#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Selenium Tests
#
# Copyright 2017-2022 Univention GmbH
#
# https://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <https://www.gnu.org/licenses/>.
from __future__ import absolute_import, print_function
import time
from typing import Any, Dict, Mapping, Optional # noqa: F401
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.keys import Keys
import univention.testing.strings as uts
import univention.testing.ucr as ucr_test
from univention.admin import localization
translator = localization.translation('ucs-test-framework')
_ = translator.translate
[docs]class UDMBase(object):
name = None
def __init__(self, selenium):
# type: (Any) -> None
self.selenium = selenium
def _get_search_value(self, objectname):
# type: (Any) -> str
return objectname
def _get_grid_value(self, objectname):
# type: (Any) -> str
return objectname
[docs] def exists(self, objectname):
# type: (str) -> bool
print('*** check if object exists', objectname)
# This method will work with *most* UDM modules.
self.search(self._get_search_value(objectname))
time.sleep(5)
self.selenium.wait_until_all_standby_animations_disappeared()
try:
self.selenium.wait_for_text(self._get_grid_value(objectname), timeout=1)
return True
except TimeoutException:
pass
return False
[docs] def open_module(self):
self.selenium.open_module(self.name)
[docs] def open_details(self, objectname):
# type: (str) -> None
print('*** open detail page of object', objectname)
# This method will work with *most* UDM modules.
self.search(self._get_search_value(objectname))
self.selenium.click_grid_entry(self._get_grid_value(objectname))
self.selenium.wait_until_standby_animation_appears_and_disappears()
[docs] def close_details(self):
# type: () -> None
print('*** close the detailpage')
self.selenium.click_button(_('Back'))
self.wait_for_main_grid_load()
[docs] def save_details(self):
# type: () -> None
print('*** save the detailpage')
self.selenium.click_button(_('Save'))
self.wait_for_main_grid_load()
[docs] def delete(self, objectname):
# type: (str) -> None
print('*** remove the object with name=', objectname)
# This method will work with *most* UDM modules.
self.search(self._get_search_value(objectname))
self.selenium.click_checkbox_of_grid_entry(self._get_grid_value(objectname))
self.selenium.click_button(_('Delete'))
self.selenium.wait_for_text(_("Please confirm the removal"))
self.selenium.click_element(
'//div[contains(concat(" ", normalize-space(@class), " "), " dijitDialog ")]'
'//*[contains(concat(" ", normalize-space(@class), " "), " dijitButtonText ")]'
'[text() = "%s"]' % (_("Delete"),)
)
# FIXME: this waits forever and let's the test fail when no grid entries exists.
# self.wait_for_main_grid_load()
[docs] def search(self, objectname):
# type: (str) -> None
print('*** searching for objects with name=', objectname)
# This method will work with *most* UDM modules.
xpath = '//input[@name="objectPropertyValue"]'
elems = webdriver.support.ui.WebDriverWait(xpath, 60).until(
self.selenium.get_all_enabled_elements
)
elems[0].clear()
elems[0].send_keys(objectname)
elems[0].send_keys(Keys.RETURN)
self.wait_for_main_grid_load()
elems[0].clear()
[docs] def wait_for_main_grid_load(self, timeout=60):
# type: (int) -> None
print('*** waiting for main grid load')
self.selenium.wait_until_standby_animation_appears_and_disappears()
[docs] def open_add_dialog(self, container=None, template=None):
# type: (Optional[str], Optional[str]) -> None
print('*** open the add dialog')
self.selenium.click_button(_('Add'))
self.selenium.wait_until_all_standby_animations_disappeared()
try:
self.selenium.wait_for_text(_('This UCS system is part of an Active Directory domain'), timeout=1)
except TimeoutException:
pass
else:
self.selenium.click_button(_('Next'))
# FIXME: clicking Next on the page with the active directory warning
# cuts the dialog in half and the dom elements are not clickable/visible.
# This is a workaround
dialogs = self.selenium.driver.find_elements_by_class_name('umcUdmNewObjectDialog')
if len(dialogs):
self.selenium.driver.execute_script('dijit.byId("%s")._position()' % (dialogs[0].get_attribute('widgetid')))
click_next = False
try:
self.selenium.wait_for_text(_('Container'), timeout=1)
click_next = True
except TimeoutException:
pass
# FIXME: select the given container
try:
self.selenium.wait_for_text(_("User template"), timeout=1)
click_next = True
except TimeoutException:
pass
if template is not None:
self.selenium.enter_input_combobox('objectTemplate', template)
if click_next:
self.selenium.click_button(_('Next'))
self.selenium.wait_until_all_standby_animations_disappeared()
[docs] def open_advanced_add_dialog(self, **kwargs):
# type: (**Any) -> None
self.open_add_dialog(**kwargs)
self.selenium.click_button(_('Advanced'))
[docs]class Portals(UDMBase):
name = _('Portal settings')
def __init__(self, selenium):
# type: (Any) -> None
super(Portals, self).__init__(selenium)
self.ucr = ucr_test.UCSTestConfigRegistry()
self.ucr.load()
[docs] def add(self, portalname=None, hostname=None):
# type: (Optional[str], Optional[str]) -> str
if portalname is None:
portalname = uts.random_string()
self.open_add_dialog()
# FIXME add this to the open_add_dialog() function
self.selenium.enter_input_combobox('objectType', 'Portal: Portal')
self.selenium.wait_until_standby_animation_appears_and_disappears()
self.selenium.click_button('Next')
self.selenium.wait_until_standby_animation_appears_and_disappears()
self.selenium.enter_input("name", portalname)
self.selenium.enter_input_combobox('__displayName-0-0', 'en_US', with_click=False)
self.selenium.enter_input('__displayName-0-1', uts.random_string())
if hostname is not None:
self.selenium.enter_input_combobox('__portalComputers-0-0', hostname)
self.selenium.click_button(_("Create portal"))
self.wait_for_main_grid_load()
return portalname
[docs]class Computers(UDMBase):
name = _('Computers')
[docs] def add(self, computername=None):
# type: (Optional[str]) -> str
if computername is None:
computername = uts.random_string()
self.open_add_dialog()
self.selenium.enter_input("name", computername)
self.selenium.click_button(_("Create computer"))
self.selenium.wait_for_text(_('has been created'))
self.selenium.click_button(_('Cancel'))
self.selenium.wait_until_all_dialogues_closed()
return computername
[docs]class Groups(UDMBase):
name = _("Groups")
[docs] def add(self, groupname=None):
# type: (Optional[str]) -> str
if groupname is None:
groupname = uts.random_string()
self.open_add_dialog()
self.selenium.wait_for_text(_("Members of this group"))
self.selenium.enter_input("name", groupname)
self.selenium.click_button(_("Create group"))
self.wait_for_main_grid_load()
return groupname
[docs]class Policies(UDMBase):
name = _('Policies')
[docs] def add(self, policyname=None):
# type: (Optional[str]) -> str
if policyname is None:
policyname = uts.random_string()
self.open_add_dialog()
self.selenium.enter_input("name", policyname)
self.selenium.click_button(_("Create policy"))
self.wait_for_main_grid_load()
return policyname
# fails in 4.4-0, Bug #48998
# def open_details(self, objectname):
# self.search(self._get_search_value(objectname))
# self.selenium.click_grid_entry(self._get_grid_value(objectname))
# self.selenium.wait_for_text(_('Advanced settings'))
[docs]class Users(UDMBase):
name = _("Users")
def __init__(self, selenium):
# type: (Any) -> None
super(Users, self).__init__(selenium)
self.ucr = ucr_test.UCSTestConfigRegistry()
self.ucr.load()
[docs] def get_description(self):
# type: () -> str
xpath = '//input[@name="description"]'
elems = webdriver.support.ui.WebDriverWait(xpath, 60).until(
self.selenium.get_all_enabled_elements
)
return elems[0].get_attribute('value')
[docs] def get_primary_mail(self):
# type: () -> str
xpath = '//input[@name="mailPrimaryAddress"]'
elems = webdriver.support.ui.WebDriverWait(xpath, 60).until(
self.selenium.get_all_enabled_elements
)
return elems[0].get_attribute('value')
[docs] def add(
self,
template=None, # type: Optional[str]
firstname='', # type: str
lastname=None, # type: Optional[str]
username=None, # type: Optional[str]
password='univention' # type: str
): # type: (...) -> Dict[str, str]
if username is None:
username = uts.random_string()
if lastname is None:
lastname = uts.random_string()
self.open_add_dialog(template=template)
self.selenium.wait_for_text(_("First name"))
self.selenium.enter_input("firstname", firstname)
self.selenium.enter_input("lastname", lastname)
self.selenium.enter_input("username", username)
self.selenium.click_button(_("Next"))
self.selenium.wait_for_text(_("Password"))
self.selenium.enter_input("password_1", password)
self.selenium.enter_input("password_2", password)
self.selenium.click_button(_("Create user"))
self.selenium.wait_for_text(_('has been created'))
self.selenium.click_button(_('Cancel'))
self.selenium.wait_until_all_dialogues_closed()
return {'username': username, 'lastname': lastname}
[docs] def copy(self, user, username='', lastname='', password='univention', **kwargs):
username = username or uts.random_string()
self.search(user)
self.selenium.click_checkbox_of_grid_entry(user)
self.selenium.click_text(_('more'))
self.selenium.click_text(_('Copy'))
try:
self.selenium.wait_for_any_text_in_list(['Container', 'Template'], timeout=5)
self.selenium.click_button('Next')
except TimeoutException:
pass
finally:
self.selenium.wait_until_standby_animation_appears_and_disappears()
self.selenium.enter_input('username', username)
self.selenium.enter_input('lastname', lastname or uts.random_string())
self.selenium.enter_input('password_1', password)
self.selenium.enter_input('password_2', password)
for key, value in kwargs.items():
self.selenium.enter_input(key, value)
self.selenium.click_text(_('Create user'))
self.selenium.wait_until_standby_animation_appears_and_disappears()
# TODO: check for error
return username
def _get_search_value(self, user):
# type: (Mapping[str, str]) -> str
return user['username']
def _get_grid_value(self, user):
# type: (Mapping[str, str]) -> str
return user['lastname'] if self.ucr.get('ad/member') else user['username']