blob: dbee36aa4ec9875a2bab672a467ff787e2e90e3a [file] [log] [blame]
#! /usr/bin/env python3 #
# BitBake Toaster UI tests implementation
#
# Copyright (C) 2023 Savoir-faire Linux
#
# SPDX-License-Identifier: GPL-2.0-only
#
import string
import random
import pytest
from django.urls import reverse
from selenium.webdriver import Keys
from selenium.webdriver.support.select import Select
from selenium.common.exceptions import TimeoutException
from tests.functional.functional_helpers import SeleniumFunctionalTestCase
from selenium.webdriver.common.by import By
from .utils import get_projectId_from_url
@pytest.mark.django_db
@pytest.mark.order("last")
class TestProjectConfig(SeleniumFunctionalTestCase):
project_id = None
PROJECT_NAME = 'TestProjectConfig'
INVALID_PATH_START_TEXT = 'The directory path should either start with a /'
INVALID_PATH_CHAR_TEXT = 'The directory path cannot include spaces or ' \
'any of these characters'
def _create_project(self, project_name):
""" Create/Test new project using:
- Project Name: Any string
- Release: Any string
- Merge Toaster settings: True or False
"""
self.get(reverse('newproject'))
self.wait_until_visible('#new-project-name', poll=2)
self.find("#new-project-name").send_keys(project_name)
select = Select(self.find("#projectversion"))
select.select_by_value('3')
# check merge toaster settings
checkbox = self.find('.checkbox-mergeattr')
if not checkbox.is_selected():
checkbox.click()
if self.PROJECT_NAME != 'TestProjectConfig':
# Reset project name if it's not the default one
self.PROJECT_NAME = 'TestProjectConfig'
self.find("#create-project-button").click()
try:
self.wait_until_visible('#hint-error-project-name', poll=2)
url = reverse('project', args=(TestProjectConfig.project_id, ))
self.get(url)
self.wait_until_visible('#config-nav', poll=3)
except TimeoutException:
self.wait_until_visible('#config-nav', poll=3)
def _random_string(self, length):
return ''.join(
random.choice(string.ascii_letters) for _ in range(length)
)
def _get_config_nav_item(self, index):
config_nav = self.find('#config-nav')
return config_nav.find_elements(By.TAG_NAME, 'li')[index]
def _navigate_bbv_page(self):
""" Navigate to project BitBake variables page """
# check if the menu is displayed
if TestProjectConfig.project_id is None:
self._create_project(project_name=self._random_string(10))
current_url = self.driver.current_url
TestProjectConfig.project_id = get_projectId_from_url(current_url)
else:
url = reverse('projectconf', args=(TestProjectConfig.project_id,))
self.get(url)
self.wait_until_visible('#config-nav', poll=3)
bbv_page_link = self._get_config_nav_item(9)
bbv_page_link.click()
self.wait_until_visible('#config-nav', poll=3)
def test_no_underscore_iamgefs_type(self):
"""
Should not accept IMAGEFS_TYPE with an underscore
"""
self._navigate_bbv_page()
imagefs_type = "foo_bar"
self.wait_until_visible('#change-image_fstypes-icon', poll=2)
self.click('#change-image_fstypes-icon')
self.enter_text('#new-imagefs_types', imagefs_type)
element = self.wait_until_visible('#hintError-image-fs_type', poll=2)
self.assertTrue(("A valid image type cannot include underscores" in element.text),
"Did not find underscore error message")
def test_checkbox_verification(self):
"""
Should automatically check the checkbox if user enters value
text box, if value is there in the checkbox.
"""
self._navigate_bbv_page()
imagefs_type = "btrfs"
self.wait_until_visible('#change-image_fstypes-icon', poll=2)
self.click('#change-image_fstypes-icon')
self.enter_text('#new-imagefs_types', imagefs_type)
checkboxes = self.driver.find_elements(By.XPATH, "//input[@class='fs-checkbox-fstypes']")
for checkbox in checkboxes:
if checkbox.get_attribute("value") == "btrfs":
self.assertEqual(checkbox.is_selected(), True)
def test_textbox_with_checkbox_verification(self):
"""
Should automatically add or remove value in textbox, if user checks
or unchecks checkboxes.
"""
self._navigate_bbv_page()
self.wait_until_visible('#change-image_fstypes-icon', poll=2)
self.click('#change-image_fstypes-icon')
checkboxes_selector = '.fs-checkbox-fstypes'
self.wait_until_visible(checkboxes_selector, poll=2)
checkboxes = self.find_all(checkboxes_selector)
for checkbox in checkboxes:
if checkbox.get_attribute("value") == "cpio":
checkbox.click()
element = self.driver.find_element(By.ID, 'new-imagefs_types')
self.wait_until_visible('#new-imagefs_types', poll=2)
self.assertTrue(("cpio" in element.get_attribute('value'),
"Imagefs not added into the textbox"))
checkbox.click()
self.assertTrue(("cpio" not in element.text),
"Image still present in the textbox")
def test_set_download_dir(self):
"""
Validate the allowed and disallowed types in the directory field for
DL_DIR
"""
self._navigate_bbv_page()
# activate the input to edit download dir
try:
change_dl_dir_btn = self.wait_until_visible('#change-dl_dir-icon', poll=2)
except TimeoutException:
# If download dir is not displayed, test is skipped
change_dl_dir_btn = None
if change_dl_dir_btn:
change_dl_dir_btn = self.wait_until_visible('#change-dl_dir-icon', poll=2)
change_dl_dir_btn.click()
# downloads dir path doesn't start with / or ${...}
input_field = self.wait_until_visible('#new-dl_dir', poll=2)
input_field.clear()
self.enter_text('#new-dl_dir', 'home/foo')
element = self.wait_until_visible('#hintError-initialChar-dl_dir', poll=2)
msg = 'downloads directory path starts with invalid character but ' \
'treated as valid'
self.assertTrue((self.INVALID_PATH_START_TEXT in element.text), msg)
# downloads dir path has a space
self.driver.find_element(By.ID, 'new-dl_dir').clear()
self.enter_text('#new-dl_dir', '/foo/bar a')
element = self.wait_until_visible('#hintError-dl_dir', poll=2)
msg = 'downloads directory path characters invalid but treated as valid'
self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
# downloads dir path starts with ${...} but has a space
self.driver.find_element(By.ID,'new-dl_dir').clear()
self.enter_text('#new-dl_dir', '${TOPDIR}/down foo')
element = self.wait_until_visible('#hintError-dl_dir', poll=2)
msg = 'downloads directory path characters invalid but treated as valid'
self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
# downloads dir path starts with /
self.driver.find_element(By.ID,'new-dl_dir').clear()
self.enter_text('#new-dl_dir', '/bar/foo')
hidden_element = self.driver.find_element(By.ID,'hintError-dl_dir')
self.assertEqual(hidden_element.is_displayed(), False,
'downloads directory path valid but treated as invalid')
# downloads dir path starts with ${...}
self.driver.find_element(By.ID,'new-dl_dir').clear()
self.enter_text('#new-dl_dir', '${TOPDIR}/down')
hidden_element = self.driver.find_element(By.ID,'hintError-dl_dir')
self.assertEqual(hidden_element.is_displayed(), False,
'downloads directory path valid but treated as invalid')
def test_set_sstate_dir(self):
"""
Validate the allowed and disallowed types in the directory field for
SSTATE_DIR
"""
self._navigate_bbv_page()
try:
btn_chg_sstate_dir = self.wait_until_visible(
'#change-sstate_dir-icon',
poll=2
)
self.click('#change-sstate_dir-icon')
except TimeoutException:
# If sstate_dir is not displayed, test is skipped
btn_chg_sstate_dir = None
if btn_chg_sstate_dir: # Skip continuation if sstate_dir is not displayed
# path doesn't start with / or ${...}
input_field = self.wait_until_visible('#new-sstate_dir', poll=2)
input_field.clear()
self.enter_text('#new-sstate_dir', 'home/foo')
element = self.wait_until_visible('#hintError-initialChar-sstate_dir', poll=2)
msg = 'sstate directory path starts with invalid character but ' \
'treated as valid'
self.assertTrue((self.INVALID_PATH_START_TEXT in element.text), msg)
# path has a space
self.driver.find_element(By.ID, 'new-sstate_dir').clear()
self.enter_text('#new-sstate_dir', '/foo/bar a')
element = self.wait_until_visible('#hintError-sstate_dir', poll=2)
msg = 'sstate directory path characters invalid but treated as valid'
self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
# path starts with ${...} but has a space
self.driver.find_element(By.ID,'new-sstate_dir').clear()
self.enter_text('#new-sstate_dir', '${TOPDIR}/down foo')
element = self.wait_until_visible('#hintError-sstate_dir', poll=2)
msg = 'sstate directory path characters invalid but treated as valid'
self.assertTrue((self.INVALID_PATH_CHAR_TEXT in element.text), msg)
# path starts with /
self.driver.find_element(By.ID,'new-sstate_dir').clear()
self.enter_text('#new-sstate_dir', '/bar/foo')
hidden_element = self.driver.find_element(By.ID, 'hintError-sstate_dir')
self.assertEqual(hidden_element.is_displayed(), False,
'sstate directory path valid but treated as invalid')
# paths starts with ${...}
self.driver.find_element(By.ID, 'new-sstate_dir').clear()
self.enter_text('#new-sstate_dir', '${TOPDIR}/down')
hidden_element = self.driver.find_element(By.ID, 'hintError-sstate_dir')
self.assertEqual(hidden_element.is_displayed(), False,
'sstate directory path valid but treated as invalid')
def _change_bbv_value(self, **kwargs):
var_name, field, btn_id, input_id, value, save_btn, *_ = kwargs.values()
""" Change bitbake variable value """
self._navigate_bbv_page()
self.wait_until_visible(f'#{btn_id}', poll=2)
if kwargs.get('new_variable'):
self.find(f"#{btn_id}").clear()
self.enter_text(f"#{btn_id}", f"{var_name}")
else:
self.click(f'#{btn_id}')
self.wait_until_visible(f'#{input_id}', poll=2)
if kwargs.get('is_select'):
select = Select(self.find(f'#{input_id}'))
select.select_by_visible_text(value)
else:
self.find(f"#{input_id}").clear()
self.enter_text(f'#{input_id}', f'{value}')
self.click(f'#{save_btn}')
value_displayed = str(self.wait_until_visible(f'#{field}').text).lower()
msg = f'{var_name} variable not changed'
self.assertTrue(str(value).lower() in value_displayed, msg)
def test_change_distro_var(self):
""" Test changing distro variable """
self._change_bbv_value(
var_name='DISTRO',
field='distro',
btn_id='change-distro-icon',
input_id='new-distro',
value='poky-changed',
save_btn="apply-change-distro",
)
def test_set_image_install_append_var(self):
""" Test setting IMAGE_INSTALL:append variable """
self._change_bbv_value(
var_name='IMAGE_INSTALL:append',
field='image_install',
btn_id='change-image_install-icon',
input_id='new-image_install',
value='bash, apt, busybox',
save_btn="apply-change-image_install",
)
def test_set_package_classes_var(self):
""" Test setting PACKAGE_CLASSES variable """
self._change_bbv_value(
var_name='PACKAGE_CLASSES',
field='package_classes',
btn_id='change-package_classes-icon',
input_id='package_classes-select',
value='package_deb',
save_btn="apply-change-package_classes",
is_select=True,
)
def test_create_new_bbv(self):
""" Test creating new bitbake variable """
self._change_bbv_value(
var_name='New_Custom_Variable',
field='configvar-list',
btn_id='variable',
input_id='value',
value='new variable value',
save_btn="add-configvar-button",
new_variable=True
)