poky/bitbake/lib/toaster/tests/browser/test_builddashboard_page.py
Richard Purdie 9501864db8 bitbake: bitbake: Strip old editor directives from file headers
There are much better ways to handle this and most editors shouldn't need this
in modern times, drop the noise from the files. Its not consitently applied
anyway.

(Bitbake rev: 5e43070e3087d09aea2f459b033d035c5ef747d0)

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2019-05-04 10:44:10 +01:00

336 lines
12 KiB
Python

#! /usr/bin/env python
#
# BitBake Toaster Implementation
#
# Copyright (C) 2013-2016 Intel Corporation
#
# SPDX-License-Identifier: GPL-2.0-only
#
from django.core.urlresolvers import reverse
from django.utils import timezone
from tests.browser.selenium_helpers import SeleniumTestCase
from orm.models import Project, Release, BitbakeVersion, Build, LogMessage
from orm.models import Layer, Layer_Version, Recipe, CustomImageRecipe, Variable
class TestBuildDashboardPage(SeleniumTestCase):
""" Tests for the build dashboard /build/X """
def setUp(self):
bbv = BitbakeVersion.objects.create(name='bbv1', giturl='/tmp/',
branch='master', dirpath="")
release = Release.objects.create(name='release1',
bitbake_version=bbv)
project = Project.objects.create_project(name='test project',
release=release)
now = timezone.now()
self.build1 = Build.objects.create(project=project,
started_on=now,
completed_on=now,
outcome=Build.SUCCEEDED)
self.build2 = Build.objects.create(project=project,
started_on=now,
completed_on=now,
outcome=Build.SUCCEEDED)
self.build3 = Build.objects.create(project=project,
started_on=now,
completed_on=now,
outcome=Build.FAILED)
# add Variable objects to the successful builds, as this is the criterion
# used to determine whether the left-hand panel should be displayed
Variable.objects.create(build=self.build1,
variable_name='Foo',
variable_value='Bar')
Variable.objects.create(build=self.build2,
variable_name='Foo',
variable_value='Bar')
# exception
msg1 = 'an exception was thrown'
self.exception_message = LogMessage.objects.create(
build=self.build1,
level=LogMessage.EXCEPTION,
message=msg1
)
# critical
msg2 = 'a critical error occurred'
self.critical_message = LogMessage.objects.create(
build=self.build1,
level=LogMessage.CRITICAL,
message=msg2
)
# error on the failed build
msg3 = 'an error occurred'
self.error_message = LogMessage.objects.create(
build=self.build3,
level=LogMessage.ERROR,
message=msg3
)
# warning on the failed build
msg4 = 'DANGER WILL ROBINSON'
self.warning_message = LogMessage.objects.create(
build=self.build3,
level=LogMessage.WARNING,
message=msg4
)
# recipes related to the build, for testing the edit custom image/new
# custom image buttons
layer = Layer.objects.create(name='alayer')
layer_version = Layer_Version.objects.create(
layer=layer, build=self.build1
)
# non-image recipes related to a build, for testing the new custom
# image button
layer_version2 = Layer_Version.objects.create(layer=layer,
build=self.build3)
# image recipes
self.image_recipe1 = Recipe.objects.create(
name='recipeA',
layer_version=layer_version,
file_path='/foo/recipeA.bb',
is_image=True
)
self.image_recipe2 = Recipe.objects.create(
name='recipeB',
layer_version=layer_version,
file_path='/foo/recipeB.bb',
is_image=True
)
# custom image recipes for this project
self.custom_image_recipe1 = CustomImageRecipe.objects.create(
name='customRecipeY',
project=project,
layer_version=layer_version,
file_path='/foo/customRecipeY.bb',
base_recipe=self.image_recipe1,
is_image=True
)
self.custom_image_recipe2 = CustomImageRecipe.objects.create(
name='customRecipeZ',
project=project,
layer_version=layer_version,
file_path='/foo/customRecipeZ.bb',
base_recipe=self.image_recipe2,
is_image=True
)
# custom image recipe for a different project (to test filtering
# of image recipes and custom image recipes is correct: this shouldn't
# show up in either query against self.build1)
self.custom_image_recipe3 = CustomImageRecipe.objects.create(
name='customRecipeOmega',
project=Project.objects.create(name='baz', release=release),
layer_version=Layer_Version.objects.create(
layer=layer, build=self.build2
),
file_path='/foo/customRecipeOmega.bb',
base_recipe=self.image_recipe2,
is_image=True
)
# another non-image recipe (to test filtering of image recipes and
# custom image recipes is correct: this shouldn't show up in either
# for any build)
self.non_image_recipe = Recipe.objects.create(
name='nonImageRecipe',
layer_version=layer_version,
file_path='/foo/nonImageRecipe.bb',
is_image=False
)
def _get_build_dashboard(self, build):
"""
Navigate to the build dashboard for build
"""
url = reverse('builddashboard', args=(build.id,))
self.get(url)
def _get_build_dashboard_errors(self, build):
"""
Get a list of HTML fragments representing the errors on the
dashboard for the Build object build
"""
self._get_build_dashboard(build)
return self.find_all('#errors div.alert-danger')
def _check_for_log_message(self, message_elements, log_message):
"""
Check that the LogMessage <log_message> has a representation in
the HTML elements <message_elements>.
message_elements: WebElements representing the log messages shown
in the build dashboard; each should have a <pre> element inside
it with a data-log-message-id attribute
log_message: orm.models.LogMessage instance
"""
expected_text = log_message.message
expected_pk = str(log_message.pk)
found = False
for element in message_elements:
log_message_text = element.find_element_by_tag_name('pre').text.strip()
text_matches = (log_message_text == expected_text)
log_message_pk = element.get_attribute('data-log-message-id')
id_matches = (log_message_pk == expected_pk)
if text_matches and id_matches:
found = True
break
template_vars = (expected_text, expected_pk)
assertion_failed_msg = 'message not found: ' \
'expected text "%s" and ID %s' % template_vars
self.assertTrue(found, assertion_failed_msg)
def _check_for_error_message(self, build, log_message):
"""
Check whether the LogMessage instance <log_message> is
represented as an HTML error in the dashboard page for the Build object
build
"""
errors = self._get_build_dashboard_errors(build)
self._check_for_log_message(errors, log_message)
def _check_labels_in_modal(self, modal, expected):
"""
Check that the text values of the <label> elements inside
the WebElement modal match the list of text values in expected
"""
# labels containing the radio buttons we're testing for
labels = modal.find_elements_by_css_selector(".radio")
labels_text = [lab.text for lab in labels]
self.assertEqual(len(labels_text), len(expected))
for expected_text in expected:
self.assertTrue(expected_text in labels_text,
"Could not find %s in %s" % (expected_text,
labels_text))
def test_exceptions_show_as_errors(self):
"""
LogMessages with level EXCEPTION should display in the errors
section of the page
"""
self._check_for_error_message(self.build1, self.exception_message)
def test_criticals_show_as_errors(self):
"""
LogMessages with level CRITICAL should display in the errors
section of the page
"""
self._check_for_error_message(self.build1, self.critical_message)
def test_edit_custom_image_button(self):
"""
A build which built two custom images should present a modal which lets
the user choose one of them to edit
"""
self._get_build_dashboard(self.build1)
# click the "edit custom image" button, which populates the modal
selector = '[data-role="edit-custom-image-trigger"]'
self.click(selector)
modal = self.driver.find_element_by_id('edit-custom-image-modal')
self.wait_until_visible("#edit-custom-image-modal")
# recipes we expect to see in the edit custom image modal
expected_recipes = [
self.custom_image_recipe1.name,
self.custom_image_recipe2.name
]
self._check_labels_in_modal(modal, expected_recipes)
def test_new_custom_image_button(self):
"""
Check that a build with multiple images and custom images presents
all of them as options for creating a new custom image from
"""
self._get_build_dashboard(self.build1)
# click the "new custom image" button, which populates the modal
selector = '[data-role="new-custom-image-trigger"]'
self.click(selector)
modal = self.driver.find_element_by_id('new-custom-image-modal')
self.wait_until_visible("#new-custom-image-modal")
# recipes we expect to see in the new custom image modal
expected_recipes = [
self.image_recipe1.name,
self.image_recipe2.name,
self.custom_image_recipe1.name,
self.custom_image_recipe2.name
]
self._check_labels_in_modal(modal, expected_recipes)
def test_new_custom_image_button_no_image(self):
"""
Check that a build which builds non-image recipes doesn't show
the new custom image button on the dashboard.
"""
self._get_build_dashboard(self.build3)
selector = '[data-role="new-custom-image-trigger"]'
self.assertFalse(self.element_exists(selector),
'new custom image button should not show for builds which ' \
'don\'t have any image recipes')
def test_left_panel(self):
""""
Builds which succeed should have a left panel and a build summary
"""
self._get_build_dashboard(self.build1)
left_panel = self.find_all('#nav')
self.assertEqual(len(left_panel), 1)
build_summary = self.find_all('[data-role="build-summary-heading"]')
self.assertEqual(len(build_summary), 1)
def test_failed_no_left_panel(self):
"""
Builds which fail should have no left panel and no build summary
"""
self._get_build_dashboard(self.build3)
left_panel = self.find_all('#nav')
self.assertEqual(len(left_panel), 0)
build_summary = self.find_all('[data-role="build-summary-heading"]')
self.assertEqual(len(build_summary), 0)
def test_failed_shows_errors_and_warnings(self):
"""
Failed builds should still show error and warning messages
"""
self._get_build_dashboard(self.build3)
errors = self.find_all('#errors div.alert-danger')
self._check_for_log_message(errors, self.error_message)
# expand the warnings area
self.click('#warning-toggle')
self.wait_until_visible('#warnings div.alert-warning')
warnings = self.find_all('#warnings div.alert-warning')
self._check_for_log_message(warnings, self.warning_message)