···
+
import ./make-test-python.nix (
+
url = "http://localhost:5232/";
+
# Radicale needs username/password.
+
url = "http://localhost:5232/";
+
# Radicale needs username/password.
+
url = "http://localhost:8080/user/calendars";
+
# > No current-user-principal returned, re-using URL http://localhost:8080/user/calendars/
+
# but we do not need username/password.
+
url = "http://localhost:8080/user/contacts";
+
pkgs.writeText "Radicale.props" (
+
pkgs.writeText name (lib.concatMapStrings (l: "${l}${eol}") lines);
+
prodid = "-//NixOS test//EN";
+
dtstamp = "20231129T194743Z";
+
writeLines "${uid}.ics" "\r\n" [
+
summary = "Epochalypse";
+
dtstart = "19700101T000000Z";
+
dtend = "20380119T031407Z";
+
summary = "One Billion Seconds";
+
dtstart = "19700101T000000Z";
+
dtend = "20010909T014640Z";
+
writeLines "${uid}.vcf" "\r\n" [
+
# One of the tools enforces this order of fields.
+
"EMAIL;TYPE=INTERNET:${email}"
+
displayName = "John Doe";
+
email = "john.doe@example.org";
+
displayName = "Jane Doe";
+
email = "jane.doe@example.org";
+
meta.maintainers = with lib.maintainers; [ schnusch ];
+
services.radicale.enable = true;
+
extraOptions = [ "--autocreate" ];
+
services.vdirsyncer = {
+
statusPath = "/home/alice/.vdirsyncer";
+
pairs = mkPairs "local" "radicale";
+
statusPath = "/home/bob/.vdirsyncer";
+
pairs = mkPairs "local" "xandikos";
+
pairs = mkPairs "radicale" "xandikos";
+
# ProtectHome is the default, but we must access our storage
+
"vdirsyncer@alice".serviceConfig.ProtectHome = lib.mkForce false;
+
"vdirsyncer@bob".serviceConfig.ProtectHome = lib.mkForce false;
+
alice.isNormalUser = true;
+
bob.isNormalUser = true;
+
machine.systemctl(f"start {name}")
+
# The service is Type=oneshot without RemainAfterExit=yes. Once it
+
# is finished it is no longer active and wait_for_unit will fail.
+
# When that happens we check if it actually failed.
+
machine.wait_for_unit(name)
+
machine.fail(f"systemctl is-failed {name}")
+
machine.wait_for_open_port(5232)
+
machine.wait_for_open_port(8080)
+
machine.wait_for_unit("multi-user.target")
+
with subtest("alice -> radicale"):
+
# vdirsyncer cannot create create collections on Radicale,
+
# see https://vdirsyncer.pimutils.org/en/stable/tutorials/radicale.html
+
machine.succeed("runuser -u radicale -- install -Dm 644 ${mkRadicaleProps "VCALENDAR"} /var/lib/radicale/collections/collection-root/alice/foocal/.Radicale.props")
+
machine.succeed("runuser -u radicale -- install -Dm 644 ${mkRadicaleProps "VADDRESSBOOK"} /var/lib/radicale/collections/collection-root/alice/foocard/.Radicale.props")
+
machine.succeed("runuser -u alice -- install -Dm 644 ${foo_ics} /home/alice/calendars/foocal/foo.ics")
+
machine.succeed("runuser -u alice -- install -Dm 644 ${foo_vcf} /home/alice/contacts/foocard/foo.vcf")
+
run_unit("vdirsyncer@alice.service")
+
machine.succeed("test -d /home/alice/.vdirsyncer")
+
machine.fail("test -e /var/lib/private/vdirsyncer/alice")
+
with subtest("bob -> xandikos"):
+
# I suspect Radicale shares the namespace for calendars and
+
# contacts, but Xandikos separates them. We just use `barcal` and
+
# `barcard` with Xandikos as well to avoid conflicts.
+
machine.succeed("runuser -u bob -- install -Dm 644 ${bar_ics} /home/bob/calendars/barcal/bar.ics")
+
machine.succeed("runuser -u bob -- install -Dm 644 ${bar_vcf} /home/bob/contacts/barcard/bar.vcf")
+
run_unit("vdirsyncer@bob.service")
+
machine.succeed("test -d /home/bob/.vdirsyncer")
+
machine.fail("test -e /var/lib/private/vdirsyncer/bob")
+
with subtest("radicale <-> xandikos"):
+
# vdirsyncer cannot create create collections on Radicale,
+
# see https://vdirsyncer.pimutils.org/en/stable/tutorials/radicale.html
+
machine.succeed("runuser -u radicale -- install -Dm 644 ${mkRadicaleProps "VCALENDAR"} /var/lib/radicale/collections/collection-root/alice/barcal/.Radicale.props")
+
machine.succeed("runuser -u radicale -- install -Dm 644 ${mkRadicaleProps "VADDRESSBOOK"} /var/lib/radicale/collections/collection-root/alice/barcard/.Radicale.props")
+
run_unit("vdirsyncer@remote.service")
+
machine.succeed("test -d /var/lib/private/vdirsyncer/remote")
+
with subtest("radicale -> alice"):
+
run_unit("vdirsyncer@alice.service")
+
with subtest("xandikos -> bob"):
+
run_unit("vdirsyncer@bob.service")
+
with subtest("compare synced files"):
+
# iCalendar files get reordered
+
machine.succeed("diff -u --strip-trailing-cr <(sort /home/alice/calendars/foocal/foo.ics) <(sort /home/bob/calendars/foocal/foo.ics) >&2")
+
machine.succeed("diff -u --strip-trailing-cr <(sort /home/bob/calendars/barcal/bar.ics) <(sort /home/alice/calendars/barcal/bar.ics) >&2")
+
machine.succeed("diff -u --strip-trailing-cr /home/alice/contacts/foocard/foo.vcf /home/bob/contacts/foocard/foo.vcf >&2")
+
machine.succeed("diff -u --strip-trailing-cr /home/bob/contacts/barcard/bar.vcf /home/alice/contacts/barcard/bar.vcf >&2")