1import ./make-test-python.nix (
2 { pkgs, lib, ... }:
3
4 let
5 user = "alice"; # from ./common/user-account.nix
6 password = "foobar"; # from ./common/user-account.nix
7 in
8 {
9 name = "cockpit";
10 meta = {
11 maintainers = with lib.maintainers; [ lucasew ];
12 };
13 nodes = {
14 server =
15 { config, ... }:
16 {
17 imports = [ ./common/user-account.nix ];
18 security.polkit.enable = true;
19 users.users.${user} = {
20 extraGroups = [ "wheel" ];
21 };
22 services.cockpit = {
23 enable = true;
24 port = 7890;
25 openFirewall = true;
26 allowed-origins = [
27 "https://server:${toString config.services.cockpit.port}"
28 ];
29 };
30 };
31 client =
32 { config, ... }:
33 {
34 imports = [ ./common/user-account.nix ];
35 environment.systemPackages =
36 let
37 seleniumScript =
38 pkgs.writers.writePython3Bin "selenium-script"
39 {
40 libraries = with pkgs.python3Packages; [ selenium ];
41 }
42 ''
43 from selenium import webdriver
44 from selenium.webdriver.common.by import By
45 from selenium.webdriver.firefox.options import Options
46 from selenium.webdriver.support.ui import WebDriverWait
47 from selenium.webdriver.support import expected_conditions as EC
48 from time import sleep
49
50
51 def log(msg):
52 from sys import stderr
53 print(f"[*] {msg}", file=stderr)
54
55
56 log("Initializing")
57
58 options = Options()
59 options.add_argument("--headless")
60
61 service = webdriver.FirefoxService(executable_path="${lib.getExe pkgs.geckodriver}") # noqa: E501
62 driver = webdriver.Firefox(options=options, service=service)
63
64 driver.implicitly_wait(10)
65
66 log("Opening homepage")
67 driver.get("https://server:7890")
68
69
70 def wait_elem(by, query, timeout=10):
71 wait = WebDriverWait(driver, timeout)
72 wait.until(EC.presence_of_element_located((by, query)))
73
74
75 def wait_title_contains(title, timeout=10):
76 wait = WebDriverWait(driver, timeout)
77 wait.until(EC.title_contains(title))
78
79
80 def find_element(by, query):
81 return driver.find_element(by, query)
82
83
84 def set_value(elem, value):
85 script = 'arguments[0].value = arguments[1]'
86 return driver.execute_script(script, elem, value)
87
88
89 log("Waiting for the homepage to load")
90
91 # cockpit sets initial title as hostname
92 wait_title_contains("server")
93 wait_elem(By.CSS_SELECTOR, 'input#login-user-input')
94
95 log("Homepage loaded!")
96
97 log("Filling out username")
98 login_input = find_element(By.CSS_SELECTOR, 'input#login-user-input')
99 set_value(login_input, "${user}")
100
101 log("Filling out password")
102 password_input = find_element(By.CSS_SELECTOR, 'input#login-password-input')
103 set_value(password_input, "${password}")
104
105 log("Submitting credentials for login")
106 driver.find_element(By.CSS_SELECTOR, 'button#login-button').click()
107
108 # driver.implicitly_wait(1)
109 # driver.get("https://server:7890/system")
110
111 log("Waiting dashboard to load")
112 wait_title_contains("${user}@server")
113
114 log("Waiting for the frontend to initialize")
115 sleep(1)
116
117 log("Looking for that banner that tells about limited access")
118 container_iframe = find_element(By.CSS_SELECTOR, 'iframe.container-frame')
119 driver.switch_to.frame(container_iframe)
120
121 assert "Web console is running in limited access mode" in driver.page_source
122
123 log("Clicking the sudo button")
124 for button in driver.find_elements(By.TAG_NAME, "button"):
125 if 'admin' in button.text:
126 button.click()
127 driver.switch_to.default_content()
128
129 log("Checking that /nonexistent is not a thing")
130 assert '/nonexistent' not in driver.page_source
131 assert len(driver.find_elements(By.CSS_SELECTOR, '#machine-reconnect')) == 0
132
133 driver.close()
134 '';
135 in
136 with pkgs;
137 [
138 firefox-unwrapped
139 geckodriver
140 seleniumScript
141 ];
142 };
143 };
144
145 testScript = ''
146 start_all()
147
148 server.wait_for_unit("sockets.target")
149 server.wait_for_open_port(7890)
150
151 client.succeed("curl -k https://server:7890 -o /dev/stderr")
152 print(client.succeed("whoami"))
153 client.succeed('PYTHONUNBUFFERED=1 selenium-script')
154 '';
155 }
156)