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#
9
10from django.urls import reverse
11from selenium.common.exceptions import ElementClickInterceptedException, TimeoutException
12from tests.browser.selenium_helpers import SeleniumTestCase
13
14from orm.models import Layer, Layer_Version, Project, LayerSource, Release
15from orm.models import BitbakeVersion
16
17from selenium.webdriver.support import expected_conditions as EC
18from selenium.webdriver.support.ui import WebDriverWait
19from selenium.webdriver.common.by import By
20
21
22class TestLayerDetailsPage(SeleniumTestCase):
23    """ Test layerdetails page works correctly """
24
25    def __init__(self, *args, **kwargs):
26        super(TestLayerDetailsPage, self).__init__(*args, **kwargs)
27
28        self.initial_values = None
29        self.url = None
30        self.imported_layer_version = None
31
32    def setUp(self):
33        release = Release.objects.create(
34            name='baz',
35            bitbake_version=BitbakeVersion.objects.create(name='v1')
36        )
37
38        # project to add new custom images to
39        self.project = Project.objects.create(name='foo', release=release)
40
41        name = "meta-imported"
42        vcs_url = "git://example.com/meta-imported"
43        subdir = "/layer"
44        gitrev = "d33d"
45        summary = "A imported layer"
46        description = "This was imported"
47
48        imported_layer = Layer.objects.create(name=name,
49                                              vcs_url=vcs_url,
50                                              summary=summary,
51                                              description=description)
52
53        self.imported_layer_version = Layer_Version.objects.create(
54            layer=imported_layer,
55            layer_source=LayerSource.TYPE_IMPORTED,
56            branch=gitrev,
57            commit=gitrev,
58            dirpath=subdir,
59            project=self.project)
60
61        self.initial_values = [name, vcs_url, subdir, gitrev, summary,
62                               description]
63        self.url = reverse('layerdetails',
64                           args=(self.project.pk,
65                                 self.imported_layer_version.pk))
66
67    def _edit_layerdetails(self):
68        """ Edit all the editable fields for the layer refresh the page and
69        check that the new values exist"""
70
71        self.get(self.url)
72        self.wait_until_visible("#add-remove-layer-btn")
73
74        self.click("#add-remove-layer-btn")
75        self.click("#edit-layer-source")
76        self.click("#repo")
77
78        self.wait_until_visible("#layer-git-repo-url")
79
80        # Open every edit box
81        for btn in self.find_all("dd .glyphicon-edit"):
82            btn.click()
83
84        # Wait for the inputs to become visible after animation
85        self.wait_until_visible("#layer-git input[type=text]")
86        self.wait_until_visible("dd textarea")
87        self.wait_until_visible("dd .change-btn")
88
89        # Edit each value
90        for inputs in self.find_all("#layer-git input[type=text]") + \
91                self.find_all("dd textarea"):
92            # ignore the tt inputs (twitter typeahead input)
93            if "tt-" in inputs.get_attribute("class"):
94                continue
95
96            value = inputs.get_attribute("value")
97
98            self.assertTrue(value in self.initial_values,
99                            "Expecting any of \"%s\"but got \"%s\"" %
100                            (self.initial_values, value))
101
102            # Make sure the input visible beofre sending keys
103            self.wait_until_visible("#layer-git input[type=text]")
104            inputs.send_keys("-edited")
105
106        # Save the new values
107        for save_btn in self.find_all(".change-btn"):
108            save_btn.click()
109
110        try:
111            self.wait_until_visible("#save-changes-for-switch", poll=3)
112            btn_save_chg_for_switch = self.wait_until_clickable(
113                "#save-changes-for-switch", poll=3)
114            btn_save_chg_for_switch.click()
115        except ElementClickInterceptedException:
116            self.skipTest(
117                "save-changes-for-switch click intercepted. Element not visible or maybe covered by another element.")
118        except TimeoutException:
119            self.skipTest(
120                "save-changes-for-switch is not clickable within the specified timeout.")
121
122        self.wait_until_visible("#edit-layer-source")
123
124        # Refresh the page to see if the new values are returned
125        self.get(self.url)
126
127        new_values = ["%s-edited" % old_val
128                      for old_val in self.initial_values]
129
130        for inputs in self.find_all('#layer-git input[type="text"]') + \
131                self.find_all('dd textarea'):
132            # ignore the tt inputs (twitter typeahead input)
133            if "tt-" in inputs.get_attribute("class"):
134                continue
135
136            value = inputs.get_attribute("value")
137
138            self.assertTrue(value in new_values,
139                            "Expecting any of \"%s\" but got \"%s\"" %
140                            (new_values, value))
141
142        # Now convert it to a local layer
143        self.click("#edit-layer-source")
144        self.click("#dir")
145        dir_input = self.wait_until_visible("#layer-dir-path-in-details")
146
147        new_dir = "/home/test/my-meta-dir"
148        dir_input.send_keys(new_dir)
149
150        try:
151            self.wait_until_visible("#save-changes-for-switch", poll=3)
152            btn_save_chg_for_switch = self.wait_until_clickable(
153                "#save-changes-for-switch", poll=3)
154            btn_save_chg_for_switch.click()
155        except ElementClickInterceptedException:
156            self.skipTest(
157                "save-changes-for-switch click intercepted. Element not properly visible or maybe behind another element.")
158        except TimeoutException:
159            self.skipTest(
160                "save-changes-for-switch is not clickable within the specified timeout.")
161
162        self.wait_until_visible("#edit-layer-source")
163
164        # Refresh the page to see if the new values are returned
165        self.get(self.url)
166        dir_input = self.find("#layer-dir-path-in-details")
167        self.assertTrue(new_dir in dir_input.get_attribute("value"),
168                        "Expected %s in the dir value for layer directory" %
169                        new_dir)
170
171    def test_edit_layerdetails_page(self):
172        try:
173            self._edit_layerdetails()
174        except ElementClickInterceptedException:
175            self.skipTest(
176                "ElementClickInterceptedException occured. Element not visible or maybe covered by another element.")
177
178    def test_delete_layer(self):
179        """ Delete the layer """
180
181        self.get(self.url)
182
183        # Wait for the tables to load to avoid a race condition where the
184        # toaster tables have made an async request. If the layer is deleted
185        # before the request finishes it will cause an exception and fail this
186        # test.
187        wait = WebDriverWait(self.driver, 30)
188
189        wait.until(EC.text_to_be_present_in_element(
190            (By.CLASS_NAME,
191             "table-count-recipestable"), "0"))
192
193        wait.until(EC.text_to_be_present_in_element(
194            (By.CLASS_NAME,
195             "table-count-machinestable"), "0"))
196
197        self.click('a[data-target="#delete-layer-modal"]')
198        self.wait_until_visible("#delete-layer-modal")
199        self.click("#layer-delete-confirmed")
200
201        notification = self.wait_until_visible("#change-notification-msg")
202        expected_text = "You have deleted 1 layer from your project: %s" % \
203            self.imported_layer_version.layer.name
204
205        self.assertTrue(expected_text in notification.text,
206                        "Expected notification text \"%s\" not found instead"
207                        "it was \"%s\"" %
208                        (expected_text, notification.text))
209
210    def test_addrm_to_project(self):
211        self.get(self.url)
212
213        # Add the layer
214        self.click("#add-remove-layer-btn")
215
216        notification = self.wait_until_visible("#change-notification-msg")
217
218        expected_text = "You have added 1 layer to your project: %s" % \
219            self.imported_layer_version.layer.name
220
221        self.assertTrue(expected_text in notification.text,
222                        "Expected notification text %s not found was "
223                        " \"%s\" instead" %
224                        (expected_text, notification.text))
225
226        # Remove the layer
227        self.click("#add-remove-layer-btn")
228
229        notification = self.wait_until_visible("#change-notification-msg")
230
231        expected_text = "You have removed 1 layer from your project: %s" % \
232            self.imported_layer_version.layer.name
233
234        self.assertTrue(expected_text in notification.text,
235                        "Expected notification text %s not found was "
236                        " \"%s\" instead" %
237                        (expected_text, notification.text))
238