···
1
+
import ./make-test-python.nix (
6
+
radicale_calendars = {
8
+
url = "http://localhost:5232/";
9
+
# Radicale needs username/password.
11
+
password = "password";
14
+
radicale_contacts = {
16
+
url = "http://localhost:5232/";
17
+
# Radicale needs username/password.
19
+
password = "password";
22
+
xandikos_calendars = {
24
+
url = "http://localhost:8080/user/calendars";
26
+
# > No current-user-principal returned, re-using URL http://localhost:8080/user/calendars/
27
+
# but we do not need username/password.
30
+
xandikos_contacts = {
32
+
url = "http://localhost:8080/user/contacts";
36
+
type = "filesystem";
37
+
path = "~/calendars";
42
+
type = "filesystem";
43
+
path = "~/contacts";
49
+
a = "${a}_calendars";
50
+
b = "${b}_calendars";
57
+
a = "${a}_contacts";
58
+
b = "${b}_contacts";
68
+
pkgs.writeText "Radicale.props" (
76
+
pkgs.writeText name (lib.concatMapStrings (l: "${l}${eol}") lines);
78
+
prodid = "-//NixOS test//EN";
79
+
dtstamp = "20231129T194743Z";
88
+
writeLines "${uid}.ics" "\r\n" [
94
+
"SUMMARY:${summary}"
95
+
"DTSTART:${dtstart}"
97
+
"DTSTAMP:${dtstamp}"
102
+
foo_ics = writeICS {
104
+
summary = "Epochalypse";
105
+
dtstart = "19700101T000000Z";
106
+
dtend = "20380119T031407Z";
109
+
bar_ics = writeICS {
111
+
summary = "One Billion Seconds";
112
+
dtstart = "19700101T000000Z";
113
+
dtend = "20010909T014640Z";
123
+
writeLines "${uid}.vcf" "\r\n" [
124
+
# One of the tools enforces this order of fields.
128
+
"EMAIL;TYPE=INTERNET:${email}"
129
+
"FN:${displayName}"
134
+
foo_vcf = writeVCF {
136
+
name = "Doe;John;;;";
137
+
displayName = "John Doe";
138
+
email = "john.doe@example.org";
141
+
bar_vcf = writeVCF {
143
+
name = "Doe;Jane;;;";
144
+
displayName = "Jane Doe";
145
+
email = "jane.doe@example.org";
150
+
name = "vdirsyncer";
152
+
meta.maintainers = with lib.maintainers; [ schnusch ];
156
+
services.radicale.enable = true;
157
+
services.xandikos = {
159
+
extraOptions = [ "--autocreate" ];
162
+
services.vdirsyncer = {
170
+
statusPath = "/home/alice/.vdirsyncer";
179
+
pairs = mkPairs "local" "radicale";
181
+
forceDiscover = true;
188
+
statusPath = "/home/bob/.vdirsyncer";
197
+
pairs = mkPairs "local" "xandikos";
199
+
forceDiscover = true;
212
+
pairs = mkPairs "radicale" "xandikos";
214
+
forceDiscover = true;
220
+
# ProtectHome is the default, but we must access our storage
222
+
systemd.services = {
223
+
"vdirsyncer@alice".serviceConfig.ProtectHome = lib.mkForce false;
224
+
"vdirsyncer@bob".serviceConfig.ProtectHome = lib.mkForce false;
228
+
alice.isNormalUser = true;
229
+
bob.isNormalUser = true;
235
+
def run_unit(name):
236
+
machine.systemctl(f"start {name}")
237
+
# The service is Type=oneshot without RemainAfterExit=yes. Once it
238
+
# is finished it is no longer active and wait_for_unit will fail.
239
+
# When that happens we check if it actually failed.
241
+
machine.wait_for_unit(name)
243
+
machine.fail(f"systemctl is-failed {name}")
247
+
machine.wait_for_open_port(5232)
248
+
machine.wait_for_open_port(8080)
249
+
machine.wait_for_unit("multi-user.target")
251
+
with subtest("alice -> radicale"):
252
+
# vdirsyncer cannot create create collections on Radicale,
253
+
# see https://vdirsyncer.pimutils.org/en/stable/tutorials/radicale.html
254
+
machine.succeed("runuser -u radicale -- install -Dm 644 ${mkRadicaleProps "VCALENDAR"} /var/lib/radicale/collections/collection-root/alice/foocal/.Radicale.props")
255
+
machine.succeed("runuser -u radicale -- install -Dm 644 ${mkRadicaleProps "VADDRESSBOOK"} /var/lib/radicale/collections/collection-root/alice/foocard/.Radicale.props")
257
+
machine.succeed("runuser -u alice -- install -Dm 644 ${foo_ics} /home/alice/calendars/foocal/foo.ics")
258
+
machine.succeed("runuser -u alice -- install -Dm 644 ${foo_vcf} /home/alice/contacts/foocard/foo.vcf")
259
+
run_unit("vdirsyncer@alice.service")
262
+
machine.succeed("test -d /home/alice/.vdirsyncer")
263
+
machine.fail("test -e /var/lib/private/vdirsyncer/alice")
265
+
with subtest("bob -> xandikos"):
266
+
# I suspect Radicale shares the namespace for calendars and
267
+
# contacts, but Xandikos separates them. We just use `barcal` and
268
+
# `barcard` with Xandikos as well to avoid conflicts.
269
+
machine.succeed("runuser -u bob -- install -Dm 644 ${bar_ics} /home/bob/calendars/barcal/bar.ics")
270
+
machine.succeed("runuser -u bob -- install -Dm 644 ${bar_vcf} /home/bob/contacts/barcard/bar.vcf")
271
+
run_unit("vdirsyncer@bob.service")
274
+
machine.succeed("test -d /home/bob/.vdirsyncer")
275
+
machine.fail("test -e /var/lib/private/vdirsyncer/bob")
277
+
with subtest("radicale <-> xandikos"):
278
+
# vdirsyncer cannot create create collections on Radicale,
279
+
# see https://vdirsyncer.pimutils.org/en/stable/tutorials/radicale.html
280
+
machine.succeed("runuser -u radicale -- install -Dm 644 ${mkRadicaleProps "VCALENDAR"} /var/lib/radicale/collections/collection-root/alice/barcal/.Radicale.props")
281
+
machine.succeed("runuser -u radicale -- install -Dm 644 ${mkRadicaleProps "VADDRESSBOOK"} /var/lib/radicale/collections/collection-root/alice/barcard/.Radicale.props")
283
+
run_unit("vdirsyncer@remote.service")
286
+
machine.succeed("test -d /var/lib/private/vdirsyncer/remote")
288
+
with subtest("radicale -> alice"):
289
+
run_unit("vdirsyncer@alice.service")
291
+
with subtest("xandikos -> bob"):
292
+
run_unit("vdirsyncer@bob.service")
294
+
with subtest("compare synced files"):
295
+
# iCalendar files get reordered
296
+
machine.succeed("diff -u --strip-trailing-cr <(sort /home/alice/calendars/foocal/foo.ics) <(sort /home/bob/calendars/foocal/foo.ics) >&2")
297
+
machine.succeed("diff -u --strip-trailing-cr <(sort /home/bob/calendars/barcal/bar.ics) <(sort /home/alice/calendars/barcal/bar.ics) >&2")
299
+
machine.succeed("diff -u --strip-trailing-cr /home/alice/contacts/foocard/foo.vcf /home/bob/contacts/foocard/foo.vcf >&2")
300
+
machine.succeed("diff -u --strip-trailing-cr /home/bob/contacts/barcard/bar.vcf /home/alice/contacts/barcard/bar.vcf >&2")