1#! /usr/bin/env python3
2#
3# BitBake Toaster Implementation
4#
5# Copyright (C) 2013-2016 Intel Corporation
6#
7# SPDX-License-Identifier: GPL-2.0-only
8#
9
10import re
11
12from django.core.urlresolvers import reverse
13from django.utils import timezone
14from tests.browser.selenium_helpers import SeleniumTestCase
15
16from orm.models import BitbakeVersion, Release, Project, Build, Target
17
18class TestProjectBuildsPage(SeleniumTestCase):
19    """ Test data at /project/X/builds is displayed correctly """
20
21    PROJECT_NAME = 'test project'
22    CLI_BUILDS_PROJECT_NAME = 'command line builds'
23
24    def setUp(self):
25        bbv = BitbakeVersion.objects.create(name='bbv1', giturl='/tmp/',
26                                            branch='master', dirpath='')
27        release = Release.objects.create(name='release1',
28                                         bitbake_version=bbv)
29        self.project1 = Project.objects.create_project(name=self.PROJECT_NAME,
30                                                       release=release)
31        self.project1.save()
32
33        self.project2 = Project.objects.create_project(name=self.PROJECT_NAME,
34                                                       release=release)
35        self.project2.save()
36
37        self.default_project = Project.objects.create_project(
38            name=self.CLI_BUILDS_PROJECT_NAME,
39            release=release
40        )
41        self.default_project.is_default = True
42        self.default_project.save()
43
44        # parameters for builds to associate with the projects
45        now = timezone.now()
46
47        self.project1_build_success = {
48            'project': self.project1,
49            'started_on': now,
50            'completed_on': now,
51            'outcome': Build.SUCCEEDED
52        }
53
54        self.project1_build_in_progress = {
55            'project': self.project1,
56            'started_on': now,
57            'completed_on': now,
58            'outcome': Build.IN_PROGRESS
59        }
60
61        self.project2_build_success = {
62            'project': self.project2,
63            'started_on': now,
64            'completed_on': now,
65            'outcome': Build.SUCCEEDED
66        }
67
68        self.project2_build_in_progress = {
69            'project': self.project2,
70            'started_on': now,
71            'completed_on': now,
72            'outcome': Build.IN_PROGRESS
73        }
74
75    def _get_rows_for_project(self, project_id):
76        """
77        Helper to retrieve HTML rows for a project's builds,
78        as shown in the main table of the page
79        """
80        url = reverse('projectbuilds', args=(project_id,))
81        self.get(url)
82        self.wait_until_present('#projectbuildstable tbody tr')
83        return self.find_all('#projectbuildstable tbody tr')
84
85    def test_show_builds_for_project(self):
86        """ Builds for a project should be displayed in the main table """
87        Build.objects.create(**self.project1_build_success)
88        Build.objects.create(**self.project1_build_success)
89        build_rows = self._get_rows_for_project(self.project1.id)
90        self.assertEqual(len(build_rows), 2)
91
92    def test_show_builds_project_only(self):
93        """ Builds for other projects should be excluded """
94        Build.objects.create(**self.project1_build_success)
95        Build.objects.create(**self.project1_build_success)
96        Build.objects.create(**self.project1_build_success)
97
98        # shouldn't see these two
99        Build.objects.create(**self.project2_build_success)
100        Build.objects.create(**self.project2_build_in_progress)
101
102        build_rows = self._get_rows_for_project(self.project1.id)
103        self.assertEqual(len(build_rows), 3)
104
105    def test_builds_exclude_in_progress(self):
106        """ "in progress" builds should not be shown in main table """
107        Build.objects.create(**self.project1_build_success)
108        Build.objects.create(**self.project1_build_success)
109
110        # shouldn't see this one
111        Build.objects.create(**self.project1_build_in_progress)
112
113        # shouldn't see these two either, as they belong to a different project
114        Build.objects.create(**self.project2_build_success)
115        Build.objects.create(**self.project2_build_in_progress)
116
117        build_rows = self._get_rows_for_project(self.project1.id)
118        self.assertEqual(len(build_rows), 2)
119
120    def test_show_tasks_with_suffix(self):
121        """ Task should be shown as suffixes on build names """
122        build = Build.objects.create(**self.project1_build_success)
123        target = 'bash'
124        task = 'clean'
125        Target.objects.create(build=build, target=target, task=task)
126
127        url = reverse('projectbuilds', args=(self.project1.id,))
128        self.get(url)
129        self.wait_until_present('td[class="target"]')
130
131        cell = self.find('td[class="target"]')
132        content = cell.get_attribute('innerHTML')
133        expected_text = '%s:%s' % (target, task)
134
135        self.assertTrue(re.search(expected_text, content),
136                        '"target" cell should contain text %s' % expected_text)
137
138    def test_cli_builds_hides_tabs(self):
139        """
140        Display for command line builds should hide tabs
141        """
142        url = reverse('projectbuilds', args=(self.default_project.id,))
143        self.get(url)
144        tabs = self.find_all('#project-topbar')
145        self.assertEqual(len(tabs), 0,
146                         'should be no top bar shown for command line builds')
147
148    def test_non_cli_builds_has_tabs(self):
149        """
150        Non-command-line builds projects should show the tabs
151        """
152        url = reverse('projectbuilds', args=(self.project1.id,))
153        self.get(url)
154        tabs = self.find_all('#project-topbar')
155        self.assertEqual(len(tabs), 1,
156                         'should be a top bar shown for non-command-line builds')
157