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