1#! /usr/bin/env python3 2# 3# BitBake Toaster Implementation 4# 5# SPDX-License-Identifier: GPL-2.0-only 6# 7# Copyright (C) 2013-2016 Intel Corporation 8# 9from django.urls import reverse 10from django.utils import timezone 11from tests.browser.selenium_helpers import SeleniumTestCase 12from tests.browser.selenium_helpers_base import Wait 13from orm.models import Project, Build, Task, Recipe, Layer, Layer_Version 14from bldcontrol.models import BuildRequest 15 16from selenium.webdriver.common.by import By 17 18class TestMostRecentBuildsStates(SeleniumTestCase): 19 """ Test states update correctly in most recent builds area """ 20 21 def _create_build_request(self): 22 project = Project.objects.get_or_create_default_project() 23 24 now = timezone.now() 25 26 build = Build.objects.create(project=project, build_name='fakebuild', 27 started_on=now, completed_on=now) 28 29 return BuildRequest.objects.create(build=build, project=project, 30 state=BuildRequest.REQ_QUEUED) 31 32 def _create_recipe(self): 33 """ Add a recipe to the database and return it """ 34 layer = Layer.objects.create() 35 layer_version = Layer_Version.objects.create(layer=layer) 36 return Recipe.objects.create(name='foo', layer_version=layer_version) 37 38 def _check_build_states(self, build_request): 39 recipes_to_parse = 10 40 url = reverse('all-builds') 41 self.get(url) 42 43 build = build_request.build 44 base_selector = '[data-latest-build-result="%s"] ' % build.id 45 46 # build queued; check shown as queued 47 selector = base_selector + '[data-build-state="Queued"]' 48 element = self.wait_until_visible(selector) 49 self.assertRegex(element.get_attribute('innerHTML'), 50 'Build queued', 'build should show queued status') 51 52 # waiting for recipes to be parsed 53 build.outcome = Build.IN_PROGRESS 54 build.recipes_to_parse = recipes_to_parse 55 build.recipes_parsed = 0 56 build.save() 57 58 build_request.state = BuildRequest.REQ_INPROGRESS 59 build_request.save() 60 61 self.get(url) 62 63 selector = base_selector + '[data-build-state="Parsing"]' 64 element = self.wait_until_visible(selector) 65 66 bar_selector = '#recipes-parsed-percentage-bar-%s' % build.id 67 bar_element = element.find_element(By.CSS_SELECTOR, bar_selector) 68 self.assertEqual(bar_element.value_of_css_property('width'), '0px', 69 'recipe parse progress should be at 0') 70 71 # recipes being parsed; check parse progress 72 build.recipes_parsed = 5 73 build.save() 74 75 self.get(url) 76 77 element = self.wait_until_visible(selector) 78 bar_element = element.find_element(By.CSS_SELECTOR, bar_selector) 79 recipe_bar_updated = lambda driver: \ 80 bar_element.get_attribute('style') == 'width: 50%;' 81 msg = 'recipe parse progress bar should update to 50%' 82 element = Wait(self.driver).until(recipe_bar_updated, msg) 83 84 # all recipes parsed, task started, waiting for first task to finish; 85 # check status is shown as "Tasks starting..." 86 build.recipes_parsed = recipes_to_parse 87 build.save() 88 89 recipe = self._create_recipe() 90 task1 = Task.objects.create(build=build, recipe=recipe, 91 task_name='Lionel') 92 task2 = Task.objects.create(build=build, recipe=recipe, 93 task_name='Jeffries') 94 95 self.get(url) 96 97 selector = base_selector + '[data-build-state="Starting"]' 98 element = self.wait_until_visible(selector) 99 self.assertRegex(element.get_attribute('innerHTML'), 100 'Tasks starting', 'build should show "tasks starting" status') 101 102 # first task finished; check tasks progress bar 103 task1.outcome = Task.OUTCOME_SUCCESS 104 task1.save() 105 106 self.get(url) 107 108 selector = base_selector + '[data-build-state="In Progress"]' 109 element = self.wait_until_visible(selector) 110 111 bar_selector = '#build-pc-done-bar-%s' % build.id 112 bar_element = element.find_element(By.CSS_SELECTOR, bar_selector) 113 114 task_bar_updated = lambda driver: \ 115 bar_element.get_attribute('style') == 'width: 50%;' 116 msg = 'tasks progress bar should update to 50%' 117 element = Wait(self.driver).until(task_bar_updated, msg) 118 119 # last task finished; check tasks progress bar updates 120 task2.outcome = Task.OUTCOME_SUCCESS 121 task2.save() 122 123 self.get(url) 124 125 element = self.wait_until_visible(selector) 126 bar_element = element.find_element(By.CSS_SELECTOR, bar_selector) 127 task_bar_updated = lambda driver: \ 128 bar_element.get_attribute('style') == 'width: 100%;' 129 msg = 'tasks progress bar should update to 100%' 130 element = Wait(self.driver).until(task_bar_updated, msg) 131 132 def test_states_to_success(self): 133 """ 134 Test state transitions in the recent builds area for a build which 135 completes successfully. 136 """ 137 build_request = self._create_build_request() 138 139 self._check_build_states(build_request) 140 141 # all tasks complete and build succeeded; check success state shown 142 build = build_request.build 143 build.outcome = Build.SUCCEEDED 144 build.save() 145 146 selector = '[data-latest-build-result="%s"] ' \ 147 '[data-build-state="Succeeded"]' % build.id 148 element = self.wait_until_visible(selector) 149 150 def test_states_to_failure(self): 151 """ 152 Test state transitions in the recent builds area for a build which 153 completes in a failure. 154 """ 155 build_request = self._create_build_request() 156 157 self._check_build_states(build_request) 158 159 # all tasks complete and build succeeded; check fail state shown 160 build = build_request.build 161 build.outcome = Build.FAILED 162 build.save() 163 164 selector = '[data-latest-build-result="%s"] ' \ 165 '[data-build-state="Failed"]' % build.id 166 element = self.wait_until_visible(selector) 167 168 def test_states_cancelling(self): 169 """ 170 Test that most recent build area updates correctly for a build 171 which is cancelled. 172 """ 173 url = reverse('all-builds') 174 175 build_request = self._create_build_request() 176 build = build_request.build 177 178 # cancel the build 179 build_request.state = BuildRequest.REQ_CANCELLING 180 build_request.save() 181 182 self.get(url) 183 184 # check cancelling state 185 selector = '[data-latest-build-result="%s"] ' \ 186 '[data-build-state="Cancelling"]' % build.id 187 element = self.wait_until_visible(selector) 188 self.assertRegex(element.get_attribute('innerHTML'), 189 'Cancelling the build', 'build should show "cancelling" status') 190 191 # check cancelled state 192 build.outcome = Build.CANCELLED 193 build.save() 194 195 self.get(url) 196 197 selector = '[data-latest-build-result="%s"] ' \ 198 '[data-build-state="Cancelled"]' % build.id 199 element = self.wait_until_visible(selector) 200 self.assertRegex(element.get_attribute('innerHTML'), 201 'Build cancelled', 'build should show "cancelled" status') 202