FreedomBox/plinth/modules/users/tests/test_functional.py
Veiko Aasa 9c7b4d7b84
tests: functional: Improve creating users in tests
- Do not require a user password when creating a user. Generate a password
  if not provided.
- Before creating a user, delete previous user with the same name.
- Delete user: Do not skip if the user doesn't exist. It avoids the
  situation that some @when tests may silently skip.
- Update openvpn and deluge functional tests assuming passwords were not
  under the tests.

Tests performed:
- users, openvpn and deluge app functional tests pass.

Signed-off-by: Veiko Aasa <veiko17@disroot.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
2021-01-09 22:03:00 -05:00

314 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SPDX-License-Identifier: AGPL-3.0-or-later
"""
Functional, browser based tests for users app.
"""
import subprocess
import urllib
import pytest
from pytest_bdd import given, parsers, scenarios, then, when
from plinth.tests import functional
_admin_password = functional.config['DEFAULT']['password']
scenarios('users.feature')
_language_codes = {
'None': '',
'Deutsch': 'de',
'Nederlands': 'nl',
'Português': 'pt',
'Türkçe': 'tr',
'dansk': 'da',
'español': 'es',
'français': 'fr',
'norsk (bokmål)': 'nb',
'polski': 'pl',
'svenska': 'sv',
'Русский': 'ru',
'తెలుగు': 'te',
'简体中文': 'zh-hans'
}
_config_page_title_language_map = {
'': 'General Configuration',
'da': 'Generel Konfiguration',
'de': 'Allgemeine Konfiguration',
'es': 'Configuración general',
'fr': 'Configuration générale',
'nb': 'Generelt oppsett',
'nl': 'Algemene Instellingen',
'pl': 'Ustawienia główne',
'pt': 'Configuração Geral',
'ru': 'Общие настройки',
'sv': 'Allmän Konfiguration',
'te': 'సాధారణ ఆకృతీకరణ',
'tr': 'Genel Yapılandırma',
'zh-hans': '常规配置',
}
@given(parsers.parse('the admin user {name:w} exists'))
def admin_user_exists(session_browser, name):
if functional.user_exists(session_browser, name):
functional.delete_user(session_browser, name)
functional.create_user(session_browser, name, groups=['admin'])
@given(parsers.parse("the user {name:w} doesn't exist"))
def user_does_not_exist(session_browser, name):
if functional.user_exists(session_browser, name):
functional.delete_user(session_browser, name)
@given(parsers.parse('the ssh keys are {ssh_keys:w}'))
def ssh_keys(session_browser, ssh_keys):
_set_ssh_keys(session_browser, ssh_keys)
@given('the client has a ssh key')
def generate_ssh_keys(session_browser, tmp_path_factory):
key_file = tmp_path_factory.getbasetemp() / 'users-ssh.key'
try:
key_file.unlink()
except FileNotFoundError:
pass
subprocess.check_call(
['ssh-keygen', '-t', 'ed25519', '-N', '', '-q', '-f',
str(key_file)])
@when(parsers.parse('I create a user named {name:w}'))
def create_user(session_browser, name):
functional.create_user(session_browser, name)
@when(parsers.parse('I rename the user {old_name:w} to {new_name:w}'))
def rename_user(session_browser, old_name, new_name):
_rename_user(session_browser, old_name, new_name)
@when(parsers.parse('I delete the user {name:w}'))
def delete_user(session_browser, name):
functional.delete_user(session_browser, name)
@when('I change the language to <language>')
def change_language(session_browser, language):
_set_language(session_browser, _language_codes[language])
@when(parsers.parse('I change the ssh keys to {ssh_keys:w}'))
def change_ssh_keys(session_browser, ssh_keys):
_set_ssh_keys(session_browser, ssh_keys)
@when('I remove the ssh keys')
def remove_ssh_keys(session_browser):
_set_ssh_keys(session_browser, '')
@when(
parsers.parse(
'I change the ssh keys to {ssh_keys:w} for the user {username:w}'))
def change_user_ssh_keys(session_browser, ssh_keys, username):
_set_ssh_keys(session_browser, ssh_keys, username=username)
@when(parsers.parse('I change my ssh keys to {ssh_keys:w}'))
def change_my_ssh_keys(session_browser, ssh_keys):
_set_ssh_keys(session_browser, ssh_keys)
@when(parsers.parse('I set the user {username:w} as inactive'))
def set_user_inactive(session_browser, username):
_set_user_inactive(session_browser, username)
@when(parsers.parse('I change my password to {new_password:w}'))
def change_my_password(session_browser, new_password):
_change_password(session_browser, new_password)
@when(
parsers.parse(
'I change the user {username:w} password to {new_password:w}'))
def change_other_user_password(session_browser, username, new_password):
_change_password(session_browser, new_password, username=username)
@when('I configure the ssh keys')
def configure_ssh_keys(session_browser, tmp_path_factory):
public_key_file = tmp_path_factory.getbasetemp() / 'users-ssh.key.pub'
public_key = public_key_file.read_text()
_set_ssh_keys(session_browser, public_key)
@then(parsers.parse('I can log in as the user {username:w}'))
def can_log_in(session_browser, username):
functional.login_with_account(session_browser, functional.base_url,
username)
assert len(session_browser.find_by_id('id_user_menu')) > 0
@then(
parsers.parse(
'I can log in as the user {username:w} with password {password:w}'))
def can_log_in_with_password(session_browser, username, password):
functional.visit(session_browser, '/plinth/accounts/logout/')
functional.login_with_account(session_browser, functional.base_url,
username, password)
assert len(session_browser.find_by_id('id_user_menu')) > 0
@then(parsers.parse("I can't log in as the user {username:w}"))
def cannot_log_in(session_browser, username):
functional.login_with_account(session_browser, functional.base_url,
username)
assert len(session_browser.find_by_id('id_user_menu')) == 0
@then('Plinth language should be <language>')
def plinth_language_should_be(session_browser, language):
assert _check_language(session_browser, _language_codes[language])
@then(parsers.parse('the ssh keys should be {ssh_keys:w}'))
def ssh_keys_match(session_browser, ssh_keys):
assert _get_ssh_keys(session_browser) == ssh_keys
@then('the ssh keys should be removed')
def ssh_keys_should_be_removed(session_browser, ssh_keys):
assert _get_ssh_keys(session_browser) == ''
@then(
parsers.parse(
'the ssh keys should be {ssh_keys:w} for the user {username:w}'))
def ssh_keys_match_for_user(session_browser, ssh_keys, username):
assert _get_ssh_keys(session_browser, username=username) == ssh_keys
@then(parsers.parse('my ssh keys should be {ssh_keys:w}'))
def my_ssh_keys_match(session_browser, ssh_keys):
assert _get_ssh_keys(session_browser) == ssh_keys
@then('the client should be able to connect passwordless over ssh')
def should_connect_passwordless_over_ssh(session_browser, tmp_path_factory):
key_file = tmp_path_factory.getbasetemp() / 'users-ssh.key'
_try_login_to_ssh(key_file=key_file)
@then("the client shouldn't be able to connect passwordless over ssh")
def should_not_connect_passwordless_over_ssh(session_browser,
tmp_path_factory):
key_file = tmp_path_factory.getbasetemp() / 'users-ssh.key'
with pytest.raises(subprocess.CalledProcessError):
_try_login_to_ssh(key_file=key_file)
@then(parsers.parse('{name:w} should be listed as a user'))
def new_user_is_listed(session_browser, name):
assert functional.user_exists(session_browser, name)
@then(parsers.parse('{name:w} should not be listed as a user'))
def new_user_is_not_listed(session_browser, name):
assert not functional.user_exists(session_browser, name)
def _rename_user(browser, old_name, new_name):
functional.nav_to_module(browser, 'users')
with functional.wait_for_page_update(browser):
browser.find_link_by_href('/plinth/sys/users/' + old_name +
'/edit/').first.click()
browser.find_by_id('id_username').fill(new_name)
browser.find_by_id('id_confirm_password').fill(_admin_password)
functional.submit(browser)
def _set_language(browser, language_code):
username = functional.config['DEFAULT']['username']
functional.visit(browser, '/plinth/sys/users/{}/edit/'.format(username))
browser.find_by_xpath('//select[@id="id_language"]//option[@value="' +
language_code + '"]').first.click()
browser.find_by_id('id_confirm_password').fill(_admin_password)
functional.submit(browser)
def _check_language(browser, language_code):
functional.nav_to_module(browser, 'config')
return browser.find_by_css('.app-titles').first.find_by_tag(
'h2').first.value == _config_page_title_language_map[language_code]
def _get_ssh_keys(browser, username=None):
functional.visit(browser, '/plinth/')
if username is None:
browser.find_by_id('id_user_menu').click()
browser.find_by_id('id_user_edit_menu').click()
else:
functional.visit(browser,
'/plinth/sys/users/{}/edit/'.format(username))
return browser.find_by_id('id_ssh_keys').text
def _set_ssh_keys(browser, ssh_keys, username=None):
if username is None:
browser.find_by_id('id_user_menu').click()
browser.find_by_id('id_user_edit_menu').click()
else:
functional.visit(browser,
'/plinth/sys/users/{}/edit/'.format(username))
current_user = browser.find_by_id('id_user_menu_link').text
auth_password = functional.get_password(current_user)
browser.find_by_id('id_ssh_keys').fill(ssh_keys)
browser.find_by_id('id_confirm_password').fill(auth_password)
functional.submit(browser)
def _set_user_inactive(browser, username):
functional.visit(browser, '/plinth/sys/users/{}/edit/'.format(username))
browser.find_by_id('id_is_active').uncheck()
browser.find_by_id('id_confirm_password').fill(_admin_password)
functional.submit(browser)
def _change_password(browser, new_password, current_password=None,
username=None):
if username is None:
browser.find_by_id('id_user_menu').click()
browser.find_by_id('id_change_password_menu').click()
else:
functional.visit(
browser, '/plinth/sys/users/{}/change_password/'.format(username))
current_user = browser.find_by_id('id_user_menu_link').text
auth_password = current_password or functional.get_password(current_user)
browser.find_by_id('id_new_password1').fill(new_password)
browser.find_by_id('id_new_password2').fill(new_password)
browser.find_by_id('id_confirm_password').fill(auth_password)
functional.submit(browser)
def _try_login_to_ssh(key_file=None):
user = functional.config['DEFAULT']['username']
hostname = urllib.parse.urlparse(
functional.config['DEFAULT']['url']).hostname
port = functional.config['DEFAULT']['ssh_port']
subprocess.check_call([
'ssh', '-p', port, '-i', key_file, '-q', '-o',
'StrictHostKeyChecking=no', '-o', 'UserKnownHostsFile=/dev/null', '-o',
'BatchMode=yes', '{0}@{1}'.format(user, hostname), '/bin/true'
])