at 22.05-pre 7.1 kB view raw
1import ./make-test-python.nix ({ pkgs, ... }: 2 let 3 homeserverUrl = "http://homeserver:8448"; 4 in 5 { 6 name = "matrix-appservice-irc"; 7 meta = { 8 maintainers = pkgs.matrix-appservice-irc.meta.maintainers; 9 }; 10 11 nodes = { 12 homeserver = { pkgs, ... }: { 13 # We'll switch to this once the config is copied into place 14 specialisation.running.configuration = { 15 services.matrix-synapse = { 16 enable = true; 17 database_type = "sqlite3"; 18 app_service_config_files = [ "/registration.yml" ]; 19 20 enable_registration = true; 21 22 listeners = [ 23 # The default but tls=false 24 { 25 "bind_address" = ""; 26 "port" = 8448; 27 "resources" = [ 28 { "compress" = true; "names" = [ "client" ]; } 29 { "compress" = false; "names" = [ "federation" ]; } 30 ]; 31 "tls" = false; 32 "type" = "http"; 33 "x_forwarded" = false; 34 } 35 ]; 36 }; 37 38 networking.firewall.allowedTCPPorts = [ 8448 ]; 39 }; 40 }; 41 42 ircd = { pkgs, ... }: { 43 services.ngircd = { 44 enable = true; 45 config = '' 46 [Global] 47 Name = ircd.ircd 48 Info = Server Info Text 49 AdminInfo1 = _ 50 51 [Channel] 52 Name = #test 53 Topic = a cool place 54 55 [Options] 56 PAM = no 57 ''; 58 }; 59 networking.firewall.allowedTCPPorts = [ 6667 ]; 60 }; 61 62 appservice = { pkgs, ... }: { 63 services.matrix-appservice-irc = { 64 enable = true; 65 registrationUrl = "http://appservice:8009"; 66 67 settings = { 68 homeserver.url = homeserverUrl; 69 homeserver.domain = "homeserver"; 70 71 ircService.servers."ircd" = { 72 name = "IRCd"; 73 port = 6667; 74 dynamicChannels = { 75 enabled = true; 76 aliasTemplate = "#irc_$CHANNEL"; 77 }; 78 }; 79 }; 80 }; 81 82 networking.firewall.allowedTCPPorts = [ 8009 ]; 83 }; 84 85 client = { pkgs, ... }: { 86 environment.systemPackages = [ 87 (pkgs.writers.writePython3Bin "do_test" 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 socket 99 import functools 100 from time import sleep 101 import asyncio 102 103 from nio import AsyncClient, RoomMessageText, JoinResponse 104 105 106 async def matrix_room_message_text_callback(matrix: AsyncClient, msg: str, _r, e): 107 print("Received matrix text message: ", e) 108 if msg in e.body: 109 print("Received hi from IRC") 110 await matrix.close() 111 exit(0) # Actual exit point 112 113 114 class IRC: 115 def __init__(self): 116 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 117 sock.connect(("ircd", 6667)) 118 sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) 119 sock.send(b"USER bob bob bob :bob\n") 120 sock.send(b"NICK bob\n") 121 self.sock = sock 122 123 def join(self, room: str): 124 self.sock.send(f"JOIN {room}\n".encode()) 125 126 def privmsg(self, room: str, msg: str): 127 self.sock.send(f"PRIVMSG {room} :{msg}\n".encode()) 128 129 def expect_msg(self, body: str): 130 buffer = "" 131 while True: 132 buf = self.sock.recv(1024).decode() 133 buffer += buf 134 if body in buffer: 135 return 136 137 138 async def run(homeserver: str): 139 irc = IRC() 140 141 matrix = AsyncClient(homeserver) 142 response = await matrix.register("alice", "foobar") 143 print("Matrix register response: ", response) 144 145 response = await matrix.join("#irc_#test:homeserver") 146 print("Matrix join room response:", response) 147 assert isinstance(response, JoinResponse) 148 room_id = response.room_id 149 150 irc.join("#test") 151 # FIXME: what are we waiting on here? Matrix? IRC? Both? 152 # 10s seem bad for busy hydra machines. 153 sleep(10) 154 155 # Exchange messages 156 print("Sending text message to matrix room") 157 response = await matrix.room_send( 158 room_id=room_id, 159 message_type="m.room.message", 160 content={"msgtype": "m.text", "body": "hi from matrix"}, 161 ) 162 print("Matrix room send response: ", response) 163 irc.privmsg("#test", "hi from irc") 164 165 print("Waiting for the matrix message to appear on the IRC side...") 166 irc.expect_msg("hi from matrix") 167 168 callback = functools.partial( 169 matrix_room_message_text_callback, matrix, "hi from irc" 170 ) 171 matrix.add_event_callback(callback, RoomMessageText) 172 173 print("Waiting for matrix message...") 174 await matrix.sync_forever() 175 176 exit(1) # Unreachable 177 178 179 if __name__ == "__main__": 180 asyncio.run(run(sys.argv[1])) 181 '' 182 ) 183 ]; 184 }; 185 }; 186 187 testScript = '' 188 import pathlib 189 190 start_all() 191 192 ircd.wait_for_unit("ngircd.service") 193 ircd.wait_for_open_port(6667) 194 195 with subtest("start the appservice"): 196 appservice.wait_for_unit("matrix-appservice-irc.service") 197 appservice.wait_for_open_port(8009) 198 199 with subtest("copy the registration file"): 200 appservice.copy_from_vm("/var/lib/matrix-appservice-irc/registration.yml") 201 homeserver.copy_from_host( 202 pathlib.Path(os.environ.get("out", os.getcwd())) / "registration.yml", "/" 203 ) 204 homeserver.succeed("chmod 444 /registration.yml") 205 206 with subtest("start the homeserver"): 207 homeserver.succeed( 208 "/run/current-system/specialisation/running/bin/switch-to-configuration test >&2" 209 ) 210 211 homeserver.wait_for_unit("matrix-synapse.service") 212 homeserver.wait_for_open_port(8448) 213 214 with subtest("ensure messages can be exchanged"): 215 client.succeed("do_test ${homeserverUrl} >&2") 216 ''; 217 })