1{ pkgs, ... }:
2
3{
4 name = "mealie";
5 meta = with pkgs.lib.maintainers; {
6 maintainers = [
7 litchipi
8 anoa
9 ];
10 };
11
12 nodes =
13 let
14 sqlite = {
15 services.mealie = {
16 enable = true;
17 port = 9001;
18 settings.ALLOW_SIGNUP = "true";
19 };
20 };
21 postgres = {
22 imports = [ sqlite ];
23 services.mealie.database.createLocally = true;
24 };
25 in
26 {
27 inherit sqlite postgres;
28 };
29
30 testScript = ''
31 import json
32 import urllib.parse
33
34 def api_get(node, path, qry={}, **headers):
35 url = f"http://localhost:9001/api{path}"
36 if len(qry) > 0:
37 url += "?" + "&".join([f"{k}={urllib.parse.quote(v)}" for k, v in qry.items()])
38
39 headers = " ".join([f"-H '{k}: {str(v)}'" for k, v in headers.items()])
40
41 got = node.succeed(f"curl -s -X GET {headers} --fail {url}")
42 print(f"* GET {path}\n{got}")
43 return json.loads(got)
44
45 def api_post(node, path, method="POST", urlencode=False, body={}, qry={}, **headers):
46 url = f"http://localhost:9001/api{path}"
47 if len(qry) > 0:
48 url += "?" + "&".join([f"{k}={urllib.parse.quote(v)}" for k, v in qry.items()])
49
50 if urlencode:
51 headers["Content-Type"] = "application/x-www-form-urlencoded"
52 print("BODY", body)
53 body = "&".join([f"{k}={urllib.parse.quote(str(v))}" for k, v in body.items()])
54 else:
55 headers["Content-Type"] = "application/json"
56 body = json.dumps(body)
57
58 headers["Accept"] = "application/json"
59 headers = " ".join([f"-H '{k}: {str(v)}'" for k, v in headers.items()])
60
61 got = node.succeed(f"curl -v --fail -X {method} {url} {headers} -d '{body}'")
62 print(f"* POST {path}\n{got}")
63 return json.loads(got)
64
65 def test_mealie(node):
66 node.wait_for_unit("mealie.service")
67 node.wait_for_open_port(9001)
68 node.succeed("curl --fail http://localhost:9001")
69
70 got = api_get(node, "/app/about")
71 assert got["version"] == "v${pkgs.mealie.version}"
72
73 new_user = dict(
74 email=node.name + ".nomail@no.mail",
75 username="noname-" + node.name,
76 fullName="No Name" + node.name,
77 password="SuperSecure" + node.name,
78 passwordConfirm="SuperSecure" + node.name,
79 group="mygroup" + node.name,
80 )
81 got = api_post(node, "/users/register", body=new_user)
82 got = api_post(node, "/auth/token", urlencode=True, body={
83 "username": new_user["username"],
84 "password": new_user["password"],
85 "remember_me": False,
86 })
87 assert "access_token" in got
88 token = "Bearer " + got["access_token"]
89
90 got = api_get(node, "/recipes", authorization=token)
91 assert got["total"] == 0
92
93 slug = api_post(node, "/recipes", body={"name": "TestRecipe"}, authorization=token)
94 recipe = { "description": "Test recipe" }
95 got = api_post(node, f"/recipes/{slug}", body=recipe, method="PATCH", authorization=token)
96 got = api_get(node, "/recipes", authorization=token)
97 assert got["total"] > 0
98 assert got["items"][0]["description"] == recipe["description"]
99
100 postgres.start()
101 test_mealie(postgres)
102 postgres.send_monitor_command("quit")
103 postgres.wait_for_shutdown()
104
105 sqlite.start()
106 test_mealie(sqlite)
107 sqlite.send_monitor_command("quit")
108 sqlite.wait_for_shutdown()
109 '';
110}