1import ./make-test-python.nix ({ pkgs, lib, ... }:
2let
3 uiPort = 1234;
4 backendPort = 5678;
5 lemmyNodeName = "server";
6in
7{
8 name = "lemmy";
9 meta = with lib.maintainers; { maintainers = [ mightyiam ]; };
10
11 nodes = {
12 client = { };
13
14 "${lemmyNodeName}" = {
15 services.lemmy = {
16 enable = true;
17 ui.port = uiPort;
18 database.createLocally = true;
19 settings = {
20 hostname = "http://${lemmyNodeName}";
21 port = backendPort;
22 # Without setup, the /feeds/* and /nodeinfo/* API endpoints won't return 200
23 setup = {
24 admin_username = "mightyiam";
25 admin_password = "ThisIsWhatIUseEverywhereTryIt";
26 site_name = "Lemmy FTW";
27 admin_email = "mightyiam@example.com";
28 };
29 };
30 caddy.enable = true;
31 };
32
33 networking.firewall.allowedTCPPorts = [ 80 ];
34
35 # pict-rs seems to need more than 1025114112 bytes
36 virtualisation.memorySize = 2000;
37 };
38 };
39
40 testScript = ''
41 server = ${lemmyNodeName}
42
43 with subtest("the backend starts and responds"):
44 server.wait_for_unit("lemmy.service")
45 server.wait_for_open_port(${toString backendPort})
46 server.succeed("curl --fail localhost:${toString backendPort}/api/v3/site")
47
48 with subtest("the UI starts and responds"):
49 server.wait_for_unit("lemmy-ui.service")
50 server.wait_for_open_port(${toString uiPort})
51 server.succeed("curl --fail localhost:${toString uiPort}")
52
53 with subtest("Lemmy-UI responds through the caddy reverse proxy"):
54 server.wait_for_unit("network-online.target")
55 server.wait_for_unit("caddy.service")
56 server.wait_for_open_port(80)
57 body = server.execute("curl --fail --location ${lemmyNodeName}")[1]
58 assert "Lemmy" in body, f"String Lemmy not found in response for ${lemmyNodeName}: \n{body}"
59
60 with subtest("the server is exposed externally"):
61 client.wait_for_unit("network-online.target")
62 client.succeed("curl -v --fail ${lemmyNodeName}")
63
64 with subtest("caddy correctly routes backend requests"):
65 # Make sure we are not hitting frontend
66 server.execute("systemctl stop lemmy-ui.service")
67
68 def assert_http_code(url, expected_http_code, extra_curl_args=""):
69 _, http_code = server.execute(f'curl --silent -o /dev/null {extra_curl_args} --fail --write-out "%{{http_code}}" {url}')
70 assert http_code == str(expected_http_code), f"expected http code {expected_http_code}, got {http_code}"
71
72 # Caddy responds with HTTP code 502 if it cannot handle the requested path
73 assert_http_code("${lemmyNodeName}/obviously-wrong-path/", 502)
74
75 assert_http_code("${lemmyNodeName}/static/js/client.js", 200)
76 assert_http_code("${lemmyNodeName}/api/v3/site", 200)
77
78 # A 404 confirms that the request goes to the backend
79 # No path can return 200 until after we upload an image to pict-rs
80 assert_http_code("${lemmyNodeName}/pictrs/", 404)
81
82 assert_http_code("${lemmyNodeName}/feeds/all.xml", 200)
83 assert_http_code("${lemmyNodeName}/nodeinfo/2.0.json", 200)
84
85 assert_http_code("${lemmyNodeName}/some-other-made-up-path/", 404, "-X POST")
86 assert_http_code("${lemmyNodeName}/some-other-path", 404, "-H 'Accept: application/activity+json'")
87 assert_http_code("${lemmyNodeName}/some-other-path", 404, "-H 'Accept: application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"'")
88 '';
89})