diff options
| -rw-r--r-- | bitbake/lib/toaster/tests/functional/test_project_page_tab_config.py | 213 |
1 files changed, 90 insertions, 123 deletions
diff --git a/bitbake/lib/toaster/tests/functional/test_project_page_tab_config.py b/bitbake/lib/toaster/tests/functional/test_project_page_tab_config.py index 5da9706b29..daf00d8f1d 100644 --- a/bitbake/lib/toaster/tests/functional/test_project_page_tab_config.py +++ b/bitbake/lib/toaster/tests/functional/test_project_page_tab_config.py | |||
| @@ -7,7 +7,6 @@ | |||
| 7 | # | 7 | # |
| 8 | 8 | ||
| 9 | import string | 9 | import string |
| 10 | import random | ||
| 11 | import pytest | 10 | import pytest |
| 12 | from django.urls import reverse | 11 | from django.urls import reverse |
| 13 | from selenium.webdriver import Keys | 12 | from selenium.webdriver import Keys |
| @@ -19,60 +18,16 @@ from selenium.webdriver.common.by import By | |||
| 19 | 18 | ||
| 20 | from .utils import get_projectId_from_url, wait_until_build, wait_until_build_cancelled | 19 | from .utils import get_projectId_from_url, wait_until_build, wait_until_build_cancelled |
| 21 | 20 | ||
| 22 | 21 | class TestProjectConfigTabBase(SeleniumFunctionalTestCase): | |
| 23 | @pytest.mark.django_db | ||
| 24 | @pytest.mark.order("last") | ||
| 25 | class TestProjectConfigTab(SeleniumFunctionalTestCase): | ||
| 26 | PROJECT_NAME = 'TestProjectConfigTab' | 22 | PROJECT_NAME = 'TestProjectConfigTab' |
| 27 | project_id = None | 23 | project_id = None |
| 28 | 24 | ||
| 29 | def _create_project(self, project_name, **kwargs): | ||
| 30 | """ Create/Test new project using: | ||
| 31 | - Project Name: Any string | ||
| 32 | - Release: Any string | ||
| 33 | - Merge Toaster settings: True or False | ||
| 34 | """ | ||
| 35 | release = kwargs.get('release', '3') | ||
| 36 | self.get(reverse('newproject')) | ||
| 37 | self.wait_until_visible('#new-project-name') | ||
| 38 | self.find("#new-project-name").send_keys(project_name) | ||
| 39 | select = Select(self.find("#projectversion")) | ||
| 40 | select.select_by_value(release) | ||
| 41 | |||
| 42 | # check merge toaster settings | ||
| 43 | checkbox = self.find('.checkbox-mergeattr') | ||
| 44 | if not checkbox.is_selected(): | ||
| 45 | checkbox.click() | ||
| 46 | |||
| 47 | if self.PROJECT_NAME != 'TestProjectConfigTab': | ||
| 48 | # Reset project name if it's not the default one | ||
| 49 | self.PROJECT_NAME = 'TestProjectConfigTab' | ||
| 50 | |||
| 51 | self.find("#create-project-button").click() | ||
| 52 | |||
| 53 | try: | ||
| 54 | self.wait_until_visible('#hint-error-project-name', poll=3) | ||
| 55 | url = reverse('project', args=(TestProjectConfigTab.project_id, )) | ||
| 56 | self.get(url) | ||
| 57 | self.wait_until_visible('#config-nav', poll=3) | ||
| 58 | except TimeoutException: | ||
| 59 | self.wait_until_visible('#config-nav', poll=3) | ||
| 60 | |||
| 61 | def _random_string(self, length): | ||
| 62 | return ''.join( | ||
| 63 | random.choice(string.ascii_letters) for _ in range(length) | ||
| 64 | ) | ||
| 65 | |||
| 66 | def _navigate_to_project_page(self): | 25 | def _navigate_to_project_page(self): |
| 67 | # Navigate to project page | 26 | # Navigate to project page |
| 68 | if TestProjectConfigTab.project_id is None: | 27 | if TestProjectConfigTabBase.project_id is None: |
| 69 | self._create_project(project_name=self._random_string(10)) | 28 | TestProjectConfigTabBase.project_id = self.create_new_project(self.PROJECT_NAME, '3', None, True) |
| 70 | current_url = self.driver.current_url | 29 | url = reverse('project', args=(TestProjectConfigTabBase.project_id,)) |
| 71 | TestProjectConfigTab.project_id = get_projectId_from_url( | 30 | self.get(url) |
| 72 | current_url) | ||
| 73 | else: | ||
| 74 | url = reverse('project', args=(TestProjectConfigTab.project_id,)) | ||
| 75 | self.get(url) | ||
| 76 | self.wait_until_visible('#config-nav') | 31 | self.wait_until_visible('#config-nav') |
| 77 | 32 | ||
| 78 | def _create_builds(self): | 33 | def _create_builds(self): |
| @@ -114,6 +69,8 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 114 | config_nav = self.find('#config-nav') | 69 | config_nav = self.find('#config-nav') |
| 115 | return config_nav.find_elements(By.TAG_NAME, 'li')[index] | 70 | return config_nav.find_elements(By.TAG_NAME, 'li')[index] |
| 116 | 71 | ||
| 72 | class TestProjectConfigTab(TestProjectConfigTabBase): | ||
| 73 | |||
| 117 | def test_project_config_nav(self): | 74 | def test_project_config_nav(self): |
| 118 | """ Test project config tab navigation: | 75 | """ Test project config tab navigation: |
| 119 | - Check if the menu is displayed and contains the right elements: | 76 | - Check if the menu is displayed and contains the right elements: |
| @@ -160,26 +117,26 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 160 | conf_nav_list = [ | 117 | conf_nav_list = [ |
| 161 | # config | 118 | # config |
| 162 | [0, 'Configuration', | 119 | [0, 'Configuration', |
| 163 | f"/toastergui/project/{TestProjectConfigTab.project_id}"], | 120 | f"/toastergui/project/{TestProjectConfigTabBase.project_id}"], |
| 164 | # custom images | 121 | # custom images |
| 165 | [2, 'Custom images', | 122 | [2, 'Custom images', |
| 166 | f"/toastergui/project/{TestProjectConfigTab.project_id}/customimages"], | 123 | f"/toastergui/project/{TestProjectConfigTabBase.project_id}/customimages"], |
| 167 | # image recipes | 124 | # image recipes |
| 168 | [3, 'Image recipes', | 125 | [3, 'Image recipes', |
| 169 | f"/toastergui/project/{TestProjectConfigTab.project_id}/images"], | 126 | f"/toastergui/project/{TestProjectConfigTabBase.project_id}/images"], |
| 170 | # software recipes | 127 | # software recipes |
| 171 | [4, 'Software recipes', | 128 | [4, 'Software recipes', |
| 172 | f"/toastergui/project/{TestProjectConfigTab.project_id}/softwarerecipes"], | 129 | f"/toastergui/project/{TestProjectConfigTabBase.project_id}/softwarerecipes"], |
| 173 | # machines | 130 | # machines |
| 174 | [5, 'Machines', | 131 | [5, 'Machines', |
| 175 | f"/toastergui/project/{TestProjectConfigTab.project_id}/machines"], | 132 | f"/toastergui/project/{TestProjectConfigTabBase.project_id}/machines"], |
| 176 | # layers | 133 | # layers |
| 177 | [6, 'Layers', | 134 | [6, 'Layers', |
| 178 | f"/toastergui/project/{TestProjectConfigTab.project_id}/layers"], | 135 | f"/toastergui/project/{TestProjectConfigTabBase.project_id}/layers"], |
| 179 | # distro | 136 | # distro |
| 180 | [7, 'Distros', | 137 | [7, 'Distros', |
| 181 | f"/toastergui/project/{TestProjectConfigTab.project_id}/distros"], | 138 | f"/toastergui/project/{TestProjectConfigTabBase.project_id}/distros"], |
| 182 | # [9, 'BitBake variables', f"/toastergui/project/{TestProjectConfigTab.project_id}/configuration"], # bitbake variables | 139 | # [9, 'BitBake variables', f"/toastergui/project/{TestProjectConfigTabBase.project_id}/configuration"], # bitbake variables |
| 183 | ] | 140 | ] |
| 184 | for index, item_name, url in conf_nav_list: | 141 | for index, item_name, url in conf_nav_list: |
| 185 | item = _get_config_nav_item(index) | 142 | item = _get_config_nav_item(index) |
| @@ -299,9 +256,11 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 299 | - meta-poky | 256 | - meta-poky |
| 300 | - meta-yocto-bsp | 257 | - meta-yocto-bsp |
| 301 | """ | 258 | """ |
| 302 | # Create a new project for this test | 259 | project_id = self.create_new_project(self.PROJECT_NAME + "-ST", '3', None, True) |
| 303 | project_name = self._random_string(10) | 260 | url = reverse('project', args=(project_id,)) |
| 304 | self._create_project(project_name=project_name) | 261 | self.get(url) |
| 262 | self.wait_until_visible('#config-nav') | ||
| 263 | |||
| 305 | # check if the menu is displayed | 264 | # check if the menu is displayed |
| 306 | self.wait_until_visible('#project-page') | 265 | self.wait_until_visible('#project-page') |
| 307 | block_l = self.driver.find_element( | 266 | block_l = self.driver.find_element( |
| @@ -374,61 +333,6 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 374 | layers_list_items = layers_list.find_elements(By.TAG_NAME, 'li') | 333 | layers_list_items = layers_list.find_elements(By.TAG_NAME, 'li') |
| 375 | self.assertEqual(len(layers_list_items), 4) | 334 | self.assertEqual(len(layers_list_items), 4) |
| 376 | 335 | ||
| 377 | def test_most_build_recipes(self): | ||
| 378 | """ Test most build recipes block contains""" | ||
| 379 | def rebuild_from_most_build_recipes(recipe_list_items): | ||
| 380 | checkbox = recipe_list_items[0].find_element(By.TAG_NAME, 'input') | ||
| 381 | checkbox.click() | ||
| 382 | build_btn = self.find('#freq-build-btn') | ||
| 383 | build_btn.click() | ||
| 384 | self.wait_until_visible('#latest-builds') | ||
| 385 | wait_until_build(self, 'queued cloning starting parsing failed') | ||
| 386 | lastest_builds = self.driver.find_elements( | ||
| 387 | By.XPATH, | ||
| 388 | '//div[@id="latest-builds"]/div' | ||
| 389 | ) | ||
| 390 | self.assertTrue(len(lastest_builds) >= 2) | ||
| 391 | last_build = lastest_builds[0] | ||
| 392 | try: | ||
| 393 | cancel_button = last_build.find_element( | ||
| 394 | By.XPATH, | ||
| 395 | '//span[@class="cancel-build-btn pull-right alert-link"]', | ||
| 396 | ) | ||
| 397 | cancel_button.click() | ||
| 398 | except NoSuchElementException: | ||
| 399 | # Skip if the build is already cancelled | ||
| 400 | pass | ||
| 401 | wait_until_build_cancelled(self) | ||
| 402 | # Create a new project for remaining asserts | ||
| 403 | project_name = self._random_string(10) | ||
| 404 | self._create_project(project_name=project_name, release='2') | ||
| 405 | current_url = self.driver.current_url | ||
| 406 | TestProjectConfigTab.project_id = get_projectId_from_url(current_url) | ||
| 407 | url = current_url.split('?')[0] | ||
| 408 | |||
| 409 | # Create a new builds | ||
| 410 | self._create_builds() | ||
| 411 | |||
| 412 | # back to project page | ||
| 413 | self.driver.get(url) | ||
| 414 | |||
| 415 | self.wait_until_visible('#project-page', poll=3) | ||
| 416 | |||
| 417 | # Most built recipes | ||
| 418 | most_built_recipes = self.driver.find_element( | ||
| 419 | By.XPATH, '//*[@id="project-page"]/div[1]/div[3]') | ||
| 420 | title = most_built_recipes.find_element(By.TAG_NAME, 'h3') | ||
| 421 | self.assertIn("Most built recipes", title.text) | ||
| 422 | # check can select a recipe and build it | ||
| 423 | self.wait_until_visible('#freq-build-list', poll=3) | ||
| 424 | recipe_list = self.find('#freq-build-list') | ||
| 425 | recipe_list_items = recipe_list.find_elements(By.TAG_NAME, 'li') | ||
| 426 | self.assertTrue( | ||
| 427 | len(recipe_list_items) > 0, | ||
| 428 | msg="No recipes found in the most built recipes list", | ||
| 429 | ) | ||
| 430 | rebuild_from_most_build_recipes(recipe_list_items) | ||
| 431 | TestProjectConfigTab.project_id = None # reset project id | ||
| 432 | 336 | ||
| 433 | def test_project_page_tab_importlayer(self): | 337 | def test_project_page_tab_importlayer(self): |
| 434 | """ Test project page tab import layer """ | 338 | """ Test project page tab import layer """ |
| @@ -472,10 +376,11 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 472 | 376 | ||
| 473 | def test_project_page_custom_image_no_image(self): | 377 | def test_project_page_custom_image_no_image(self): |
| 474 | """ Test project page tab "New custom image" when no custom image """ | 378 | """ Test project page tab "New custom image" when no custom image """ |
| 475 | project_name = self._random_string(10) | 379 | project_id = self.create_new_project(self.PROJECT_NAME + "-CustomImage", '3', None, True) |
| 476 | self._create_project(project_name=project_name) | 380 | url = reverse('project', args=(project_id,)) |
| 477 | current_url = self.driver.current_url | 381 | self.get(url) |
| 478 | TestProjectConfigTab.project_id = get_projectId_from_url(current_url) | 382 | self.wait_until_visible('#config-nav') |
| 383 | |||
| 479 | # navigate to "Custom image" tab | 384 | # navigate to "Custom image" tab |
| 480 | custom_image_section = self._get_config_nav_item(2) | 385 | custom_image_section = self._get_config_nav_item(2) |
| 481 | custom_image_section.click() | 386 | custom_image_section.click() |
| @@ -490,9 +395,9 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 490 | div_empty_msg = self.find('#empty-state-customimagestable') | 395 | div_empty_msg = self.find('#empty-state-customimagestable') |
| 491 | link_create_custom_image = div_empty_msg.find_element( | 396 | link_create_custom_image = div_empty_msg.find_element( |
| 492 | By.TAG_NAME, 'a') | 397 | By.TAG_NAME, 'a') |
| 493 | self.assertTrue(TestProjectConfigTab.project_id is not None) | 398 | self.assertTrue(TestProjectConfigTabBase.project_id is not None) |
| 494 | self.assertIn( | 399 | self.assertIn( |
| 495 | f"/toastergui/project/{TestProjectConfigTab.project_id}/newcustomimage", str( | 400 | f"/toastergui/project/{project_id}/newcustomimage", str( |
| 496 | link_create_custom_image.get_attribute('href') | 401 | link_create_custom_image.get_attribute('href') |
| 497 | ) | 402 | ) |
| 498 | ) | 403 | ) |
| @@ -501,7 +406,6 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 501 | link_create_custom_image.text | 406 | link_create_custom_image.text |
| 502 | ) | 407 | ) |
| 503 | ) | 408 | ) |
| 504 | TestProjectConfigTab.project_id = None # reset project id | ||
| 505 | 409 | ||
| 506 | def test_project_page_image_recipe(self): | 410 | def test_project_page_image_recipe(self): |
| 507 | """ Test project page section images | 411 | """ Test project page section images |
| @@ -526,3 +430,66 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 526 | self.wait_until_visible('#imagerecipestable tbody tr') | 430 | self.wait_until_visible('#imagerecipestable tbody tr') |
| 527 | rows = self.find_all('#imagerecipestable tbody tr') | 431 | rows = self.find_all('#imagerecipestable tbody tr') |
| 528 | self.assertTrue(len(rows) > 0) | 432 | self.assertTrue(len(rows) > 0) |
| 433 | |||
| 434 | @pytest.mark.django_db | ||
| 435 | @pytest.mark.order("last") | ||
| 436 | class TestProjectConfigTabDB(TestProjectConfigTabBase): | ||
| 437 | |||
| 438 | def test_most_build_recipes(self): | ||
| 439 | """ Test most build recipes block contains""" | ||
| 440 | def rebuild_from_most_build_recipes(recipe_list_items): | ||
| 441 | checkbox = recipe_list_items[0].find_element(By.TAG_NAME, 'input') | ||
| 442 | checkbox.click() | ||
| 443 | build_btn = self.find('#freq-build-btn') | ||
| 444 | build_btn.click() | ||
| 445 | self.wait_until_visible('#latest-builds') | ||
| 446 | wait_until_build(self, 'queued cloning starting parsing failed') | ||
| 447 | lastest_builds = self.driver.find_elements( | ||
| 448 | By.XPATH, | ||
| 449 | '//div[@id="latest-builds"]/div' | ||
| 450 | ) | ||
| 451 | self.assertTrue(len(lastest_builds) >= 2) | ||
| 452 | last_build = lastest_builds[0] | ||
| 453 | try: | ||
| 454 | cancel_button = last_build.find_element( | ||
| 455 | By.XPATH, | ||
| 456 | '//span[@class="cancel-build-btn pull-right alert-link"]', | ||
| 457 | ) | ||
| 458 | cancel_button.click() | ||
| 459 | except NoSuchElementException: | ||
| 460 | # Skip if the build is already cancelled | ||
| 461 | pass | ||
| 462 | wait_until_build_cancelled(self) | ||
| 463 | |||
| 464 | # Create a new project for remaining asserts | ||
| 465 | project_id = self.create_new_project(self.PROJECT_NAME + "-MostBuilt", '2', None, True) | ||
| 466 | url = reverse('project', args=(project_id,)) | ||
| 467 | self.get(url) | ||
| 468 | self.wait_until_visible('#config-nav') | ||
| 469 | |||
| 470 | current_url = self.driver.current_url | ||
| 471 | url = current_url.split('?')[0] | ||
| 472 | |||
| 473 | # Create a new builds | ||
| 474 | self._create_builds() | ||
| 475 | |||
| 476 | # back to project page | ||
| 477 | self.driver.get(url) | ||
| 478 | |||
| 479 | self.wait_until_visible('#project-page', poll=3) | ||
| 480 | |||
| 481 | # Most built recipes | ||
| 482 | most_built_recipes = self.driver.find_element( | ||
| 483 | By.XPATH, '//*[@id="project-page"]/div[1]/div[3]') | ||
| 484 | title = most_built_recipes.find_element(By.TAG_NAME, 'h3') | ||
| 485 | self.assertIn("Most built recipes", title.text) | ||
| 486 | # check can select a recipe and build it | ||
| 487 | self.wait_until_visible('#freq-build-list', poll=3) | ||
| 488 | recipe_list = self.find('#freq-build-list') | ||
| 489 | recipe_list_items = recipe_list.find_elements(By.TAG_NAME, 'li') | ||
| 490 | self.assertTrue( | ||
| 491 | len(recipe_list_items) > 0, | ||
| 492 | msg="No recipes found in the most built recipes list", | ||
| 493 | ) | ||
| 494 | rebuild_from_most_build_recipes(recipe_list_items) | ||
| 495 | |||
