notes: 2.3.0 -> 2.3.1 (#352950)
[NixPkgs.git] / nixos / tests / matrix / appservice-irc.nix
blob41a6b005064fdb18b0d636572f41107e8bf83cd7
1 { pkgs, ... }:
2   let
3     homeserverUrl = "http://homeserver:8008";
4   in
5   {
6     name = "matrix-appservice-irc";
7     meta = {
8       maintainers = pkgs.matrix-appservice-irc.meta.maintainers;
9     };
11     nodes = {
12       homeserver = {
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             settings = {
18               database.name = "sqlite3";
19               app_service_config_files = [ "/registration.yml" ];
21               enable_registration = true;
23               # don't use this in production, always use some form of verification
24               enable_registration_without_verification = true;
26               listeners = [ {
27                 # The default but tls=false
28                 bind_addresses = [
29                   "0.0.0.0"
30                 ];
31                 port = 8008;
32                 resources = [ {
33                   "compress" = true;
34                   "names" = [ "client" ];
35                 } {
36                   "compress" = false;
37                   "names" = [ "federation" ];
38                 } ];
39                 tls = false;
40                 type = "http";
41               } ];
42             };
43           };
45           networking.firewall.allowedTCPPorts = [ 8008 ];
46         };
47       };
49       ircd = {
50         services.ngircd = {
51           enable = true;
52           config = ''
53             [Global]
54               Name = ircd.ircd
55               Info = Server Info Text
56               AdminInfo1 = _
58             [Channel]
59               Name = #test
60               Topic = a cool place
62             [Options]
63               PAM = no
64           '';
65         };
66         networking.firewall.allowedTCPPorts = [ 6667 ];
67       };
69       appservice = { pkgs, ... }: {
70         services.matrix-appservice-irc = {
71           enable = true;
72           registrationUrl = "http://appservice:8009";
74           settings = {
75             homeserver.url = homeserverUrl;
76             homeserver.domain = "homeserver";
78             ircService = {
79               servers."ircd" = {
80                 name = "IRCd";
81                 port = 6667;
82                 dynamicChannels = {
83                   enabled = true;
84                   aliasTemplate = "#irc_$CHANNEL";
85                 };
86               };
87               mediaProxy = {
88                 publicUrl = "http://localhost:11111/media";
89                 ttl = 0;
90               };
91             };
92           };
93         };
95         networking.firewall.allowedTCPPorts = [ 8009 ];
96       };
98       client = { pkgs, ... }: {
99         environment.systemPackages = [
100           (pkgs.writers.writePython3Bin "do_test"
101           {
102             libraries = [ pkgs.python3Packages.matrix-nio ];
103             flakeIgnore = [
104               # We don't live in the dark ages anymore.
105               # Languages like Python that are whitespace heavy will overrun
106               # 79 characters..
107               "E501"
108             ];
109           } ''
110               import sys
111               import socket
112               import functools
113               from time import sleep
114               import asyncio
116               from nio import AsyncClient, RoomMessageText, JoinResponse
119               async def matrix_room_message_text_callback(matrix: AsyncClient, msg: str, _r, e):
120                   print("Received matrix text message: ", e)
121                   if msg in e.body:
122                       print("Received hi from IRC")
123                       await matrix.close()
124                       exit(0)  # Actual exit point
127               class IRC:
128                   def __init__(self):
129                       sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
130                       sock.connect(("ircd", 6667))
131                       sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
132                       sock.send(b"USER bob bob bob :bob\n")
133                       sock.send(b"NICK bob\n")
134                       self.sock = sock
136                   def join(self, room: str):
137                       self.sock.send(f"JOIN {room}\n".encode())
139                   def privmsg(self, room: str, msg: str):
140                       self.sock.send(f"PRIVMSG {room} :{msg}\n".encode())
142                   def expect_msg(self, body: str):
143                       buffer = ""
144                       while True:
145                           buf = self.sock.recv(1024).decode()
146                           buffer += buf
147                           if body in buffer:
148                               return
151               async def run(homeserver: str):
152                   irc = IRC()
154                   matrix = AsyncClient(homeserver)
155                   response = await matrix.register("alice", "foobar")
156                   print("Matrix register response: ", response)
158                   response = await matrix.join("#irc_#test:homeserver")
159                   print("Matrix join room response:", response)
160                   assert isinstance(response, JoinResponse)
161                   room_id = response.room_id
163                   irc.join("#test")
164                   # FIXME: what are we waiting on here? Matrix? IRC? Both?
165                   # 10s seem bad for busy hydra machines.
166                   sleep(10)
168                   # Exchange messages
169                   print("Sending text message to matrix room")
170                   response = await matrix.room_send(
171                       room_id=room_id,
172                       message_type="m.room.message",
173                       content={"msgtype": "m.text", "body": "hi from matrix"},
174                   )
175                   print("Matrix room send response: ", response)
176                   irc.privmsg("#test", "hi from irc")
178                   print("Waiting for the matrix message to appear on the IRC side...")
179                   irc.expect_msg("hi from matrix")
181                   callback = functools.partial(
182                       matrix_room_message_text_callback, matrix, "hi from irc"
183                   )
184                   matrix.add_event_callback(callback, RoomMessageText)
186                   print("Waiting for matrix message...")
187                   await matrix.sync_forever()
189                   exit(1)  # Unreachable
192               if __name__ == "__main__":
193                   asyncio.run(run(sys.argv[1]))
194             ''
195           )
196         ];
197       };
198     };
200     testScript = ''
201       import pathlib
202       import os
204       start_all()
206       ircd.wait_for_unit("ngircd.service")
207       ircd.wait_for_open_port(6667)
209       with subtest("start the appservice"):
210           appservice.wait_for_unit("matrix-appservice-irc.service")
211           appservice.wait_for_open_port(8009)
212           appservice.wait_for_file("/var/lib/matrix-appservice-irc/media-signingkey.jwk")
213           appservice.wait_for_open_port(11111)
215       with subtest("copy the registration file"):
216           appservice.copy_from_vm("/var/lib/matrix-appservice-irc/registration.yml")
217           homeserver.copy_from_host(
218               str(pathlib.Path(os.environ.get("out", os.getcwd())) / "registration.yml"), "/"
219           )
220           homeserver.succeed("chmod 444 /registration.yml")
222       with subtest("start the homeserver"):
223           homeserver.succeed(
224               "/run/current-system/specialisation/running/bin/switch-to-configuration test >&2"
225           )
227           homeserver.wait_for_unit("matrix-synapse.service")
228           homeserver.wait_for_open_port(8008)
230       with subtest("ensure messages can be exchanged"):
231           client.succeed("do_test ${homeserverUrl} >&2")
232     '';
233   }