#! /usr/bin/env python # ex:ts=4:sw=4:sts=4:et # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- # # BitBake Toaster Implementation # # Copyright (C) 2013-2016 Intel Corporation # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 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 has a representation in the HTML elements . message_elements: WebElements representing the log messages shown in the build dashboard; each should have a
 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  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