at 24.11-pre 9.2 kB view raw
1{ system ? builtins.currentSystem, 2 config ? {}, 3 pkgs ? import ../.. { inherit system config; } 4}: 5 6with import ../lib/testing-python.nix { inherit system pkgs; }; 7 8let 9 user = "alice"; 10 11 client = 12 { pkgs, ... }: 13 14 { imports = [ ./common/user-account.nix ./common/x11.nix ]; 15 hardware.opengl.driSupport = true; 16 virtualisation.memorySize = 256; 17 environment = { 18 systemPackages = [ pkgs.armagetronad ]; 19 variables.XAUTHORITY = "/home/${user}/.Xauthority"; 20 }; 21 test-support.displayManager.auto.user = user; 22 }; 23 24in 25makeTest { 26 name = "armagetronad"; 27 meta = with pkgs.lib.maintainers; { 28 maintainers = [ numinit ]; 29 }; 30 31 enableOCR = true; 32 33 nodes = 34 { 35 server = { 36 services.armagetronad.servers = { 37 high-rubber = { 38 enable = true; 39 name = "Smoke Test High Rubber Server"; 40 port = 4534; 41 settings = { 42 SERVER_OPTIONS = "High Rubber server made to run smoke tests."; 43 CYCLE_RUBBER = 40; 44 SIZE_FACTOR = 0.5; 45 }; 46 roundSettings = { 47 SAY = [ 48 "NixOS Smoke Test Server" 49 "https://nixos.org" 50 ]; 51 }; 52 }; 53 sty = { 54 enable = true; 55 name = "Smoke Test sty+ct+ap Server"; 56 package = pkgs.armagetronad."0.2.9-sty+ct+ap".dedicated; 57 port = 4535; 58 settings = { 59 SERVER_OPTIONS = "sty+ct+ap server made to run smoke tests."; 60 CYCLE_RUBBER = 20; 61 SIZE_FACTOR = 0.5; 62 }; 63 roundSettings = { 64 SAY = [ 65 "NixOS Smoke Test sty+ct+ap Server" 66 "https://nixos.org" 67 ]; 68 }; 69 }; 70 trunk = { 71 enable = true; 72 name = "Smoke Test trunk Server"; 73 package = pkgs.armagetronad."0.4".dedicated; 74 port = 4536; 75 settings = { 76 SERVER_OPTIONS = "0.4 server made to run smoke tests."; 77 CYCLE_RUBBER = 20; 78 SIZE_FACTOR = 0.5; 79 }; 80 roundSettings = { 81 SAY = [ 82 "NixOS Smoke Test 0.4 Server" 83 "https://nixos.org" 84 ]; 85 }; 86 }; 87 }; 88 }; 89 90 client1 = client; 91 client2 = client; 92 }; 93 94 testScript = let 95 xdo = name: text: let 96 xdoScript = pkgs.writeText "${name}.xdo" text; 97 in "${pkgs.xdotool}/bin/xdotool ${xdoScript}"; 98 in 99 '' 100 import shlex 101 import threading 102 from collections import namedtuple 103 104 class Client(namedtuple('Client', ('node', 'name'))): 105 def send(self, *keys): 106 for key in keys: 107 self.node.send_key(key) 108 109 def send_on(self, text, *keys): 110 self.node.wait_for_text(text) 111 self.send(*keys) 112 113 Server = namedtuple('Server', ('node', 'name', 'address', 'port', 'welcome', 'attacker', 'victim', 'coredump_delay')) 114 115 # Clients and their in-game names 116 clients = ( 117 Client(client1, 'Arduino'), 118 Client(client2, 'SmOoThIcE') 119 ) 120 121 # Server configs. 122 servers = ( 123 Server(server, 'high-rubber', 'server', 4534, 'NixOS Smoke Test Server', 'SmOoThIcE', 'Arduino', 8), 124 Server(server, 'sty', 'server', 4535, 'NixOS Smoke Test sty+ct+ap Server', 'Arduino', 'SmOoThIcE', 8), 125 Server(server, 'trunk', 'server', 4536, 'NixOS Smoke Test 0.4 Server', 'Arduino', 'SmOoThIcE', 8) 126 ) 127 128 """ 129 Runs a command as the client user. 130 """ 131 def run(cmd): 132 return "su - ${user} -c " + shlex.quote(cmd) 133 134 screenshot_idx = 1 135 136 """ 137 Takes screenshots on all clients. 138 """ 139 def take_screenshots(screenshot_idx): 140 for client in clients: 141 client.node.screenshot(f"screen_{client.name}_{screenshot_idx}") 142 return screenshot_idx + 1 143 144 # Wait for the servers to come up. 145 start_all() 146 for srv in servers: 147 srv.node.wait_for_unit(f"armagetronad-{srv.name}") 148 srv.node.wait_until_succeeds(f"ss --numeric --udp --listening | grep -q {srv.port}") 149 150 # Make sure console commands work through the named pipe we created. 151 for srv in servers: 152 srv.node.succeed( 153 f"echo 'say Testing!' >> /var/lib/armagetronad/{srv.name}/input" 154 ) 155 srv.node.succeed( 156 f"echo 'say Testing again!' >> /var/lib/armagetronad/{srv.name}/input" 157 ) 158 srv.node.wait_until_succeeds( 159 f"journalctl -u armagetronad-{srv.name} -e | grep -q 'Admin: Testing!'" 160 ) 161 srv.node.wait_until_succeeds( 162 f"journalctl -u armagetronad-{srv.name} -e | grep -q 'Admin: Testing again!'" 163 ) 164 165 """ 166 Sets up a client, waiting for the given barrier on completion. 167 """ 168 def client_setup(client, servers, barrier): 169 client.node.wait_for_x() 170 171 # Configure Armagetron. 172 client.node.succeed( 173 run("mkdir -p ~/.armagetronad/var"), 174 run(f"echo 'PLAYER_1 {client.name}' >> ~/.armagetronad/var/autoexec.cfg") 175 ) 176 for idx, srv in enumerate(servers): 177 client.node.succeed( 178 run(f"echo 'BOOKMARK_{idx+1}_ADDRESS {srv.address}' >> ~/.armagetronad/var/autoexec.cfg"), 179 run(f"echo 'BOOKMARK_{idx+1}_NAME {srv.name}' >> ~/.armagetronad/var/autoexec.cfg"), 180 run(f"echo 'BOOKMARK_{idx+1}_PORT {srv.port}' >> ~/.armagetronad/var/autoexec.cfg") 181 ) 182 183 # Start Armagetron. 184 client.node.succeed(run("ulimit -c unlimited; armagetronad >&2 & disown")) 185 client.node.wait_until_succeeds( 186 run( 187 "${xdo "create_new_win-select_main_window" '' 188 search --onlyvisible --name "Armagetron Advanced" 189 windowfocus --sync 190 windowactivate --sync 191 ''}" 192 ) 193 ) 194 195 # Get through the tutorial. 196 client.send_on('Language Settings', 'ret') 197 client.send_on('First Setup', 'ret') 198 client.send_on('Welcome to Armagetron Advanced', 'ret') 199 client.send_on('round 1', 'esc') 200 client.send_on('Menu', 'up', 'up', 'ret') 201 client.send_on('We hope you', 'ret') 202 client.send_on('Armagetron Advanced', 'ret') 203 client.send_on('Play Game', 'ret') 204 205 # Online > LAN > Network Setup > Mates > Server Bookmarks 206 client.send_on('Multiplayer', 'down', 'down', 'down', 'down', 'ret') 207 208 barrier.wait() 209 210 # Get to the Server Bookmarks screen on both clients. This takes a while so do it asynchronously. 211 barrier = threading.Barrier(3, timeout=120) 212 for client in clients: 213 threading.Thread(target=client_setup, args=(client, servers, barrier)).start() 214 barrier.wait() 215 216 # Main testing loop. Iterates through each server bookmark and connects to them in sequence. 217 # Assumes that the game is currently on the Server Bookmarks screen. 218 for srv in servers: 219 screenshot_idx = take_screenshots(screenshot_idx) 220 221 # Connect both clients at once, one second apart. 222 for client in clients: 223 client.send('ret') 224 client.node.sleep(1) 225 226 # Wait for clients to connect 227 for client in clients: 228 srv.node.wait_until_succeeds( 229 f"journalctl -u armagetronad-{srv.name} -e | grep -q '{client.name}.*entered the game'" 230 ) 231 232 # Wait for the match to start 233 srv.node.wait_until_succeeds( 234 f"journalctl -u armagetronad-{srv.name} -e | grep -q 'Admin: {srv.welcome}'" 235 ) 236 srv.node.wait_until_succeeds( 237 f"journalctl -u armagetronad-{srv.name} -e | grep -q 'Admin: https://nixos.org'" 238 ) 239 srv.node.wait_until_succeeds( 240 f"journalctl -u armagetronad-{srv.name} -e | grep -q 'Go (round 1 of 10)'" 241 ) 242 243 # Wait a bit 244 srv.node.sleep(srv.coredump_delay) 245 246 # Turn the attacker player's lightcycle left 247 attacker = next(client for client in clients if client.name == srv.attacker) 248 victim = next(client for client in clients if client.name == srv.victim) 249 attacker.send('left') 250 screenshot_idx = take_screenshots(screenshot_idx) 251 252 # Wait for coredump. 253 srv.node.wait_until_succeeds( 254 f"journalctl -u armagetronad-{srv.name} -e | grep -q '{attacker.name} core dumped {victim.name}'" 255 ) 256 screenshot_idx = take_screenshots(screenshot_idx) 257 258 # Disconnect both clients from the server 259 for client in clients: 260 client.send('esc') 261 client.send_on('Menu', 'up', 'up', 'ret') 262 srv.node.wait_until_succeeds( 263 f"journalctl -u armagetronad-{srv.name} -e | grep -q '{client.name}.*left the game'" 264 ) 265 266 # Next server. 267 for client in clients: 268 client.send_on('Server Bookmarks', 'down') 269 270 # Stop the servers 271 for srv in servers: 272 srv.node.succeed( 273 f"systemctl stop armagetronad-{srv.name}" 274 ) 275 srv.node.wait_until_fails(f"ss --numeric --udp --listening | grep -q {srv.port}") 276 ''; 277 278}