1 import ../make-test-python.nix ({ pkgs, ... }:
3 homeserverDomain = "server";
4 homeserverUrl = "http://server:8008";
6 instagramBotUsername = "instagrambot";
7 facebookBotUsername = "facebookbot";
10 name = "mautrix-meta-sqlite";
11 meta.maintainers = pkgs.mautrix-meta.meta.maintainers;
14 server = { config, pkgs, ... }: {
15 services.matrix-synapse = {
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;
26 # The default but tls=false
33 "names" = [ "client" ];
36 "names" = [ "federation" ];
44 services.mautrix-meta.instances.facebook = {
49 address = homeserverUrl;
50 domain = homeserverDomain;
56 bot.username = facebookBotUsername;
59 bridge.permissions."@${username}:server" = "user";
63 services.mautrix-meta.instances.instagram = {
68 address = homeserverUrl;
69 domain = homeserverDomain;
75 bot.username = instagramBotUsername;
78 bridge.permissions."@${username}:server" = "user";
82 networking.firewall.allowedTCPPorts = [ 8008 ];
85 client = { pkgs, ... }: {
86 environment.systemPackages = [
87 (pkgs.writers.writePython3Bin "register_user"
89 libraries = [ pkgs.python3Packages.matrix-nio ];
91 # We don't live in the dark ages anymore.
92 # Languages like Python that are whitespace heavy will overrun
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]))
114 (pkgs.writers.writePython3Bin "do_test"
116 libraries = [ pkgs.python3Packages.matrix-nio ];
118 # We don't live in the dark ages anymore.
119 # Languages like Python that are whitespace heavy will overrun
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)
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."
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]))
170 def extract_token(data):
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"
191 with subtest("wait for bridges and homeserver"):
193 server.wait_for_unit("mautrix-meta-facebook.service")
194 server.wait_for_unit("mautrix-meta-instagram.service")
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")