Add integration test for nc admin section

Signed-off-by: Tobias Knöppler <6317548+theCalcaholic@users.noreply.github.com>
This commit is contained in:
Tobias Knöppler 2023-10-19 23:37:45 +02:00
parent 3958883e62
commit a76c8a9c88
No known key found for this signature in database
GPG Key ID: 3510056072886A8F
7 changed files with 129 additions and 25 deletions

View File

@ -219,15 +219,16 @@ function get_app_params() {
local cfg="$( cat "$cfg_file" )"
local param_count="$(jq ".params | length" <<<"$cfg")"
local i=0
local json="{"$'\n'
local json="{"
while [[ $i -lt $param_count ]]
do
param_id="$(jq -r ".params[$i].id" <<<"$cfg")"
param_val="$(jq -r ".params[$i].value" <<<"$cfg")"
json="${json} \"${param_id}\": \"${param_val}\","$'\n'
json="${json}"$'\n'" \"${param_id}\": \"${param_val}\""
i=$((i+1))
[[ $i -lt $param_count ]] && json="${json},"
done
json="${json}}"
json="${json}"$'\n'"}"
echo "$json"
return 0
}

View File

@ -6,9 +6,14 @@ namespace OCA\NextcloudPi\Service;
use OCA\NextcloudPi\Exceptions\InvalidSettingsException;
use OCA\NextcloudPi\Exceptions\SaveSettingsException;
use Psr\Log\LoggerInterface;
class SettingsService {
private LoggerInterface $logger;
public function __construct(LoggerInterface $logger) {
$this->logger = $logger;
}
/**
* @param $name string of the config
@ -20,10 +25,14 @@ class SettingsService {
[$ret, $config_str, $stderr] = $this->runCommand( "bash -c \"sudo /home/www/ncp-app-bridge.sh config $name\"");
$config = null;
if ($ret == 0) {
$config = json_decode($config_str, true);
try {
$config = json_decode($config_str, true, 512, JSON_THROW_ON_ERROR);
} catch (\Exception $e) {
$this->logger->error($e);
}
}
if ($config == null) {
error_log("Failed to retrieve ncp config (exit code: $ret)");
$this->logger->error("Failed to retrieve ncp config (exit code: $ret)");
return $defaults;
}
return $config;
@ -55,10 +64,10 @@ class SettingsService {
};
$settings_map = [
"CANARY" => ["ncp-community", "CANARY", $parseBool],
"ADMIN_NOTIFICATIONS" => ["ncp-community", "ADMIN_NOTIFICATIONS", $parseBool],
"USAGE_SURVEYS" => ["ncp-community", "USAGE_SURVEYS", $parseBool],
"NOTIFICATION_ACCOUNTS" => ["ncp-community", "NOTIFICATION_ACCOUNTS", $identityFn]
"canary" => ["ncp-community", "CANARY", $parseBool],
"adminNotifications" => ["ncp-community", "ADMIN_NOTIFICATIONS", $parseBool],
"usageSurveys" => ["ncp-community", "USAGE_SURVEYS", $parseBool],
"notificationAccounts" => ["ncp-community", "NOTIFICATION_ACCOUNTS", $identityFn]
];
foreach ($settings as $k => $value) {

View File

@ -31,7 +31,7 @@ class AdminSettings implements ISettings {
"CANARY" => 'no',
"USAGE_SURVEYS" => 'no',
"ADMIN_NOTIFICATIONS" => 'no',
"NOtIFICATION_ACCOUNTS" => ""
"NOTIFICATION_ACCOUNTS" => ""
]);
$ncp_version = trim($this->service->getFileContent("ncp-version", "unknown"));

View File

@ -28,8 +28,8 @@ style('nextcloudpi', 'admin');
<label for="adminNotifications">Enable notifications about relevant changes in NCP</label>
</li>
<li>
<input name="adminNotifications" type="checkbox" <?php echo $_['community']['USAGE_SURVEYS'] === 'yes' ? ' checked="checked"' : ''; ?>"/>
<label for="adminNotifications">Enable notifications for surveys that help to improve NCP</label>
<input name="usageSurveys" type="checkbox" <?php echo $_['community']['USAGE_SURVEYS'] === 'yes' ? ' checked="checked"' : ''; ?>"/>
<label for="usageSurveys">Enable notifications for surveys that help to improve NCP</label>
</li>
<li>
<div>Accounts to notify:</div>

2
ncp.sh
View File

@ -199,8 +199,6 @@ action="${1?}"
. /usr/local/etc/library.sh
[[ -z "${key}" ]] || {
set_app_param ncp-community.sh "${key}" "${val}"
get_app_params ncp-community.sh
exit 0
}
get_app_params ncp-community.sh
exit $?

View File

@ -11,18 +11,20 @@ Use at your own risk!
More at https://ownyourbits.com
"""
import json
import sys
import time
import urllib
import os
import getopt
import configparser
import signal
import re
import time
from pathlib import Path
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.firefox.options import Options
from selenium.common.exceptions import NoSuchElementException, WebDriverException, TimeoutException
@ -48,14 +50,14 @@ class TestFailed(Exception):
class Test:
title = "test"
title = "test"
def new(self, title):
self.title = title
print("[check] " + "{:16}".format(title), end=' ', flush = True)
def check(self, expression, msg=None):
if expression:
if expression and not isinstance(expression, Exception):
print(tc.green + "ok" + tc.normal)
self.log("ok")
else:
@ -66,7 +68,6 @@ class Test:
exc_args.append(expression)
if msg is not None:
exc_args.append(msg)
raise TestFailed(*exc_args)
def report(self, title, expression, msg=None):
@ -112,6 +113,13 @@ class VisibilityOfElementLocatedByAnyLocator:
class ConfigTestFailure(Exception):
pass
def is_admin_notifications_checkbox(item: WebElement):
try:
input_item = item.find_element(By.TAG_NAME, "input")
return input_item.get_attribute("name") == "adminNotifications"
except:
return False
def test_nextcloud(IP: str, nc_port: str, driver: WebDriver):
""" Login and assert admin page checks"""
@ -132,7 +140,10 @@ def test_nextcloud(IP: str, nc_port: str, driver: WebDriver):
try:
driver.find_element(By.ID, "submit").click()
except NoSuchElementException:
pass
try:
driver.find_element(By.CSS_SELECTOR, ".login-form button[type=submit]").click()
except NoSuchElementException:
pass
test.report("password", "Wrong password" not in driver.page_source, msg="Failed to login with provided password")
@ -154,10 +165,11 @@ def test_nextcloud(IP: str, nc_port: str, driver: WebDriver):
infos = driver.find_elements(By.CSS_SELECTOR, "#postsetupchecks > .info > li")
for info in infos:
if re.match(r'.*Your installation has no default phone region set.*', info.text):
if re.match(r'.*Your installation has no default phone region set.*', info.text) \
or re.match(r'The PHP module "imagick" is not enabled', info.text):
continue
else:
print('text', info.text)
php_modules = info.find_elements(By.CSS_SELECTOR, "li")
if len(php_modules) != 1:
raise ConfigTestFailure(f"Could not find the list of php modules within the info message "
@ -174,6 +186,88 @@ def test_nextcloud(IP: str, nc_port: str, driver: WebDriver):
except Exception as e:
test.check(e)
try:
overlay_close_btn = driver.find_element(By.CLASS_NAME, "modal-container__close")
if overlay_close_btn.is_displayed():
overlay_close_btn.click()
time.sleep(3)
except NoSuchElementException:
pass
test.new("admin section (1)")
try:
driver.get(f"https://{IP}:{nc_port}/index.php/settings/admin")
except Exception as e:
test.check(e, msg=f"{tc.red}error:{tc.normal} unable to reach {tc.yellow + IP + tc.normal}")
old_admin_notifications_value = None
list_items = driver.find_elements(By.CSS_SELECTOR, "#nextcloudpi li")
try:
wait.until(lambda drv: drv.find_element(By.ID, "nextcloudpi").is_displayed())
expected = {
"ncp_version": False,
"php_version": False,
"debian_release": False,
"canary": False,
"admin_notifications": False,
# "usage_surveys": False,
"notification_accounts": False
}
version_re = re.compile(r'^(v\d+\.\d+\.\d+)$')
with (Path(__file__).parent / '../etc/ncp.cfg').open('r') as cfg_file:
ncp_cfg = json.load(cfg_file)
for li in list_items:
try:
inp = li.find_element(By.TAG_NAME, "input")
inp_name = inp.get_attribute("name")
inp_value = inp.get_attribute("value") if inp.get_attribute("type") != "checkbox" else inp.is_selected()
if inp_name == "canary":
expected["canary"] = True
elif inp_name == "adminNotifications":
old_admin_notifications_value = inp_value
expected["admin_notifications"] = True
elif inp_name == "usageSurveys":
expected["usage_surveys"] = True
elif inp_name == "notificationAccounts":
expected["notification_accounts"] = True
except:
divs = li.find_elements(By.TAG_NAME, "div")
if 'ncp version' in divs[0].text.lower() and version_re.match(divs[1].text):
expected['ncp_version'] = True
elif 'php version' in divs[0].text.lower() and divs[1].text == ncp_cfg['php_version']:
expected['php_version'] = True
elif 'debian release' in divs[0].text.lower() and divs[1].text == ncp_cfg['release']:
expected['debian_release'] = True
failed = list(map(lambda item: item[0], filter(lambda item: not item[1], expected.items())))
test.check(len(failed) == 0, f"checks failed for admin section: [{', '.join(failed)}]")
except Exception as e:
test.check(e)
test.new("admin section (2)")
wait = WebDriverWait(driver, 10)
try:
li = next(filter(is_admin_notifications_checkbox, list_items))
li.find_element(By.TAG_NAME, "input").click()
time.sleep(5)
wait.until(lambda drv: drv.find_element(By.CSS_SELECTOR, "#nextcloudpi .error-message:not(.hidden)"))
error_box = driver.find_element(By.CSS_SELECTOR, "#nextcloudpi .error-message")
test.check(False, str(error_box.text))
except Exception as e:
if isinstance(e, TestFailed):
raise e
test.check(True)
test.new("admin section (3)")
try:
driver.refresh()
except Exception as e:
test.check(e, msg=f"{tc.red}error:{tc.normal} unable to reach {tc.yellow + IP + tc.normal}")
try:
list_items = driver.find_elements(By.CSS_SELECTOR, "#nextcloudpi li")
li = next(filter(is_admin_notifications_checkbox, list_items))
test.check(li.find_element(By.TAG_NAME, "input").is_selected() != old_admin_notifications_value,
"Toggling admin notifications didn't work")
except Exception as e:
test.check(e)
if __name__ == "__main__":
signal.signal(signal.SIGINT, signal_handler)
@ -231,13 +325,17 @@ if __name__ == "__main__":
print("---------------------------")
driver = webdriver.Firefox(options=options)
failed=False
try:
test_nextcloud(IP, nc_port, driver)
except Exception as e:
print(e)
print(traceback.format_exc())
failed=True
finally:
driver.close()
if failed:
sys.exit(1)
# License
#

View File

@ -31,8 +31,6 @@ action="${1?}"
. /usr/local/etc/library.sh
[[ -z "${key}" ]] || {
set_app_param ncp-community.sh "${key}" "${val}"
get_app_params ncp-community.sh
exit 0
}
get_app_params ncp-community.sh
exit $?