From c8730adf1a46035def741ca3eef52b6a5181b54d Mon Sep 17 00:00:00 2001 From: eljamm Date: Wed, 10 Dec 2025 10:13:06 +0100 Subject: [PATCH] nixos/tests: init Kaidan --- nixos/tests/all-tests.nix | 1 + nixos/tests/kaidan/default.nix | 158 +++++++++++++++++++++++++++++ nixos/tests/kaidan/prosody.nix | 59 +++++++++++ pkgs/by-name/ka/kaidan/package.nix | 2 + 4 files changed, 220 insertions(+) create mode 100644 nixos/tests/kaidan/default.nix create mode 100644 nixos/tests/kaidan/prosody.nix diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index dea336cb1173..dd1ff5878281 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -802,6 +802,7 @@ in jotta-cli = runTest ./jotta-cli.nix; k3s = handleTest ./k3s { }; kafka = handleTest ./kafka { }; + kaidan = runTest ./kaidan; kanboard = runTest ./web-apps/kanboard.nix; kanidm = runTest ./kanidm.nix; kanidm-provisioning = runTest ./kanidm-provisioning.nix; diff --git a/nixos/tests/kaidan/default.nix b/nixos/tests/kaidan/default.nix new file mode 100644 index 000000000000..9ac97dd05266 --- /dev/null +++ b/nixos/tests/kaidan/default.nix @@ -0,0 +1,158 @@ +{ + lib, + ... +}: +{ + name = "Kaidan XMPP Chat App"; + + nodes = { + machine = + { + pkgs, + ... + }: + { + imports = [ + # enable graphical session + users (alice, bob) + ../common/x11.nix + ../common/user-account.nix + + # XMPP server for Kaidan + ./prosody.nix + ]; + + test-support.displayManager.auto.user = "alice"; + + environment.systemPackages = with pkgs; [ + kaidan + xdotool # automated mouse clicks + ]; + + # Kaidan requires a keyring for storing user passwords + services.gnome.gnome-keyring.enable = true; + }; + }; + + enableOCR = true; + interactive.sshBackdoor.enable = true; # ssh -o User=root vsock/3 + + testScript = + { nodes, ... }: + let + users.john = { + email = "john@example.com"; + password = "foobar"; + message = "Hello, I'm John!"; + }; + + users.alice = { + email = "alice@example.com"; + password = "foobar"; + message = "Hello, I'm Alice!"; + }; + in + # py + '' + import json + + users = json.loads("""${lib.strings.toJSON users}""") + + def wait_main_screen(): + machine.wait_for_text(r"(Kaidan|free|communication|every|device)") + + def click_position(x: int, y: int): + machine.succeed(f"su - alice -c 'DISPLAY=:0 xdotool mousemove --sync {x} {y} click 1'") + machine.sleep(1) + + def login_user(user: str): + machine.send_chars(f"{users[user]["email"]}\n", 0.1) + machine.sleep(1) + machine.send_chars(f"{users[user]["password"]}\n", 0.1) + + # add user account + def add_user_account(user: str): + click_position(26, 48) # burger menu + click_position(179, 144) # add account + + wait_main_screen() + click_position(366, 598) # chat address + login_user(user) + machine.sleep(1) + + # add user to the contact list + # NOTE: currently, we're hardcoding this to add to john's contact list, + # since it's simpler than somehow reading the screen, determining where + # each user is positioned and choosing them. + def add_contact(user, message=""): + click_position(26, 48) # burger menu + machine.wait_for_text(r"(Add|contact|chat|QR|code|address)") + click_position(225, 344) # Add contact by chat address + click_position(404, 359) # Add contact to john + + machine.send_chars(f"{users[user]["email"]}\n",0.1); + machine.sleep(1) + machine.send_key("tab") + machine.send_key("tab") + machine.sleep(1) + machine.send_chars(f"{message if message != "" else users[user]["message"]}\n",0.1); + machine.sleep(1) + + click_position(511, 524) # Add + + # send a message + def send_message(message): + click_position(602, 742) # message box + machine.send_chars(f"{message}\n", 0.2) + machine.sleep(1) + + ## START ## + start_all() + machine.wait_for_x() + + # Setup prosody so we can connect + machine.wait_for_unit("prosody.service") + machine.succeed("create-prosody-users") + machine.systemctl("start network-online.target") + machine.wait_for_unit("network-online.target") + + # Start Kaidan and scale it to full screen + machine.execute("env DISPLAY=:0 sudo -u alice kaidan >&2 &") + wait_main_screen() + machine.send_key("alt-f10") + machine.sleep(1) + + with subtest("Set up users"): + login_user("john") + + # set up keyring for storing user passwords + machine.wait_for_text(r"(Choose|keyring|Default|Confirm|Continue)") + machine.send_chars("foobar", 0.1) + machine.send_key("tab") + machine.send_chars("foobar\n", 0.1) + machine.wait_for_text(r"(Search|Select|chat|start)") + + # we add a second account, which will be communicating with the first one + add_user_account("alice") + machine.wait_for_text(r"(Search|Select|chat|start)") + + # NOTE: OCR doesn't work well here. We assume both messages are received + # and just take a screenshot. + # TODO: verify messages exist in the screenshot. + with subtest("Chat between 2 users"): + # add alice to john's contacts with an initial message + add_contact("alice", users["john"]["message"]) + machine.sleep(5) + + # john sends alice a message + click_position(151, 110) # alice in john's contacts + send_message(users["john"]["message"]) + + # alice receives john's message and replies + click_position(151, 183) # john in alice's contacts + send_message(users["alice"]["message"]) + + # john receives alice's message + click_position(151, 110) # alice in john's contacts + machine.screenshot("kaidan_chat_log") # both messages should be here + ''; +} diff --git a/nixos/tests/kaidan/prosody.nix b/nixos/tests/kaidan/prosody.nix new file mode 100644 index 000000000000..d7ba8b6951a2 --- /dev/null +++ b/nixos/tests/kaidan/prosody.nix @@ -0,0 +1,59 @@ +{ + config, + pkgs, + lib, + ... +}: +# NOTE: most of this is taken from the prosody test +let + cert = pkgs.runCommand "selfSignedCerts" { buildInputs = [ pkgs.openssl ]; } '' + openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -nodes -days 365 \ + -subj '/C=GB/CN=example.com/CN=uploads.example.com/CN=conference.example.com' -addext "subjectAltName = DNS:example.com,DNS:uploads.example.com,DNS:conference.example.com" + mkdir -p $out + cp key.pem cert.pem $out + ''; + + # Creates and set password for the 2 xmpp test users. + # + # Doing that in a bash script instead of doing that in the test + # script allow us to easily provision the users when running that + # test interactively. + createUsers = pkgs.writeShellScriptBin "create-prosody-users" '' + set -e + prosodyctl register alice example.com foobar + prosodyctl register john example.com foobar + ''; +in +{ + # Make the self-signed certificates work + security.pki.certificateFiles = [ "${cert}/cert.pem" ]; + + networking.extraHosts = '' + ${config.networking.primaryIPAddress} example.com + ${config.networking.primaryIPAddress} conference.example.com + ${config.networking.primaryIPAddress} uploads.example.com + ''; + + environment.systemPackages = [ + createUsers + ]; + + # Configure Prosody with self-signed certificates + services.prosody = { + enable = true; + ssl.cert = "${cert}/cert.pem"; + ssl.key = "${cert}/key.pem"; + virtualHosts.example = { + enabled = true; + domain = "example.com"; + ssl.cert = "${cert}/cert.pem"; + ssl.key = "${cert}/key.pem"; + }; + muc = [ { domain = "conference.example.com"; } ]; + httpFileShare = { + domain = "uploads.example.com"; + }; + }; + + networking.hosts."127.0.0.1" = [ "example.com" ]; +} diff --git a/pkgs/by-name/ka/kaidan/package.nix b/pkgs/by-name/ka/kaidan/package.nix index e6a83f357b41..fb85455a5ebc 100644 --- a/pkgs/by-name/ka/kaidan/package.nix +++ b/pkgs/by-name/ka/kaidan/package.nix @@ -3,6 +3,7 @@ stdenv, fetchFromGitLab, nix-update-script, + nixosTests, # build cmake, @@ -74,6 +75,7 @@ stdenv.mkDerivation (finalAttrs: { ''; passthru.updateScript = nix-update-script { extraArgs = [ "--version=branch" ]; }; + passthru.tests.kaidan = nixosTests.kaidan; meta = { description = "User-friendly and modern chat app, using XMPP";