212 lines
7.7 KiB
Python
212 lines
7.7 KiB
Python
|
#! /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')
|