python312Packages.yoda: 2.0.1 -> 2.0.2
[NixPkgs.git] / nixos / tests / matrix / mautrix-meta-sqlite.nix
blobb5e580620049a14f2c9f20d6d92bfcab37a7ba8a
1 import ../make-test-python.nix ({ pkgs, ... }:
2   let
3     homeserverDomain = "server";
4     homeserverUrl = "http://server:8008";
5     username = "alice";
6     instagramBotUsername = "instagrambot";
7     facebookBotUsername = "facebookbot";
8   in
9   {
10     name = "mautrix-meta-sqlite";
11     meta.maintainers = pkgs.mautrix-meta.meta.maintainers;
13     nodes = {
14       server = { config, pkgs, ... }: {
15         services.matrix-synapse = {
16           enable = true;
17           settings = {
18             database.name = "sqlite3";
20             enable_registration = true;
22             # don't use this in production, always use some form of verification
23             enable_registration_without_verification = true;
25             listeners = [ {
26               # The default but tls=false
27               bind_addresses = [
28                 "0.0.0.0"
29               ];
30               port = 8008;
31               resources = [ {
32                 "compress" = true;
33                 "names" = [ "client" ];
34               } {
35                 "compress" = false;
36                 "names" = [ "federation" ];
37               } ];
38               tls = false;
39               type = "http";
40             } ];
41           };
42         };
44         services.mautrix-meta.instances.facebook = {
45           enable = true;
47           settings = {
48             homeserver = {
49               address = homeserverUrl;
50               domain = homeserverDomain;
51             };
53             appservice = {
54               port = 8009;
56               bot.username = facebookBotUsername;
57             };
59             bridge.permissions."@${username}:server" = "user";
60           };
61         };
63         services.mautrix-meta.instances.instagram = {
64           enable = true;
66           settings = {
67             homeserver = {
68               address = homeserverUrl;
69               domain = homeserverDomain;
70             };
72             appservice = {
73               port = 8010;
75               bot.username = instagramBotUsername;
76             };
78             bridge.permissions."@${username}:server" = "user";
79           };
80         };
82         networking.firewall.allowedTCPPorts = [ 8008 ];
83       };
85       client = { pkgs, ... }: {
86         environment.systemPackages = [
87           (pkgs.writers.writePython3Bin "register_user"
88           {
89             libraries = [ pkgs.python3Packages.matrix-nio ];
90             flakeIgnore = [
91               # We don't live in the dark ages anymore.
92               # Languages like Python that are whitespace heavy will overrun
93               # 79 characters..
94               "E501"
95             ];
96           } ''
97               import sys
98               import asyncio
100               from nio import AsyncClient
103               async def run(username: str, homeserver: str):
104                   matrix = AsyncClient(homeserver)
106                   response = await matrix.register(username, "foobar")
107                   print("Matrix register response: ", response)
110               if __name__ == "__main__":
111                   asyncio.run(run(sys.argv[1], sys.argv[2]))
112             ''
113           )
114           (pkgs.writers.writePython3Bin "do_test"
115           {
116             libraries = [ pkgs.python3Packages.matrix-nio ];
117             flakeIgnore = [
118               # We don't live in the dark ages anymore.
119               # Languages like Python that are whitespace heavy will overrun
120               # 79 characters..
121               "E501"
122             ];
123           } ''
124               import sys
125               import functools
126               import asyncio
128               from nio import AsyncClient, RoomMessageNotice, RoomCreateResponse, RoomInviteResponse
131               async def message_callback(matrix: AsyncClient, msg: str, _r, e):
132                   print("Received matrix text message: ", e)
133                   assert msg in e.body
134                   exit(0)  # Success!
137               async def run(username: str, bot_username: str, homeserver: str):
138                   matrix = AsyncClient(homeserver, f"@{username}:${homeserverDomain}")
140                   response = await matrix.login("foobar")
141                   print("Matrix login response: ", response)
143                   # Open a DM with the bridge bot
144                   response = await matrix.room_create()
145                   print("Matrix create room response:", response)
146                   assert isinstance(response, RoomCreateResponse)
147                   room_id = response.room_id
149                   response = await matrix.room_invite(room_id, f"@{bot_username}:${homeserverDomain}")
150                   assert isinstance(response, RoomInviteResponse)
152                   callback = functools.partial(
153                       message_callback, matrix, "Hello, I'm an Instagram bridge bot."
154                   )
155                   matrix.add_event_callback(callback, RoomMessageNotice)
157                   print("Waiting for matrix message...")
158                   await matrix.sync_forever(timeout=30000)
161               if __name__ == "__main__":
162                   asyncio.run(run(sys.argv[1], sys.argv[2], sys.argv[3]))
163             ''
164           )
165         ];
166       };
167     };
169     testScript = ''
170       def extract_token(data):
171           stdout = data[1]
172           stdout = stdout.strip()
173           line = stdout.split('\n')[-1]
174           return line.split(':')[-1].strip("\" '\n")
176       def get_token_from(token, file):
177           data = server.execute(f"cat {file} | grep {token}")
178           return extract_token(data)
180       def get_as_token_from(file):
181           return get_token_from("as_token", file)
183       def get_hs_token_from(file):
184           return get_token_from("hs_token", file)
186       config_yaml = "/var/lib/mautrix-meta-facebook/config.yaml"
187       registration_yaml = "/var/lib/mautrix-meta-facebook/meta-registration.yaml"
189       start_all()
191       with subtest("wait for bridges and homeserver"):
192           # bridge
193           server.wait_for_unit("mautrix-meta-facebook.service")
194           server.wait_for_unit("mautrix-meta-instagram.service")
196           # homeserver
197           server.wait_for_unit("matrix-synapse.service")
199           server.wait_for_open_port(8008)
200           # Bridges only open the port after they contact the homeserver
201           server.wait_for_open_port(8009)
202           server.wait_for_open_port(8010)
204       with subtest("register user"):
205           client.succeed("register_user ${username} ${homeserverUrl} >&2")
207       with subtest("ensure messages can be exchanged"):
208           client.succeed("do_test ${username} ${facebookBotUsername} ${homeserverUrl} >&2")
209           client.succeed("do_test ${username} ${instagramBotUsername} ${homeserverUrl} >&2")
211       with subtest("ensure as_token and hs_token stays same after restart"):
212           generated_as_token_facebook = get_as_token_from(config_yaml)
213           generated_hs_token_facebook = get_hs_token_from(config_yaml)
215           generated_as_token_facebook_registration = get_as_token_from(registration_yaml)
216           generated_hs_token_facebook_registration = get_hs_token_from(registration_yaml)
218           # Indirectly checks the as token is not set to something like empty string or "null"
219           assert len(generated_as_token_facebook) > 20, f"as_token ({generated_as_token_facebook}) is too short, something went wrong"
220           assert len(generated_hs_token_facebook) > 20, f"hs_token ({generated_hs_token_facebook}) is too short, something went wrong"
222           assert generated_as_token_facebook == generated_as_token_facebook_registration, f"as_token should be the same in registration ({generated_as_token_facebook_registration}) and configuration ({generated_as_token_facebook}) files"
223           assert generated_hs_token_facebook == generated_hs_token_facebook_registration, f"hs_token should be the same in registration ({generated_hs_token_facebook_registration}) and configuration ({generated_hs_token_facebook}) files"
225           server.systemctl("restart mautrix-meta-facebook")
226           server.systemctl("restart mautrix-meta-instagram")
228           server.wait_for_open_port(8009)
229           server.wait_for_open_port(8010)
231           new_as_token_facebook = get_as_token_from(config_yaml)
232           new_hs_token_facebook = get_hs_token_from(config_yaml)
234           assert generated_as_token_facebook == new_as_token_facebook, f"as_token should stay the same after restart inside the configuration file (is: {new_as_token_facebook}, was: {generated_as_token_facebook})"
235           assert generated_hs_token_facebook == new_hs_token_facebook, f"hs_token should stay the same after restart inside the configuration file (is: {new_hs_token_facebook}, was: {generated_hs_token_facebook})"
237           new_as_token_facebook = get_as_token_from(registration_yaml)
238           new_hs_token_facebook = get_hs_token_from(registration_yaml)
240           assert generated_as_token_facebook == new_as_token_facebook, f"as_token should stay the same after restart inside the registration file (is: {new_as_token_facebook}, was: {generated_as_token_facebook})"
241           assert generated_hs_token_facebook == new_hs_token_facebook, f"hs_token should stay the same after restart inside the registration file (is: {new_hs_token_facebook}, was: {generated_hs_token_facebook})"
243       with subtest("ensure messages can be exchanged after restart"):
244           client.succeed("do_test ${username} ${instagramBotUsername} ${homeserverUrl} >&2")
245           client.succeed("do_test ${username} ${facebookBotUsername} ${homeserverUrl} >&2")
246     '';
247   })