summaryrefslogtreecommitdiffstats
path: root/nixos/tests/kaidan/default.nix
blob: 4cccfcf47026236c32977789bfe4936f8f84d4c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
{
  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;

  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(19, 52) # burger menu
        click_position(70, 150) # 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):
        click_position(19, 52) # burger menu
        machine.sleep(10)
        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)

        click_position(511, 500) # 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_console_text(r"(RosterPage|EmptyChatPage)")
        machine.sleep(10)

        # we add a second account, which will be communicating with the first one
        add_user_account("alice")
        machine.wait_for_console_text(r"(RosterPage|EmptyChatPage)")
        machine.sleep(10)

      # 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")
        machine.sleep(10)

        # 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
    '';
}