diff options
Diffstat (limited to 'bitbake')
| -rw-r--r-- | bitbake/lib/toaster/tests/functional/test_project_page.py | 2 | ||||
| -rw-r--r-- | bitbake/lib/toaster/tests/functional/test_project_page_tab_config.py | 186 |
2 files changed, 95 insertions, 93 deletions
diff --git a/bitbake/lib/toaster/tests/functional/test_project_page.py b/bitbake/lib/toaster/tests/functional/test_project_page.py index 077badb0c2..82dca442f9 100644 --- a/bitbake/lib/toaster/tests/functional/test_project_page.py +++ b/bitbake/lib/toaster/tests/functional/test_project_page.py | |||
| @@ -461,7 +461,7 @@ class TestProjectPage(SeleniumFunctionalTestCase): | |||
| 461 | '//td[@class="add-del-layers"]//a[1]' | 461 | '//td[@class="add-del-layers"]//a[1]' |
| 462 | ) | 462 | ) |
| 463 | build_btn.click() | 463 | build_btn.click() |
| 464 | build_state = wait_until_build(self, 'parsing starting cloning queued') | 464 | build_state = wait_until_build(self, 'queued cloning starting parsing failed') |
| 465 | lastest_builds = self.driver.find_elements( | 465 | lastest_builds = self.driver.find_elements( |
| 466 | By.XPATH, | 466 | By.XPATH, |
| 467 | '//div[@id="latest-builds"]/div' | 467 | '//div[@id="latest-builds"]/div' |
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 d911ff00d4..4dbf5aeba4 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 | |||
| @@ -12,7 +12,7 @@ import pytest | |||
| 12 | from django.urls import reverse | 12 | from django.urls import reverse |
| 13 | from selenium.webdriver import Keys | 13 | from selenium.webdriver import Keys |
| 14 | from selenium.webdriver.support.select import Select | 14 | from selenium.webdriver.support.select import Select |
| 15 | from selenium.common.exceptions import TimeoutException | 15 | from selenium.common.exceptions import NoSuchElementException, TimeoutException |
| 16 | from orm.models import Project | 16 | from orm.models import Project |
| 17 | from tests.functional.functional_helpers import SeleniumFunctionalTestCase | 17 | from tests.functional.functional_helpers import SeleniumFunctionalTestCase |
| 18 | from selenium.webdriver.common.by import By | 18 | from selenium.webdriver.common.by import By |
| @@ -26,17 +26,18 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 26 | PROJECT_NAME = 'TestProjectConfigTab' | 26 | PROJECT_NAME = 'TestProjectConfigTab' |
| 27 | project_id = None | 27 | project_id = None |
| 28 | 28 | ||
| 29 | def _create_project(self, project_name): | 29 | def _create_project(self, project_name, **kwargs): |
| 30 | """ Create/Test new project using: | 30 | """ Create/Test new project using: |
| 31 | - Project Name: Any string | 31 | - Project Name: Any string |
| 32 | - Release: Any string | 32 | - Release: Any string |
| 33 | - Merge Toaster settings: True or False | 33 | - Merge Toaster settings: True or False |
| 34 | """ | 34 | """ |
| 35 | release = kwargs.get('release', '3') | ||
| 35 | self.get(reverse('newproject')) | 36 | self.get(reverse('newproject')) |
| 36 | self.wait_until_visible('#new-project-name') | 37 | self.wait_until_visible('#new-project-name') |
| 37 | self.find("#new-project-name").send_keys(project_name) | 38 | self.find("#new-project-name").send_keys(project_name) |
| 38 | select = Select(self.find("#projectversion")) | 39 | select = Select(self.find("#projectversion")) |
| 39 | select.select_by_value('3') | 40 | select.select_by_value(release) |
| 40 | 41 | ||
| 41 | # check merge toaster settings | 42 | # check merge toaster settings |
| 42 | checkbox = self.find('.checkbox-mergeattr') | 43 | checkbox = self.find('.checkbox-mergeattr') |
| @@ -50,7 +51,7 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 50 | self.find("#create-project-button").click() | 51 | self.find("#create-project-button").click() |
| 51 | 52 | ||
| 52 | try: | 53 | try: |
| 53 | self.wait_until_visible('#hint-error-project-name') | 54 | self.wait_until_visible('#hint-error-project-name', poll=3) |
| 54 | url = reverse('project', args=(TestProjectConfigTab.project_id, )) | 55 | url = reverse('project', args=(TestProjectConfigTab.project_id, )) |
| 55 | self.get(url) | 56 | self.get(url) |
| 56 | self.wait_until_visible('#config-nav', poll=3) | 57 | self.wait_until_visible('#config-nav', poll=3) |
| @@ -67,7 +68,8 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 67 | if TestProjectConfigTab.project_id is None: | 68 | if TestProjectConfigTab.project_id is None: |
| 68 | self._create_project(project_name=self._random_string(10)) | 69 | self._create_project(project_name=self._random_string(10)) |
| 69 | current_url = self.driver.current_url | 70 | current_url = self.driver.current_url |
| 70 | TestProjectConfigTab.project_id = get_projectId_from_url(current_url) | 71 | TestProjectConfigTab.project_id = get_projectId_from_url( |
| 72 | current_url) | ||
| 71 | else: | 73 | else: |
| 72 | url = reverse('project', args=(TestProjectConfigTab.project_id,)) | 74 | url = reverse('project', args=(TestProjectConfigTab.project_id,)) |
| 73 | self.get(url) | 75 | self.get(url) |
| @@ -76,27 +78,30 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 76 | def _create_builds(self): | 78 | def _create_builds(self): |
| 77 | # check search box can be use to build recipes | 79 | # check search box can be use to build recipes |
| 78 | search_box = self.find('#build-input') | 80 | search_box = self.find('#build-input') |
| 79 | search_box.send_keys('core-image-minimal') | 81 | search_box.send_keys('foo') |
| 80 | self.find('#build-button').click() | 82 | self.find('#build-button').click() |
| 81 | self.wait_until_visible('#latest-builds') | 83 | self.wait_until_present('#latest-builds') |
| 82 | # loop until reach the parsing state | 84 | # loop until reach the parsing state |
| 83 | build_state = wait_until_build(self, 'parsing starting cloning') | 85 | wait_until_build(self, 'queued cloning starting parsing failed') |
| 84 | lastest_builds = self.driver.find_elements( | 86 | lastest_builds = self.driver.find_elements( |
| 85 | By.XPATH, | 87 | By.XPATH, |
| 86 | '//div[@id="latest-builds"]/div', | 88 | '//div[@id="latest-builds"]/div', |
| 87 | ) | 89 | ) |
| 88 | last_build = lastest_builds[0] | 90 | last_build = lastest_builds[0] |
| 89 | self.assertTrue( | 91 | self.assertTrue( |
| 90 | 'core-image-minimal' in str(last_build.text) | 92 | 'foo' in str(last_build.text) |
| 91 | ) | 93 | ) |
| 92 | cancel_button = last_build.find_element( | 94 | last_build = lastest_builds[0] |
| 93 | By.XPATH, | 95 | try: |
| 94 | '//span[@class="cancel-build-btn pull-right alert-link"]', | 96 | cancel_button = last_build.find_element( |
| 95 | ) | 97 | By.XPATH, |
| 96 | cancel_button.click() | 98 | '//span[@class="cancel-build-btn pull-right alert-link"]', |
| 97 | if 'starting' not in build_state: # change build state when cancelled in starting state | 99 | ) |
| 98 | wait_until_build_cancelled(self) | 100 | cancel_button.click() |
| 99 | return build_state | 101 | except NoSuchElementException: |
| 102 | # Skip if the build is already cancelled | ||
| 103 | pass | ||
| 104 | wait_until_build_cancelled(self) | ||
| 100 | 105 | ||
| 101 | def _get_tabs(self): | 106 | def _get_tabs(self): |
| 102 | # tabs links list | 107 | # tabs links list |
| @@ -126,6 +131,7 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 126 | - Delete project | 131 | - Delete project |
| 127 | """ | 132 | """ |
| 128 | self._navigate_to_project_page() | 133 | self._navigate_to_project_page() |
| 134 | |||
| 129 | def _get_config_nav_item(index): | 135 | def _get_config_nav_item(index): |
| 130 | config_nav = self.find('#config-nav') | 136 | config_nav = self.find('#config-nav') |
| 131 | return config_nav.find_elements(By.TAG_NAME, 'li')[index] | 137 | return config_nav.find_elements(By.TAG_NAME, 'li')[index] |
| @@ -152,13 +158,27 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 152 | self.assertTrue("actions" in str(actions.text).lower()) | 158 | self.assertTrue("actions" in str(actions.text).lower()) |
| 153 | 159 | ||
| 154 | conf_nav_list = [ | 160 | conf_nav_list = [ |
| 155 | [0, 'Configuration', f"/toastergui/project/{TestProjectConfigTab.project_id}"], # config | 161 | # config |
| 156 | [2, 'Custom images', f"/toastergui/project/{TestProjectConfigTab.project_id}/customimages"], # custom images | 162 | [0, 'Configuration', |
| 157 | [3, 'Image recipes', f"/toastergui/project/{TestProjectConfigTab.project_id}/images"], # image recipes | 163 | f"/toastergui/project/{TestProjectConfigTab.project_id}"], |
| 158 | [4, 'Software recipes', f"/toastergui/project/{TestProjectConfigTab.project_id}/softwarerecipes"], # software recipes | 164 | # custom images |
| 159 | [5, 'Machines', f"/toastergui/project/{TestProjectConfigTab.project_id}/machines"], # machines | 165 | [2, 'Custom images', |
| 160 | [6, 'Layers', f"/toastergui/project/{TestProjectConfigTab.project_id}/layers"], # layers | 166 | f"/toastergui/project/{TestProjectConfigTab.project_id}/customimages"], |
| 161 | [7, 'Distros', f"/toastergui/project/{TestProjectConfigTab.project_id}/distros"], # distro | 167 | # image recipes |
| 168 | [3, 'Image recipes', | ||
| 169 | f"/toastergui/project/{TestProjectConfigTab.project_id}/images"], | ||
| 170 | # software recipes | ||
| 171 | [4, 'Software recipes', | ||
| 172 | f"/toastergui/project/{TestProjectConfigTab.project_id}/softwarerecipes"], | ||
| 173 | # machines | ||
| 174 | [5, 'Machines', | ||
| 175 | f"/toastergui/project/{TestProjectConfigTab.project_id}/machines"], | ||
| 176 | # layers | ||
| 177 | [6, 'Layers', | ||
| 178 | f"/toastergui/project/{TestProjectConfigTab.project_id}/layers"], | ||
| 179 | # distro | ||
| 180 | [7, 'Distros', | ||
| 181 | f"/toastergui/project/{TestProjectConfigTab.project_id}/distros"], | ||
| 162 | # [9, 'BitBake variables', f"/toastergui/project/{TestProjectConfigTab.project_id}/configuration"], # bitbake variables | 182 | # [9, 'BitBake variables', f"/toastergui/project/{TestProjectConfigTab.project_id}/configuration"], # bitbake variables |
| 163 | ] | 183 | ] |
| 164 | for index, item_name, url in conf_nav_list: | 184 | for index, item_name, url in conf_nav_list: |
| @@ -281,15 +301,10 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 281 | # Create a new project for this test | 301 | # Create a new project for this test |
| 282 | project_name = self._random_string(10) | 302 | project_name = self._random_string(10) |
| 283 | self._create_project(project_name=project_name) | 303 | self._create_project(project_name=project_name) |
| 284 | current_url = self.driver.current_url | ||
| 285 | TestProjectConfigTab.project_id = get_projectId_from_url(current_url) | ||
| 286 | url = current_url.split('?')[0] | ||
| 287 | # check if the menu is displayed | 304 | # check if the menu is displayed |
| 288 | self.wait_until_visible('#project-page') | 305 | self.wait_until_visible('#project-page') |
| 289 | block_l = self.driver.find_element( | 306 | block_l = self.driver.find_element( |
| 290 | By.XPATH, '//*[@id="project-page"]/div[2]') | 307 | By.XPATH, '//*[@id="project-page"]/div[2]') |
| 291 | most_built_recipes = self.driver.find_element( | ||
| 292 | By.XPATH, '//*[@id="project-page"]/div[1]/div[3]') | ||
| 293 | project_release = self.driver.find_element( | 308 | project_release = self.driver.find_element( |
| 294 | By.XPATH, '//*[@id="project-page"]/div[1]/div[4]') | 309 | By.XPATH, '//*[@id="project-page"]/div[1]/div[4]') |
| 295 | layers = block_l.find_element(By.ID, 'layer-container') | 310 | layers = block_l.find_element(By.ID, 'layer-container') |
| @@ -315,26 +330,6 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 315 | f'You have changed the {item_name} to: {new_item_name}' in change_notification.text | 330 | f'You have changed the {item_name} to: {new_item_name}' in change_notification.text |
| 316 | ) | 331 | ) |
| 317 | 332 | ||
| 318 | def rebuild_from_most_build_recipes(recipe_list_items): | ||
| 319 | checkbox = recipe_list_items[0].find_element(By.TAG_NAME, 'input') | ||
| 320 | checkbox.click() | ||
| 321 | build_btn = self.find('#freq-build-btn') | ||
| 322 | build_btn.click() | ||
| 323 | self.wait_until_visible('#latest-builds') | ||
| 324 | build_state = wait_until_build(self, 'parsing starting cloning queued') | ||
| 325 | lastest_builds = self.driver.find_elements( | ||
| 326 | By.XPATH, | ||
| 327 | '//div[@id="latest-builds"]/div' | ||
| 328 | ) | ||
| 329 | last_build = lastest_builds[0] | ||
| 330 | self.assertTrue(len(lastest_builds) >= 2) | ||
| 331 | cancel_button = last_build.find_element( | ||
| 332 | By.XPATH, | ||
| 333 | '//span[@class="cancel-build-btn pull-right alert-link"]', | ||
| 334 | ) | ||
| 335 | cancel_button.click() | ||
| 336 | if 'starting' not in build_state: # change build state when cancelled in starting state | ||
| 337 | wait_until_build_cancelled(self) | ||
| 338 | # Machine | 333 | # Machine |
| 339 | check_machine_distro(self, 'machine', 'qemux86-64', 'machine-section') | 334 | check_machine_distro(self, 'machine', 'qemux86-64', 'machine-section') |
| 340 | # Distro | 335 | # Distro |
| @@ -374,32 +369,61 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 374 | layers_list_items = layers_list.find_elements(By.TAG_NAME, 'li') | 369 | layers_list_items = layers_list.find_elements(By.TAG_NAME, 'li') |
| 375 | self.assertTrue(len(layers_list_items) == 4) | 370 | self.assertTrue(len(layers_list_items) == 4) |
| 376 | 371 | ||
| 377 | # Most built recipes | 372 | def test_most_build_recipes(self): |
| 378 | title = most_built_recipes.find_element(By.TAG_NAME, 'h3') | 373 | """ Test most build recipes block contains""" |
| 379 | self.assertTrue("Most built recipes" in title.text) | 374 | def rebuild_from_most_build_recipes(recipe_list_items): |
| 375 | checkbox = recipe_list_items[0].find_element(By.TAG_NAME, 'input') | ||
| 376 | checkbox.click() | ||
| 377 | build_btn = self.find('#freq-build-btn') | ||
| 378 | build_btn.click() | ||
| 379 | self.wait_until_present('#latest-builds') | ||
| 380 | wait_until_build(self, 'queued cloning starting parsing failed') | ||
| 381 | lastest_builds = self.driver.find_elements( | ||
| 382 | By.XPATH, | ||
| 383 | '//div[@id="latest-builds"]/div' | ||
| 384 | ) | ||
| 385 | self.assertTrue(len(lastest_builds) >= 2) | ||
| 386 | last_build = lastest_builds[0] | ||
| 387 | try: | ||
| 388 | cancel_button = last_build.find_element( | ||
| 389 | By.XPATH, | ||
| 390 | '//span[@class="cancel-build-btn pull-right alert-link"]', | ||
| 391 | ) | ||
| 392 | cancel_button.click() | ||
| 393 | except NoSuchElementException: | ||
| 394 | # Skip if the build is already cancelled | ||
| 395 | pass | ||
| 396 | wait_until_build_cancelled(self) | ||
| 397 | # Create a new project for remaining asserts | ||
| 398 | project_name = self._random_string(10) | ||
| 399 | self._create_project(project_name=project_name, release='2') | ||
| 400 | current_url = self.driver.current_url | ||
| 401 | TestProjectConfigTab.project_id = get_projectId_from_url(current_url) | ||
| 402 | url = current_url.split('?')[0] | ||
| 403 | |||
| 380 | # Create a new builds | 404 | # Create a new builds |
| 381 | build_state = self._create_builds() | 405 | self._create_builds() |
| 382 | 406 | ||
| 383 | # Refresh the page | 407 | # back to project page |
| 384 | self.driver.get(url) | 408 | self.driver.get(url) |
| 385 | 409 | ||
| 386 | self.wait_until_visible('#project-page', poll=3) | 410 | self.wait_until_visible('#project-page', poll=3) |
| 387 | # check can select a recipe and build it | 411 | |
| 412 | # Most built recipes | ||
| 388 | most_built_recipes = self.driver.find_element( | 413 | most_built_recipes = self.driver.find_element( |
| 389 | By.XPATH, '//*[@id="project-page"]/div[1]/div[3]') | 414 | By.XPATH, '//*[@id="project-page"]/div[1]/div[3]') |
| 390 | recipe_list = most_built_recipes.find_element(By.ID, 'freq-build-list') | 415 | title = most_built_recipes.find_element(By.TAG_NAME, 'h3') |
| 416 | self.assertTrue("Most built recipes" in title.text) | ||
| 417 | # check can select a recipe and build it | ||
| 418 | self.wait_until_visible('#freq-build-list', poll=3) | ||
| 419 | recipe_list = self.find('#freq-build-list') | ||
| 391 | recipe_list_items = recipe_list.find_elements(By.TAG_NAME, 'li') | 420 | recipe_list_items = recipe_list.find_elements(By.TAG_NAME, 'li') |
| 392 | if 'starting' not in build_state: # Build will not appear in the list if canceled in starting state | 421 | self.assertTrue( |
| 393 | self.assertTrue( | 422 | len(recipe_list_items) > 0, |
| 394 | len(recipe_list_items) > 0, | 423 | msg="Any recipes found in the most built recipes list", |
| 395 | msg="No recipes found in the most built recipes list", | 424 | ) |
| 396 | ) | 425 | rebuild_from_most_build_recipes(recipe_list_items) |
| 397 | rebuild_from_most_build_recipes(recipe_list_items) | 426 | TestProjectConfigTab.project_id = None # reset project id |
| 398 | else: | ||
| 399 | self.assertTrue( | ||
| 400 | len(recipe_list_items) == 0, | ||
| 401 | msg="Recipes found in the most built recipes list", | ||
| 402 | ) | ||
| 403 | 427 | ||
| 404 | def test_project_page_tab_importlayer(self): | 428 | def test_project_page_tab_importlayer(self): |
| 405 | """ Test project page tab import layer """ | 429 | """ Test project page tab import layer """ |
| @@ -461,10 +485,9 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 461 | div_empty_msg = self.find('#empty-state-customimagestable') | 485 | div_empty_msg = self.find('#empty-state-customimagestable') |
| 462 | link_create_custom_image = div_empty_msg.find_element( | 486 | link_create_custom_image = div_empty_msg.find_element( |
| 463 | By.TAG_NAME, 'a') | 487 | By.TAG_NAME, 'a') |
| 464 | last_project_id = Project.objects.get(name=project_name).id | 488 | self.assertTrue(TestProjectConfigTab.project_id is not None) |
| 465 | self.assertTrue(last_project_id is not None) | ||
| 466 | self.assertTrue( | 489 | self.assertTrue( |
| 467 | f"/toastergui/project/{last_project_id}/newcustomimage" in str( | 490 | f"/toastergui/project/{TestProjectConfigTab.project_id}/newcustomimage" in str( |
| 468 | link_create_custom_image.get_attribute('href') | 491 | link_create_custom_image.get_attribute('href') |
| 469 | ) | 492 | ) |
| 470 | ) | 493 | ) |
| @@ -473,6 +496,7 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 473 | link_create_custom_image.text | 496 | link_create_custom_image.text |
| 474 | ) | 497 | ) |
| 475 | ) | 498 | ) |
| 499 | TestProjectConfigTab.project_id = None # reset project id | ||
| 476 | 500 | ||
| 477 | def test_project_page_image_recipe(self): | 501 | def test_project_page_image_recipe(self): |
| 478 | """ Test project page section images | 502 | """ Test project page section images |
| @@ -497,25 +521,3 @@ class TestProjectConfigTab(SeleniumFunctionalTestCase): | |||
| 497 | self.wait_until_visible('#imagerecipestable tbody tr') | 521 | self.wait_until_visible('#imagerecipestable tbody tr') |
| 498 | rows = self.find_all('#imagerecipestable tbody tr') | 522 | rows = self.find_all('#imagerecipestable tbody tr') |
| 499 | self.assertTrue(len(rows) > 0) | 523 | self.assertTrue(len(rows) > 0) |
| 500 | |||
| 501 | # Test build button | ||
| 502 | image_to_build = rows[0] | ||
| 503 | build_btn = image_to_build.find_element( | ||
| 504 | By.XPATH, | ||
| 505 | '//td[@class="add-del-layers"]' | ||
| 506 | ) | ||
| 507 | build_btn.click() | ||
| 508 | build_state = wait_until_build(self, 'parsing starting cloning queued') | ||
| 509 | lastest_builds = self.driver.find_elements( | ||
| 510 | By.XPATH, | ||
| 511 | '//div[@id="latest-builds"]/div' | ||
| 512 | ) | ||
| 513 | self.assertTrue(len(lastest_builds) > 0) | ||
| 514 | last_build = lastest_builds[0] | ||
| 515 | cancel_button = last_build.find_element( | ||
| 516 | By.XPATH, | ||
| 517 | '//span[@class="cancel-build-btn pull-right alert-link"]', | ||
| 518 | ) | ||
| 519 | cancel_button.click() | ||
| 520 | if 'starting' not in build_state: # change build state when cancelled in starting state | ||
| 521 | wait_until_build_cancelled(self) | ||
