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