From cf0b07c96f3f02f867fcb2e340cff94f950b44e9 Mon Sep 17 00:00:00 2001 From: Elliot Smith Date: Thu, 14 Jul 2016 15:58:00 +0100 Subject: [PATCH] bitbake: toaster-tests: add tests for most recent builds state changes Add tests for the state transitions in the "most recent builds" area of the all builds page. [YOCTO #9631] (Bitbake rev: b95681cf38475903ad4f73059313dda8c0dccef6) Signed-off-by: Elliot Smith Signed-off-by: Richard Purdie --- .../browser/test_most_recent_builds_states.py | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 bitbake/lib/toaster/tests/browser/test_most_recent_builds_states.py diff --git a/bitbake/lib/toaster/tests/browser/test_most_recent_builds_states.py b/bitbake/lib/toaster/tests/browser/test_most_recent_builds_states.py new file mode 100644 index 0000000000..abc0b0bc88 --- /dev/null +++ b/bitbake/lib/toaster/tests/browser/test_most_recent_builds_states.py @@ -0,0 +1,211 @@ +#! /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 tests.browser.selenium_helpers_base import Wait +from orm.models import Project, Build, Task, Recipe, Layer, Layer_Version +from bldcontrol.models import BuildRequest + +class TestMostRecentBuildsStates(SeleniumTestCase): + """ Test states update correctly in most recent builds area """ + + def _create_build_request(self): + project = Project.objects.get_or_create_default_project() + + now = timezone.now() + + build = Build.objects.create(project=project, build_name='fakebuild', + started_on=now, completed_on=now) + + return BuildRequest.objects.create(build=build, project=project, + state=BuildRequest.REQ_QUEUED) + + def _create_recipe(self): + """ Add a recipe to the database and return it """ + layer = Layer.objects.create() + layer_version = Layer_Version.objects.create(layer=layer) + return Recipe.objects.create(name='foo', layer_version=layer_version) + + def _check_build_states(self, build_request): + recipes_to_parse = 10 + url = reverse('all-builds') + self.get(url) + + build = build_request.build + base_selector = '[data-latest-build-result="%s"] ' % build.id + + # build queued; check shown as queued + selector = base_selector + '[data-build-state="Queued"]' + element = self.wait_until_visible(selector) + self.assertRegexpMatches(element.get_attribute('innerHTML'), + 'Build queued', 'build should show queued status') + + # waiting for recipes to be parsed + build.outcome = Build.IN_PROGRESS + build.recipes_to_parse = recipes_to_parse + build.recipes_parsed = 0 + + build_request.state = BuildRequest.REQ_INPROGRESS + build_request.save() + + self.get(url) + + selector = base_selector + '[data-build-state="Parsing"]' + element = self.wait_until_visible(selector) + + bar_selector = '#recipes-parsed-percentage-bar-%s' % build.id + bar_element = element.find_element_by_css_selector(bar_selector) + self.assertEqual(bar_element.value_of_css_property('width'), '0px', + 'recipe parse progress should be at 0') + + # recipes being parsed; check parse progress + build.recipes_parsed = 5 + build.save() + + self.get(url) + + element = self.wait_until_visible(selector) + bar_element = element.find_element_by_css_selector(bar_selector) + recipe_bar_updated = lambda driver: \ + bar_element.get_attribute('style') == 'width: 50%;' + msg = 'recipe parse progress bar should update to 50%' + element = Wait(self.driver).until(recipe_bar_updated, msg) + + # all recipes parsed, task started, waiting for first task to finish; + # check status is shown as "Tasks starting..." + build.recipes_parsed = recipes_to_parse + build.save() + + recipe = self._create_recipe() + task1 = Task.objects.create(build=build, recipe=recipe, + task_name='Lionel') + task2 = Task.objects.create(build=build, recipe=recipe, + task_name='Jeffries') + + self.get(url) + + selector = base_selector + '[data-build-state="Starting"]' + element = self.wait_until_visible(selector) + self.assertRegexpMatches(element.get_attribute('innerHTML'), + 'Tasks starting', 'build should show "tasks starting" status') + + # first task finished; check tasks progress bar + task1.order = 1 + task1.save() + + self.get(url) + + selector = base_selector + '[data-build-state="In Progress"]' + element = self.wait_until_visible(selector) + + bar_selector = '#build-pc-done-bar-%s' % build.id + bar_element = element.find_element_by_css_selector(bar_selector) + + task_bar_updated = lambda driver: \ + bar_element.get_attribute('style') == 'width: 50%;' + msg = 'tasks progress bar should update to 50%' + element = Wait(self.driver).until(task_bar_updated, msg) + + # last task finished; check tasks progress bar updates + task2.order = 2 + task2.save() + + self.get(url) + + element = self.wait_until_visible(selector) + bar_element = element.find_element_by_css_selector(bar_selector) + task_bar_updated = lambda driver: \ + bar_element.get_attribute('style') == 'width: 100%;' + msg = 'tasks progress bar should update to 100%' + element = Wait(self.driver).until(task_bar_updated, msg) + + def test_states_to_success(self): + """ + Test state transitions in the recent builds area for a build which + completes successfully. + """ + build_request = self._create_build_request() + + self._check_build_states(build_request) + + # all tasks complete and build succeeded; check success state shown + build = build_request.build + build.outcome = Build.SUCCEEDED + build.save() + + selector = '[data-latest-build-result="%s"] ' \ + '[data-build-state="Succeeded"]' % build.id + element = self.wait_until_visible(selector) + + def test_states_to_failure(self): + """ + Test state transitions in the recent builds area for a build which + completes in a failure. + """ + build_request = self._create_build_request() + + self._check_build_states(build_request) + + # all tasks complete and build succeeded; check fail state shown + build = build_request.build + build.outcome = Build.FAILED + build.save() + + selector = '[data-latest-build-result="%s"] ' \ + '[data-build-state="Failed"]' % build.id + element = self.wait_until_visible(selector) + + def test_states_cancelling(self): + """ + Test that most recent build area updates correctly for a build + which is cancelled. + """ + url = reverse('all-builds') + + build_request = self._create_build_request() + build = build_request.build + + # cancel the build + build_request.state = BuildRequest.REQ_CANCELLING + build_request.save() + + self.get(url) + + # check cancelling state + selector = '[data-latest-build-result="%s"] ' \ + '[data-build-state="Cancelling"]' % build.id + element = self.wait_until_visible(selector) + self.assertRegexpMatches(element.get_attribute('innerHTML'), + 'Cancelling the build', 'build should show "cancelling" status') + + # check cancelled state + build.outcome = Build.CANCELLED + build.save() + + self.get(url) + + selector = '[data-latest-build-result="%s"] ' \ + '[data-build-state="Cancelled"]' % build.id + element = self.wait_until_visible(selector) + self.assertRegexpMatches(element.get_attribute('innerHTML'), + 'Build cancelled', 'build should show "cancelled" status')