summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/tests/browser/test_all_builds_page.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/toaster/tests/browser/test_all_builds_page.py')
-rw-r--r--bitbake/lib/toaster/tests/browser/test_all_builds_page.py315
1 files changed, 285 insertions, 30 deletions
diff --git a/bitbake/lib/toaster/tests/browser/test_all_builds_page.py b/bitbake/lib/toaster/tests/browser/test_all_builds_page.py
index 8423d3dab2..b9356a0344 100644
--- a/bitbake/lib/toaster/tests/browser/test_all_builds_page.py
+++ b/bitbake/lib/toaster/tests/browser/test_all_builds_page.py
@@ -7,13 +7,18 @@
7# SPDX-License-Identifier: GPL-2.0-only 7# SPDX-License-Identifier: GPL-2.0-only
8# 8#
9 9
10import os
10import re 11import re
11 12
12from django.urls import reverse 13from django.urls import reverse
14from selenium.webdriver.support.select import Select
13from django.utils import timezone 15from django.utils import timezone
16from bldcontrol.models import BuildRequest
14from tests.browser.selenium_helpers import SeleniumTestCase 17from tests.browser.selenium_helpers import SeleniumTestCase
15 18
16from orm.models import BitbakeVersion, Release, Project, Build, Target 19from orm.models import BitbakeVersion, Layer, Layer_Version, Recipe, Release, Project, Build, Target, Task
20
21from selenium.webdriver.common.by import By
17 22
18 23
19class TestAllBuildsPage(SeleniumTestCase): 24class TestAllBuildsPage(SeleniumTestCase):
@@ -23,7 +28,8 @@ class TestAllBuildsPage(SeleniumTestCase):
23 CLI_BUILDS_PROJECT_NAME = 'command line builds' 28 CLI_BUILDS_PROJECT_NAME = 'command line builds'
24 29
25 def setUp(self): 30 def setUp(self):
26 bbv = BitbakeVersion.objects.create(name='bbv1', giturl='/tmp/', 31 builldir = os.environ.get('BUILDDIR', './')
32 bbv = BitbakeVersion.objects.create(name='bbv1', giturl=f'{builldir}/',
27 branch='master', dirpath='') 33 branch='master', dirpath='')
28 release = Release.objects.create(name='release1', 34 release = Release.objects.create(name='release1',
29 bitbake_version=bbv) 35 bitbake_version=bbv)
@@ -69,7 +75,7 @@ class TestAllBuildsPage(SeleniumTestCase):
69 '[data-role="data-recent-build-buildtime-field"]' % build.id 75 '[data-role="data-recent-build-buildtime-field"]' % build.id
70 76
71 # because this loads via Ajax, wait for it to be visible 77 # because this loads via Ajax, wait for it to be visible
72 self.wait_until_present(selector) 78 self.wait_until_visible(selector)
73 79
74 build_time_spans = self.find_all(selector) 80 build_time_spans = self.find_all(selector)
75 81
@@ -79,7 +85,7 @@ class TestAllBuildsPage(SeleniumTestCase):
79 85
80 def _get_row_for_build(self, build): 86 def _get_row_for_build(self, build):
81 """ Get the table row for the build from the all builds table """ 87 """ Get the table row for the build from the all builds table """
82 self.wait_until_present('#allbuildstable') 88 self.wait_until_visible('#allbuildstable')
83 89
84 rows = self.find_all('#allbuildstable tr') 90 rows = self.find_all('#allbuildstable tr')
85 91
@@ -91,7 +97,7 @@ class TestAllBuildsPage(SeleniumTestCase):
91 found_row = None 97 found_row = None
92 for row in rows: 98 for row in rows:
93 99
94 outcome_links = row.find_elements_by_css_selector(selector) 100 outcome_links = row.find_elements(By.CSS_SELECTOR, selector)
95 if len(outcome_links) == 1: 101 if len(outcome_links) == 1:
96 found_row = row 102 found_row = row
97 break 103 break
@@ -100,6 +106,66 @@ class TestAllBuildsPage(SeleniumTestCase):
100 106
101 return found_row 107 return found_row
102 108
109 def _get_create_builds(self, **kwargs):
110 """ Create a build and return the build object """
111 build1 = Build.objects.create(**self.project1_build_success)
112 build2 = Build.objects.create(**self.project1_build_failure)
113
114 # add some targets to these builds so they have recipe links
115 # (and so we can find the row in the ToasterTable corresponding to
116 # a particular build)
117 Target.objects.create(build=build1, target='foo')
118 Target.objects.create(build=build2, target='bar')
119
120 if kwargs:
121 # Create kwargs.get('success') builds with success status with target
122 # and kwargs.get('failure') builds with failure status with target
123 for i in range(kwargs.get('success', 0)):
124 now = timezone.now()
125 self.project1_build_success['started_on'] = now
126 self.project1_build_success[
127 'completed_on'] = now - timezone.timedelta(days=i)
128 build = Build.objects.create(**self.project1_build_success)
129 Target.objects.create(build=build,
130 target=f'{i}_success_recipe',
131 task=f'{i}_success_task')
132
133 self._set_buildRequest_and_task_on_build(build)
134 for i in range(kwargs.get('failure', 0)):
135 now = timezone.now()
136 self.project1_build_failure['started_on'] = now
137 self.project1_build_failure[
138 'completed_on'] = now - timezone.timedelta(days=i)
139 build = Build.objects.create(**self.project1_build_failure)
140 Target.objects.create(build=build,
141 target=f'{i}_fail_recipe',
142 task=f'{i}_fail_task')
143 self._set_buildRequest_and_task_on_build(build)
144 return build1, build2
145
146 def _create_recipe(self):
147 """ Add a recipe to the database and return it """
148 layer = Layer.objects.create()
149 layer_version = Layer_Version.objects.create(layer=layer)
150 return Recipe.objects.create(name='recipe_foo', layer_version=layer_version)
151
152 def _set_buildRequest_and_task_on_build(self, build):
153 """ Set buildRequest and task on build """
154 build.recipes_parsed = 1
155 build.save()
156 buildRequest = BuildRequest.objects.create(
157 build=build,
158 project=self.project1,
159 state=BuildRequest.REQ_COMPLETED)
160 build.build_request = buildRequest
161 recipe = self._create_recipe()
162 task = Task.objects.create(build=build,
163 recipe=recipe,
164 task_name='task',
165 outcome=Task.OUTCOME_SUCCESS)
166 task.save()
167 build.save()
168
103 def test_show_tasks_with_suffix(self): 169 def test_show_tasks_with_suffix(self):
104 """ Task should be shown as suffix on build name """ 170 """ Task should be shown as suffix on build name """
105 build = Build.objects.create(**self.project1_build_success) 171 build = Build.objects.create(**self.project1_build_success)
@@ -109,7 +175,7 @@ class TestAllBuildsPage(SeleniumTestCase):
109 175
110 url = reverse('all-builds') 176 url = reverse('all-builds')
111 self.get(url) 177 self.get(url)
112 self.wait_until_present('td[class="target"]') 178 self.wait_until_visible('td[class="target"]')
113 179
114 cell = self.find('td[class="target"]') 180 cell = self.find('td[class="target"]')
115 content = cell.get_attribute('innerHTML') 181 content = cell.get_attribute('innerHTML')
@@ -126,23 +192,25 @@ class TestAllBuildsPage(SeleniumTestCase):
126 but should be shown for other builds 192 but should be shown for other builds
127 """ 193 """
128 build1 = Build.objects.create(**self.project1_build_success) 194 build1 = Build.objects.create(**self.project1_build_success)
129 default_build = Build.objects.create(**self.default_project_build_success) 195 default_build = Build.objects.create(
196 **self.default_project_build_success)
130 197
131 url = reverse('all-builds') 198 url = reverse('all-builds')
132 self.get(url) 199 self.get(url)
133 200
134 # shouldn't see a rebuild button for command-line builds
135 selector = 'div[data-latest-build-result="%s"] .rebuild-btn' % default_build.id
136 run_again_button = self.find_all(selector)
137 self.assertEqual(len(run_again_button), 0,
138 'should not see a rebuild button for cli builds')
139
140 # should see a rebuild button for non-command-line builds 201 # should see a rebuild button for non-command-line builds
202 self.wait_until_visible('#allbuildstable tbody tr')
141 selector = 'div[data-latest-build-result="%s"] .rebuild-btn' % build1.id 203 selector = 'div[data-latest-build-result="%s"] .rebuild-btn' % build1.id
142 run_again_button = self.find_all(selector) 204 run_again_button = self.find_all(selector)
143 self.assertEqual(len(run_again_button), 1, 205 self.assertEqual(len(run_again_button), 1,
144 'should see a rebuild button for non-cli builds') 206 'should see a rebuild button for non-cli builds')
145 207
208 # shouldn't see a rebuild button for command-line builds
209 selector = 'div[data-latest-build-result="%s"] .rebuild-btn' % default_build.id
210 run_again_button = self.find_all(selector)
211 self.assertEqual(len(run_again_button), 0,
212 'should not see a rebuild button for cli builds')
213
146 def test_tooltips_on_project_name(self): 214 def test_tooltips_on_project_name(self):
147 """ 215 """
148 Test tooltips shown next to project name in the main table 216 Test tooltips shown next to project name in the main table
@@ -156,6 +224,7 @@ class TestAllBuildsPage(SeleniumTestCase):
156 224
157 url = reverse('all-builds') 225 url = reverse('all-builds')
158 self.get(url) 226 self.get(url)
227 self.wait_until_visible('#allbuildstable', poll=3)
159 228
160 # get the project name cells from the table 229 # get the project name cells from the table
161 cells = self.find_all('#allbuildstable td[class="project"]') 230 cells = self.find_all('#allbuildstable td[class="project"]')
@@ -164,7 +233,7 @@ class TestAllBuildsPage(SeleniumTestCase):
164 233
165 for cell in cells: 234 for cell in cells:
166 content = cell.get_attribute('innerHTML') 235 content = cell.get_attribute('innerHTML')
167 help_icons = cell.find_elements_by_css_selector(selector) 236 help_icons = cell.find_elements(By.CSS_SELECTOR, selector)
168 237
169 if re.search(self.PROJECT_NAME, content): 238 if re.search(self.PROJECT_NAME, content):
170 # no help icon next to non-cli project name 239 # no help icon next to non-cli project name
@@ -184,38 +253,224 @@ class TestAllBuildsPage(SeleniumTestCase):
184 recent builds area; failed builds should not have links on the time column, 253 recent builds area; failed builds should not have links on the time column,
185 or in the recent builds area 254 or in the recent builds area
186 """ 255 """
187 build1 = Build.objects.create(**self.project1_build_success) 256 build1, build2 = self._get_create_builds()
188 build2 = Build.objects.create(**self.project1_build_failure)
189
190 # add some targets to these builds so they have recipe links
191 # (and so we can find the row in the ToasterTable corresponding to
192 # a particular build)
193 Target.objects.create(build=build1, target='foo')
194 Target.objects.create(build=build2, target='bar')
195 257
196 url = reverse('all-builds') 258 url = reverse('all-builds')
197 self.get(url) 259 self.get(url)
260 self.wait_until_visible('#allbuildstable', poll=3)
198 261
199 # test recent builds area for successful build 262 # test recent builds area for successful build
200 element = self._get_build_time_element(build1) 263 element = self._get_build_time_element(build1)
201 links = element.find_elements_by_css_selector('a') 264 links = element.find_elements(By.CSS_SELECTOR, 'a')
202 msg = 'should be a link on the build time for a successful recent build' 265 msg = 'should be a link on the build time for a successful recent build'
203 self.assertEquals(len(links), 1, msg) 266 self.assertEqual(len(links), 1, msg)
204 267
205 # test recent builds area for failed build 268 # test recent builds area for failed build
206 element = self._get_build_time_element(build2) 269 element = self._get_build_time_element(build2)
207 links = element.find_elements_by_css_selector('a') 270 links = element.find_elements(By.CSS_SELECTOR, 'a')
208 msg = 'should not be a link on the build time for a failed recent build' 271 msg = 'should not be a link on the build time for a failed recent build'
209 self.assertEquals(len(links), 0, msg) 272 self.assertEqual(len(links), 0, msg)
210 273
211 # test the time column for successful build 274 # test the time column for successful build
212 build1_row = self._get_row_for_build(build1) 275 build1_row = self._get_row_for_build(build1)
213 links = build1_row.find_elements_by_css_selector('td.time a') 276 links = build1_row.find_elements(By.CSS_SELECTOR, 'td.time a')
214 msg = 'should be a link on the build time for a successful build' 277 msg = 'should be a link on the build time for a successful build'
215 self.assertEquals(len(links), 1, msg) 278 self.assertEqual(len(links), 1, msg)
216 279
217 # test the time column for failed build 280 # test the time column for failed build
218 build2_row = self._get_row_for_build(build2) 281 build2_row = self._get_row_for_build(build2)
219 links = build2_row.find_elements_by_css_selector('td.time a') 282 links = build2_row.find_elements(By.CSS_SELECTOR, 'td.time a')
220 msg = 'should not be a link on the build time for a failed build' 283 msg = 'should not be a link on the build time for a failed build'
221 self.assertEquals(len(links), 0, msg) 284 self.assertEqual(len(links), 0, msg)
285
286 def test_builds_table_search_box(self):
287 """ Test the search box in the builds table on the all builds page """
288 self._get_create_builds()
289
290 url = reverse('all-builds')
291 self.get(url)
292
293 # Check search box is present and works
294 self.wait_until_visible('#allbuildstable tbody tr')
295 search_box = self.find('#search-input-allbuildstable')
296 self.assertTrue(search_box.is_displayed())
297
298 # Check that we can search for a build by recipe name
299 search_box.send_keys('foo')
300 search_btn = self.find('#search-submit-allbuildstable')
301 search_btn.click()
302 self.wait_until_visible('#allbuildstable tbody tr')
303 rows = self.find_all('#allbuildstable tbody tr')
304 self.assertTrue(len(rows) >= 1)
305
306 def test_filtering_on_failure_tasks_column(self):
307 """ Test the filtering on failure tasks column in the builds table on the all builds page """
308 def _check_if_filter_failed_tasks_column_is_visible():
309 # check if failed tasks filter column is visible, if not click on it
310 # Check edit column
311 edit_column = self.find('#edit-columns-button')
312 self.assertTrue(edit_column.is_displayed())
313 edit_column.click()
314 # Check dropdown is visible
315 self.wait_until_visible('ul.dropdown-menu.editcol')
316 filter_fails_task_checkbox = self.find('#checkbox-failed_tasks')
317 if not filter_fails_task_checkbox.is_selected():
318 filter_fails_task_checkbox.click()
319 edit_column.click()
320
321 self._get_create_builds(success=10, failure=10)
322
323 url = reverse('all-builds')
324 self.get(url)
325
326 # Check filtering on failure tasks column
327 self.wait_until_visible('#allbuildstable tbody tr')
328 _check_if_filter_failed_tasks_column_is_visible()
329 failed_tasks_filter = self.find('#failed_tasks_filter')
330 failed_tasks_filter.click()
331 # Check popup is visible
332 self.wait_until_visible('#filter-modal-allbuildstable')
333 self.assertTrue(
334 self.find('#filter-modal-allbuildstable').is_displayed())
335 # Check that we can filter by failure tasks
336 build_without_failure_tasks = self.find(
337 '#failed_tasks_filter\\:without_failed_tasks')
338 build_without_failure_tasks.click()
339 # click on apply button
340 self.find('#filter-modal-allbuildstable .btn-primary').click()
341 self.wait_until_visible('#allbuildstable tbody tr')
342 # Check if filter is applied, by checking if failed_tasks_filter has btn-primary class
343 self.assertTrue(self.find('#failed_tasks_filter').get_attribute(
344 'class').find('btn-primary') != -1)
345
346 def test_filtering_on_completedOn_column(self):
347 """ Test the filtering on completed_on column in the builds table on the all builds page """
348 self._get_create_builds(success=10, failure=10)
349
350 url = reverse('all-builds')
351 self.get(url)
352
353 # Check filtering on failure tasks column
354 self.wait_until_visible('#allbuildstable tbody tr')
355 completed_on_filter = self.find('#completed_on_filter')
356 completed_on_filter.click()
357 # Check popup is visible
358 self.wait_until_visible('#filter-modal-allbuildstable')
359 self.assertTrue(
360 self.find('#filter-modal-allbuildstable').is_displayed())
361 # Check that we can filter by failure tasks
362 build_without_failure_tasks = self.find(
363 '#completed_on_filter\\:date_range')
364 build_without_failure_tasks.click()
365 # click on apply button
366 self.find('#filter-modal-allbuildstable .btn-primary').click()
367 self.wait_until_visible('#allbuildstable tbody tr')
368 # Check if filter is applied, by checking if completed_on_filter has btn-primary class
369 self.assertTrue(self.find('#completed_on_filter').get_attribute(
370 'class').find('btn-primary') != -1)
371
372 # Filter by date range
373 self.find('#completed_on_filter').click()
374 self.wait_until_visible('#filter-modal-allbuildstable')
375 date_ranges = self.driver.find_elements(
376 By.XPATH, '//input[@class="form-control hasDatepicker"]')
377 today = timezone.now()
378 yestersday = today - timezone.timedelta(days=1)
379 date_ranges[0].send_keys(yestersday.strftime('%Y-%m-%d'))
380 date_ranges[1].send_keys(today.strftime('%Y-%m-%d'))
381 self.find('#filter-modal-allbuildstable .btn-primary').click()
382 self.wait_until_visible('#allbuildstable tbody tr')
383 self.assertTrue(self.find('#completed_on_filter').get_attribute(
384 'class').find('btn-primary') != -1)
385 # Check if filter is applied, number of builds displayed should be 6
386 self.assertTrue(len(self.find_all('#allbuildstable tbody tr')) >= 4)
387
388 def test_builds_table_editColumn(self):
389 """ Test the edit column feature in the builds table on the all builds page """
390 self._get_create_builds(success=10, failure=10)
391
392 def test_edit_column(check_box_id):
393 # Check that we can hide/show table column
394 check_box = self.find(f'#{check_box_id}')
395 th_class = str(check_box_id).replace('checkbox-', '')
396 if check_box.is_selected():
397 # check if column is visible in table
398 self.assertTrue(
399 self.find(
400 f'#allbuildstable thead th.{th_class}'
401 ).is_displayed(),
402 f"The {th_class} column is checked in EditColumn dropdown, but it's not visible in table"
403 )
404 check_box.click()
405 # check if column is hidden in table
406 self.assertFalse(
407 self.find(
408 f'#allbuildstable thead th.{th_class}'
409 ).is_displayed(),
410 f"The {th_class} column is unchecked in EditColumn dropdown, but it's visible in table"
411 )
412 else:
413 # check if column is hidden in table
414 self.assertFalse(
415 self.find(
416 f'#allbuildstable thead th.{th_class}'
417 ).is_displayed(),
418 f"The {th_class} column is unchecked in EditColumn dropdown, but it's visible in table"
419 )
420 check_box.click()
421 # check if column is visible in table
422 self.assertTrue(
423 self.find(
424 f'#allbuildstable thead th.{th_class}'
425 ).is_displayed(),
426 f"The {th_class} column is checked in EditColumn dropdown, but it's not visible in table"
427 )
428 url = reverse('all-builds')
429 self.get(url)
430 self.wait_until_visible('#allbuildstable tbody tr')
431
432 # Check edit column
433 edit_column = self.find('#edit-columns-button')
434 self.assertTrue(edit_column.is_displayed())
435 edit_column.click()
436 # Check dropdown is visible
437 self.wait_until_visible('ul.dropdown-menu.editcol')
438
439 # Check that we can hide the edit column
440 test_edit_column('checkbox-errors_no')
441 test_edit_column('checkbox-failed_tasks')
442 test_edit_column('checkbox-image_files')
443 test_edit_column('checkbox-project')
444 test_edit_column('checkbox-started_on')
445 test_edit_column('checkbox-time')
446 test_edit_column('checkbox-warnings_no')
447
448 def test_builds_table_show_rows(self):
449 """ Test the show rows feature in the builds table on the all builds page """
450 self._get_create_builds(success=100, failure=100)
451
452 def test_show_rows(row_to_show, show_row_link):
453 # Check that we can show rows == row_to_show
454 show_row_link.select_by_value(str(row_to_show))
455 self.wait_until_visible('#allbuildstable tbody tr', poll=3)
456 # check at least some rows are visible
457 self.assertTrue(
458 len(self.find_all('#allbuildstable tbody tr')) > 0
459 )
460
461 url = reverse('all-builds')
462 self.get(url)
463 self.wait_until_visible('#allbuildstable tbody tr')
464
465 show_rows = self.driver.find_elements(
466 By.XPATH,
467 '//select[@class="form-control pagesize-allbuildstable"]'
468 )
469 # Check show rows
470 for show_row_link in show_rows:
471 show_row_link = Select(show_row_link)
472 test_show_rows(10, show_row_link)
473 test_show_rows(25, show_row_link)
474 test_show_rows(50, show_row_link)
475 test_show_rows(100, show_row_link)
476 test_show_rows(150, show_row_link)