import ../make-test-python.nix ({ pkgs, ... }: let homeserverDomain = "server"; homeserverUrl = "http://server:8008"; userName = "alice"; botUserName = "instagrambot"; asToken = "this-is-my-totally-randomly-generated-as-token"; hsToken = "this-is-my-totally-randomly-generated-hs-token"; in { name = "mautrix-meta-postgres"; meta.maintainers = pkgs.mautrix-meta.meta.maintainers; nodes = { server = { config, pkgs, ... }: { services.postgresql = { enable = true; ensureUsers = [ { name = "mautrix-meta-instagram"; ensureDBOwnership = true; } ]; ensureDatabases = [ "mautrix-meta-instagram" ]; }; systemd.services.mautrix-meta-instagram = { wants = [ "postgres.service" ]; after = [ "postgres.service" ]; }; services.matrix-synapse = { enable = true; settings = { database.name = "sqlite3"; enable_registration = true; # don't use this in production, always use some form of verification enable_registration_without_verification = true; listeners = [ { # The default but tls=false bind_addresses = [ "0.0.0.0" ]; port = 8008; resources = [ { "compress" = true; "names" = [ "client" ]; } { "compress" = false; "names" = [ "federation" ]; } ]; tls = false; type = "http"; } ]; }; }; services.mautrix-meta.instances.instagram = { enable = true; environmentFile = pkgs.writeText ''my-secrets'' '' AS_TOKEN=${asToken} HS_TOKEN=${hsToken} ''; settings = { homeserver = { address = homeserverUrl; domain = homeserverDomain; }; appservice = { port = 8009; as_token = "$AS_TOKEN"; hs_token = "$HS_TOKEN"; database = { type = "postgres"; uri = "postgres:///mautrix-meta-instagram?host=/var/run/postgresql"; }; bot.username = botUserName; }; bridge.permissions."@${userName}:server" = "user"; }; }; networking.firewall.allowedTCPPorts = [ 8008 8009 ]; }; client = { pkgs, ... }: { environment.systemPackages = [ (pkgs.writers.writePython3Bin "do_test" { libraries = [ pkgs.python3Packages.matrix-nio ]; flakeIgnore = [ # We don't live in the dark ages anymore. # Languages like Python that are whitespace heavy will overrun # 79 characters.. "E501" ]; } '' import sys import functools import asyncio from nio import AsyncClient, RoomMessageNotice, RoomCreateResponse, RoomInviteResponse async def message_callback(matrix: AsyncClient, msg: str, _r, e): print("Received matrix text message: ", e) assert msg in e.body exit(0) # Success! async def run(homeserver: str): matrix = AsyncClient(homeserver) response = await matrix.register("${userName}", "foobar") print("Matrix register response: ", response) # Open a DM with the bridge bot response = await matrix.room_create() print("Matrix create room response:", response) assert isinstance(response, RoomCreateResponse) room_id = response.room_id response = await matrix.room_invite(room_id, "@${botUserName}:${homeserverDomain}") assert isinstance(response, RoomInviteResponse) callback = functools.partial( message_callback, matrix, "Hello, I'm an Instagram bridge bot." ) matrix.add_event_callback(callback, RoomMessageNotice) print("Waiting for matrix message...") await matrix.sync_forever(timeout=30000) if __name__ == "__main__": asyncio.run(run(sys.argv[1])) '' ) ]; }; }; testScript = '' def extract_token(data): stdout = data[1] stdout = stdout.strip() line = stdout.split('\n')[-1] return line.split(':')[-1].strip("\" '\n") def get_token_from(token, file): data = server.execute(f"cat {file} | grep {token}") return extract_token(data) def get_as_token_from(file): return get_token_from("as_token", file) def get_hs_token_from(file): return get_token_from("hs_token", file) config_yaml = "/var/lib/mautrix-meta-instagram/config.yaml" registration_yaml = "/var/lib/mautrix-meta-instagram/meta-registration.yaml" expected_as_token = "${asToken}" expected_hs_token = "${hsToken}" start_all() with subtest("start the server"): # bridge server.wait_for_unit("mautrix-meta-instagram.service") # homeserver server.wait_for_unit("matrix-synapse.service") server.wait_for_open_port(8008) # Bridge only opens the port after it contacts the homeserver server.wait_for_open_port(8009) with subtest("ensure messages can be exchanged"): client.succeed("do_test ${homeserverUrl} >&2") with subtest("ensure as_token, hs_token match from environment file"): as_token = get_as_token_from(config_yaml) hs_token = get_hs_token_from(config_yaml) as_token_registration = get_as_token_from(registration_yaml) hs_token_registration = get_hs_token_from(registration_yaml) assert as_token == expected_as_token, f"as_token in config should match the one specified (is: {as_token}, expected: {expected_as_token})" assert hs_token == expected_hs_token, f"hs_token in config should match the one specified (is: {hs_token}, expected: {expected_hs_token})" assert as_token_registration == expected_as_token, f"as_token in registration should match the one specified (is: {as_token_registration}, expected: {expected_as_token})" assert hs_token_registration == expected_hs_token, f"hs_token in registration should match the one specified (is: {hs_token_registration}, expected: {expected_hs_token})" with subtest("ensure as_token and hs_token stays same after restart"): server.systemctl("restart mautrix-meta-instagram") server.wait_for_open_port(8009) as_token = get_as_token_from(config_yaml) hs_token = get_hs_token_from(config_yaml) as_token_registration = get_as_token_from(registration_yaml) hs_token_registration = get_hs_token_from(registration_yaml) assert as_token == expected_as_token, f"as_token in config should match the one specified (is: {as_token}, expected: {expected_as_token})" assert hs_token == expected_hs_token, f"hs_token in config should match the one specified (is: {hs_token}, expected: {expected_hs_token})" assert as_token_registration == expected_as_token, f"as_token in registration should match the one specified (is: {as_token_registration}, expected: {expected_as_token})" assert hs_token_registration == expected_hs_token, f"hs_token in registration should match the one specified (is: {hs_token_registration}, expected: {expected_hs_token})" ''; })