summaryrefslogtreecommitdiffstats
path: root/bitbake/lib
diff options
context:
space:
mode:
authorAlassane Yattara <alassane.yattara@savoirfairelinux.com>2023-12-08 02:53:19 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2023-12-08 17:17:42 +0000
commit23d3e2c718d6eab5151a425e835554bd4fe20a8b (patch)
tree804d0fa917bf4e03c93d8d3b96ed3a64b5ddc4c0 /bitbake/lib
parentd5a6e3b546e7d6691150a5906e531e3b3d6919ee (diff)
downloadpoky-23d3e2c718d6eab5151a425e835554bd4fe20a8b.tar.gz
bitbake: toaster/tests: Bug fixes, functional tests dependent on each other
refactor test_create_project and test_project_page to remove their dependencies (Bitbake rev: 54f7c0bb6ff435c4936c3422532aa071bd5b66e8) Signed-off-by: Alassane Yattara <alassane.yattara@savoirfairelinux.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib')
-rw-r--r--bitbake/lib/toaster/tests/functional/test_create_new_project.py1
-rw-r--r--bitbake/lib/toaster/tests/functional/test_project_page.py164
2 files changed, 79 insertions, 86 deletions
diff --git a/bitbake/lib/toaster/tests/functional/test_create_new_project.py b/bitbake/lib/toaster/tests/functional/test_create_new_project.py
index dc7d1fc20b..bbda0cf4e6 100644
--- a/bitbake/lib/toaster/tests/functional/test_create_new_project.py
+++ b/bitbake/lib/toaster/tests/functional/test_create_new_project.py
@@ -16,6 +16,7 @@ from selenium.webdriver.common.by import By
16 16
17 17
18@pytest.mark.django_db 18@pytest.mark.django_db
19@pytest.mark.order("last")
19class TestCreateNewProject(SeleniumFunctionalTestCase): 20class TestCreateNewProject(SeleniumFunctionalTestCase):
20 21
21 def _create_test_new_project( 22 def _create_test_new_project(
diff --git a/bitbake/lib/toaster/tests/functional/test_project_page.py b/bitbake/lib/toaster/tests/functional/test_project_page.py
index 03f64f8fef..077badb0c2 100644
--- a/bitbake/lib/toaster/tests/functional/test_project_page.py
+++ b/bitbake/lib/toaster/tests/functional/test_project_page.py
@@ -6,88 +6,89 @@
6# SPDX-License-Identifier: GPL-2.0-only 6# SPDX-License-Identifier: GPL-2.0-only
7# 7#
8 8
9import os
9import random 10import random
10import string 11import string
12from unittest import skip
11import pytest 13import pytest
12from time import sleep
13from django.urls import reverse 14from django.urls import reverse
14from django.utils import timezone 15from django.utils import timezone
15from selenium.webdriver.common.keys import Keys 16from selenium.webdriver.common.keys import Keys
16from selenium.webdriver.support.select import Select 17from selenium.webdriver.support.select import Select
17from selenium.common.exceptions import NoSuchElementException, TimeoutException 18from selenium.common.exceptions import TimeoutException
18from tests.functional.functional_helpers import SeleniumFunctionalTestCase 19from tests.functional.functional_helpers import SeleniumFunctionalTestCase
19from orm.models import Build, Project, Target 20from orm.models import Build, Project, Target
20from selenium.webdriver.common.by import By 21from selenium.webdriver.common.by import By
21 22
23from .utils import get_projectId_from_url, wait_until_build, wait_until_build_cancelled
24
22 25
23@pytest.mark.django_db 26@pytest.mark.django_db
27@pytest.mark.order("last")
24class TestProjectPage(SeleniumFunctionalTestCase): 28class TestProjectPage(SeleniumFunctionalTestCase):
29 project_id = None
30 PROJECT_NAME = 'TestProjectPage'
25 31
26 def setUp(self): 32 def _create_project(self, project_name):
27 super().setUp()
28 release = '3'
29 project_name = 'project_' + self.generate_random_string()
30 self._create_test_new_project(
31 project_name,
32 release,
33 False,
34 )
35
36 def generate_random_string(self, length=10):
37 characters = string.ascii_letters + string.digits # alphabetic and numerical characters
38 random_string = ''.join(random.choice(characters) for _ in range(length))
39 return random_string
40
41 def _create_test_new_project(
42 self,
43 project_name,
44 release,
45 merge_toaster_settings,
46 ):
47 """ Create/Test new project using: 33 """ Create/Test new project using:
48 - Project Name: Any string 34 - Project Name: Any string
49 - Release: Any string 35 - Release: Any string
50 - Merge Toaster settings: True or False 36 - Merge Toaster settings: True or False
51 """ 37 """
52 self.get(reverse('newproject')) 38 self.get(reverse('newproject'))
53 self.driver.find_element(By.ID, 39 self.wait_until_visible('#new-project-name')
54 "new-project-name").send_keys(project_name) 40 self.find("#new-project-name").send_keys(project_name)
55 41 select = Select(self.find("#projectversion"))
56 select = Select(self.find('#projectversion')) 42 select.select_by_value('3')
57 select.select_by_value(release)
58 43
59 # check merge toaster settings 44 # check merge toaster settings
60 checkbox = self.find('.checkbox-mergeattr') 45 checkbox = self.find('.checkbox-mergeattr')
61 if merge_toaster_settings: 46 if not checkbox.is_selected():
62 if not checkbox.is_selected(): 47 checkbox.click()
63 checkbox.click() 48
49 if self.PROJECT_NAME != 'TestProjectPage':
50 # Reset project name if it's not the default one
51 self.PROJECT_NAME = 'TestProjectPage'
52
53 self.find("#create-project-button").click()
54
55 try:
56 self.wait_until_visible('#hint-error-project-name')
57 url = reverse('project', args=(TestProjectPage.project_id, ))
58 self.get(url)
59 self.wait_until_visible('#config-nav', poll=3)
60 except TimeoutException:
61 self.wait_until_visible('#config-nav', poll=3)
62
63 def _random_string(self, length):
64 return ''.join(
65 random.choice(string.ascii_letters) for _ in range(length)
66 )
67
68 def _navigate_to_project_page(self):
69 # Navigate to project page
70 if TestProjectPage.project_id is None:
71 self._create_project(project_name=self._random_string(10))
72 current_url = self.driver.current_url
73 TestProjectPage.project_id = get_projectId_from_url(current_url)
64 else: 74 else:
65 if checkbox.is_selected(): 75 url = reverse('project', args=(TestProjectPage.project_id,))
66 checkbox.click() 76 self.get(url)
67 77 self.wait_until_visible('#config-nav')
68 self.driver.find_element(By.ID, "create-project-button").click()
69 78
70 def _get_create_builds(self, **kwargs): 79 def _get_create_builds(self, **kwargs):
71 """ Create a build and return the build object """ 80 """ Create a build and return the build object """
72 # parameters for builds to associate with the projects 81 # parameters for builds to associate with the projects
73 now = timezone.now() 82 now = timezone.now()
74 release = '3'
75 project_name = 'projectmaster'
76 self._create_test_new_project(
77 project_name+"2",
78 release,
79 False,
80 )
81
82 self.project1_build_success = { 83 self.project1_build_success = {
83 'project': Project.objects.get(id=1), 84 'project': Project.objects.get(id=TestProjectPage.project_id),
84 'started_on': now, 85 'started_on': now,
85 'completed_on': now, 86 'completed_on': now,
86 'outcome': Build.SUCCEEDED 87 'outcome': Build.SUCCEEDED
87 } 88 }
88 89
89 self.project1_build_failure = { 90 self.project1_build_failure = {
90 'project': Project.objects.get(id=1), 91 'project': Project.objects.get(id=TestProjectPage.project_id),
91 'started_on': now, 92 'started_on': now,
92 'completed_on': now, 93 'completed_on': now,
93 'outcome': Build.FAILED 94 'outcome': Build.FAILED
@@ -180,9 +181,7 @@ class TestProjectPage(SeleniumFunctionalTestCase):
180 181
181 def _navigate_to_config_nav(self, nav_id, nav_index): 182 def _navigate_to_config_nav(self, nav_id, nav_index):
182 # navigate to the project page 183 # navigate to the project page
183 url = reverse("project", args=(1,)) 184 self._navigate_to_project_page()
184 self.get(url)
185 self.wait_until_visible('#config-nav')
186 # click on "Software recipe" tab 185 # click on "Software recipe" tab
187 soft_recipe = self._get_config_nav_item(nav_index) 186 soft_recipe = self._get_config_nav_item(nav_index)
188 soft_recipe.click() 187 soft_recipe.click()
@@ -211,29 +210,6 @@ class TestProjectPage(SeleniumFunctionalTestCase):
211 if row_to_show not in to_skip: 210 if row_to_show not in to_skip:
212 test_show_rows(row_to_show, show_row_link) 211 test_show_rows(row_to_show, show_row_link)
213 212
214 def _wait_until_build(self, state):
215 timeout = 10
216 start_time = 0
217 while True:
218 if start_time > timeout:
219 raise TimeoutException(
220 f'Build did not reach {state} state within {timeout} seconds'
221 )
222 try:
223 last_build_state = self.driver.find_element(
224 By.XPATH,
225 '//*[@id="latest-builds"]/div[1]//div[@class="build-state"]',
226 )
227 build_state = last_build_state.get_attribute(
228 'data-build-state')
229 state_text = state.lower().split()
230 if any(x in str(build_state).lower() for x in state_text):
231 break
232 except NoSuchElementException:
233 continue
234 start_time += 1
235 sleep(1) # take a breath and try again
236
237 def _mixin_test_table_search_input(self, **kwargs): 213 def _mixin_test_table_search_input(self, **kwargs):
238 input_selector, input_text, searchBtn_selector, table_selector, *_ = kwargs.values() 214 input_selector, input_text, searchBtn_selector, table_selector, *_ = kwargs.values()
239 # Test search input 215 # Test search input
@@ -245,11 +221,19 @@ class TestProjectPage(SeleniumFunctionalTestCase):
245 rows = self.find_all(f'#{table_selector} tbody tr') 221 rows = self.find_all(f'#{table_selector} tbody tr')
246 self.assertTrue(len(rows) > 0) 222 self.assertTrue(len(rows) > 0)
247 223
224 def test_create_project(self):
225 """ Create/Test new project using:
226 - Project Name: Any string
227 - Release: Any string
228 - Merge Toaster settings: True or False
229 """
230 self._create_project(project_name=self.PROJECT_NAME)
231
248 def test_image_recipe_editColumn(self): 232 def test_image_recipe_editColumn(self):
249 """ Test the edit column feature in image recipe table on project page """ 233 """ Test the edit column feature in image recipe table on project page """
250 self._get_create_builds(success=10, failure=10) 234 self._get_create_builds(success=10, failure=10)
251 235
252 url = reverse('projectimagerecipes', args=(1,)) 236 url = reverse('projectimagerecipes', args=(TestProjectPage.project_id,))
253 self.get(url) 237 self.get(url)
254 self.wait_until_present('#imagerecipestable tbody tr') 238 self.wait_until_present('#imagerecipestable tbody tr')
255 239
@@ -276,8 +260,7 @@ class TestProjectPage(SeleniumFunctionalTestCase):
276 - AT RIGHT -> button "New project", displayed, clickable 260 - AT RIGHT -> button "New project", displayed, clickable
277 """ 261 """
278 # navigate to the project page 262 # navigate to the project page
279 url = reverse("project", args=(1,)) 263 self._navigate_to_project_page()
280 self.get(url)
281 264
282 # check page header 265 # check page header
283 # AT LEFT -> Logo of Yocto project 266 # AT LEFT -> Logo of Yocto project
@@ -360,8 +343,7 @@ class TestProjectPage(SeleniumFunctionalTestCase):
360 - Check project name is changed 343 - Check project name is changed
361 """ 344 """
362 # navigate to the project page 345 # navigate to the project page
363 url = reverse("project", args=(1,)) 346 self._navigate_to_project_page()
364 self.get(url)
365 347
366 # click on "Edit" icon button 348 # click on "Edit" icon button
367 self.wait_until_visible('#project-name-container') 349 self.wait_until_visible('#project-name-container')
@@ -388,8 +370,7 @@ class TestProjectPage(SeleniumFunctionalTestCase):
388 Check search box used to build recipes 370 Check search box used to build recipes
389 """ 371 """
390 # navigate to the project page 372 # navigate to the project page
391 url = reverse("project", args=(1,)) 373 self._navigate_to_project_page()
392 self.get(url)
393 374
394 # check "configuration" tab 375 # check "configuration" tab
395 self.wait_until_visible('#topbar-configuration-tab') 376 self.wait_until_visible('#topbar-configuration-tab')
@@ -397,7 +378,7 @@ class TestProjectPage(SeleniumFunctionalTestCase):
397 self.assertTrue(config_tab.get_attribute('class') == 'active') 378 self.assertTrue(config_tab.get_attribute('class') == 'active')
398 self.assertTrue('Configuration' in str(config_tab.text)) 379 self.assertTrue('Configuration' in str(config_tab.text))
399 self.assertTrue( 380 self.assertTrue(
400 f"/toastergui/project/1" in str(self.driver.current_url) 381 f"/toastergui/project/{TestProjectPage.project_id}" in str(self.driver.current_url)
401 ) 382 )
402 383
403 def get_tabs(): 384 def get_tabs():
@@ -420,7 +401,7 @@ class TestProjectPage(SeleniumFunctionalTestCase):
420 check_tab_link( 401 check_tab_link(
421 1, 402 1,
422 'Builds', 403 'Builds',
423 f"/toastergui/project/1/builds" 404 f"/toastergui/project/{TestProjectPage.project_id}/builds"
424 ) 405 )
425 406
426 # check "Import layers" tab 407 # check "Import layers" tab
@@ -429,7 +410,7 @@ class TestProjectPage(SeleniumFunctionalTestCase):
429 check_tab_link( 410 check_tab_link(
430 2, 411 2,
431 'Import layer', 412 'Import layer',
432 f"/toastergui/project/1/importlayer" 413 f"/toastergui/project/{TestProjectPage.project_id}/importlayer"
433 ) 414 )
434 415
435 # check "New custom image" tab 416 # check "New custom image" tab
@@ -438,7 +419,7 @@ class TestProjectPage(SeleniumFunctionalTestCase):
438 check_tab_link( 419 check_tab_link(
439 3, 420 3,
440 'New custom image', 421 'New custom image',
441 f"/toastergui/project/1/newcustomimage" 422 f"/toastergui/project/{TestProjectPage.project_id}/newcustomimage"
442 ) 423 )
443 424
444 # check search box can be use to build recipes 425 # check search box can be use to build recipes
@@ -480,12 +461,20 @@ class TestProjectPage(SeleniumFunctionalTestCase):
480 '//td[@class="add-del-layers"]//a[1]' 461 '//td[@class="add-del-layers"]//a[1]'
481 ) 462 )
482 build_btn.click() 463 build_btn.click()
483 self._wait_until_build('parsing starting cloning queued') 464 build_state = wait_until_build(self, 'parsing starting cloning queued')
484 lastest_builds = self.driver.find_elements( 465 lastest_builds = self.driver.find_elements(
485 By.XPATH, 466 By.XPATH,
486 '//div[@id="latest-builds"]/div' 467 '//div[@id="latest-builds"]/div'
487 ) 468 )
488 self.assertTrue(len(lastest_builds) > 0) 469 self.assertTrue(len(lastest_builds) > 0)
470 last_build = lastest_builds[0]
471 cancel_button = last_build.find_element(
472 By.XPATH,
473 '//span[@class="cancel-build-btn pull-right alert-link"]',
474 )
475 cancel_button.click()
476 if 'starting' not in build_state: # change build state when cancelled in starting state
477 wait_until_build_cancelled(self)
489 478
490 # check software recipe table feature(show/hide column, pagination) 479 # check software recipe table feature(show/hide column, pagination)
491 self._navigate_to_config_nav('softwarerecipestable', 4) 480 self._navigate_to_config_nav('softwarerecipestable', 4)
@@ -547,6 +536,7 @@ class TestProjectPage(SeleniumFunctionalTestCase):
547 searchBtn_selector='search-submit-machinestable', 536 searchBtn_selector='search-submit-machinestable',
548 table_selector='machinestable' 537 table_selector='machinestable'
549 ) 538 )
539 self.wait_until_visible('#machinestable tbody tr', poll=3)
550 rows = self.find_all('#machinestable tbody tr') 540 rows = self.find_all('#machinestable tbody tr')
551 machine_to_add = rows[0] 541 machine_to_add = rows[0]
552 add_btn = machine_to_add.find_element(By.XPATH, '//td[@class="add-del-layers"]') 542 add_btn = machine_to_add.find_element(By.XPATH, '//td[@class="add-del-layers"]')
@@ -593,6 +583,7 @@ class TestProjectPage(SeleniumFunctionalTestCase):
593 table_selector='layerstable' 583 table_selector='layerstable'
594 ) 584 )
595 # check "Add layer" button works 585 # check "Add layer" button works
586 self.wait_until_visible('#layerstable tbody tr', poll=3)
596 rows = self.find_all('#layerstable tbody tr') 587 rows = self.find_all('#layerstable tbody tr')
597 layer_to_add = rows[0] 588 layer_to_add = rows[0]
598 add_btn = layer_to_add.find_element( 589 add_btn = layer_to_add.find_element(
@@ -601,7 +592,7 @@ class TestProjectPage(SeleniumFunctionalTestCase):
601 ) 592 )
602 add_btn.click() 593 add_btn.click()
603 # check modal is displayed 594 # check modal is displayed
604 self.wait_until_visible('#dependencies-modal', poll=2) 595 self.wait_until_visible('#dependencies-modal', poll=3)
605 list_dependencies = self.find_all('#dependencies-list li') 596 list_dependencies = self.find_all('#dependencies-list li')
606 # click on add-layers button 597 # click on add-layers button
607 add_layers_btn = self.driver.find_element( 598 add_layers_btn = self.driver.find_element(
@@ -615,6 +606,7 @@ class TestProjectPage(SeleniumFunctionalTestCase):
615 f'You have added {len(list_dependencies)+1} layers to your project: {input_text} and its dependencies' in str(change_notification.text) 606 f'You have added {len(list_dependencies)+1} layers to your project: {input_text} and its dependencies' in str(change_notification.text)
616 ) 607 )
617 # check "Remove layer" button works 608 # check "Remove layer" button works
609 self.wait_until_visible('#layerstable tbody tr', poll=3)
618 rows = self.find_all('#layerstable tbody tr') 610 rows = self.find_all('#layerstable tbody tr')
619 layer_to_remove = rows[0] 611 layer_to_remove = rows[0]
620 remove_btn = layer_to_remove.find_element( 612 remove_btn = layer_to_remove.find_element(
@@ -706,7 +698,7 @@ class TestProjectPage(SeleniumFunctionalTestCase):
706 - Check layer summary 698 - Check layer summary
707 - Check layer description 699 - Check layer description
708 """ 700 """
709 url = reverse("layerdetails", args=(1, 8)) 701 url = reverse("layerdetails", args=(TestProjectPage.project_id, 8))
710 self.get(url) 702 self.get(url)
711 self.wait_until_visible('.page-header') 703 self.wait_until_visible('.page-header')
712 # check title is displayed 704 # check title is displayed
@@ -765,7 +757,7 @@ class TestProjectPage(SeleniumFunctionalTestCase):
765 - Check recipe: name, summary, description, Version, Section, 757 - Check recipe: name, summary, description, Version, Section,
766 License, Approx. packages included, Approx. size, Recipe file 758 License, Approx. packages included, Approx. size, Recipe file
767 """ 759 """
768 url = reverse("recipedetails", args=(1, 53428)) 760 url = reverse("recipedetails", args=(TestProjectPage.project_id, 53428))
769 self.get(url) 761 self.get(url)
770 self.wait_until_visible('.page-header') 762 self.wait_until_visible('.page-header')
771 # check title is displayed 763 # check title is displayed