diff options
Diffstat (limited to 'bitbake/lib/toaster/tests/functional/functional_helpers.py')
-rw-r--r-- | bitbake/lib/toaster/tests/functional/functional_helpers.py | 82 |
1 files changed, 55 insertions, 27 deletions
diff --git a/bitbake/lib/toaster/tests/functional/functional_helpers.py b/bitbake/lib/toaster/tests/functional/functional_helpers.py index 5c4ea71794..7c20437d14 100644 --- a/bitbake/lib/toaster/tests/functional/functional_helpers.py +++ b/bitbake/lib/toaster/tests/functional/functional_helpers.py | |||
@@ -11,35 +11,55 @@ import os | |||
11 | import logging | 11 | import logging |
12 | import subprocess | 12 | import subprocess |
13 | import signal | 13 | import signal |
14 | import time | ||
15 | import re | 14 | import re |
16 | 15 | ||
17 | from tests.browser.selenium_helpers_base import SeleniumTestCaseBase | 16 | from tests.browser.selenium_helpers_base import SeleniumTestCaseBase |
18 | from tests.builds.buildtest import load_build_environment | 17 | from selenium.webdriver.common.by import By |
18 | from selenium.common.exceptions import NoSuchElementException | ||
19 | 19 | ||
20 | logger = logging.getLogger("toaster") | 20 | logger = logging.getLogger("toaster") |
21 | toaster_processes = [] | ||
21 | 22 | ||
22 | class SeleniumFunctionalTestCase(SeleniumTestCaseBase): | 23 | class SeleniumFunctionalTestCase(SeleniumTestCaseBase): |
23 | wait_toaster_time = 5 | 24 | wait_toaster_time = 10 |
24 | 25 | ||
25 | @classmethod | 26 | @classmethod |
26 | def setUpClass(cls): | 27 | def setUpClass(cls): |
27 | # So that the buildinfo helper uses the test database' | 28 | # So that the buildinfo helper uses the test database' |
28 | if os.environ.get('DJANGO_SETTINGS_MODULE', '') != \ | 29 | if os.environ.get('DJANGO_SETTINGS_MODULE', '') != \ |
29 | 'toastermain.settings_test': | 30 | 'toastermain.settings_test': |
30 | raise RuntimeError("Please initialise django with the tests settings: " \ | 31 | raise RuntimeError("Please initialise django with the tests settings: " |
31 | "DJANGO_SETTINGS_MODULE='toastermain.settings_test'") | 32 | "DJANGO_SETTINGS_MODULE='toastermain.settings_test'") |
32 | 33 | ||
33 | load_build_environment() | 34 | # Wait for any known toaster processes to exit |
35 | global toaster_processes | ||
36 | for toaster_process in toaster_processes: | ||
37 | try: | ||
38 | os.waitpid(toaster_process, os.WNOHANG) | ||
39 | except ChildProcessError: | ||
40 | pass | ||
34 | 41 | ||
35 | # start toaster | 42 | # start toaster |
36 | cmd = "bash -c 'source toaster start'" | 43 | cmd = "bash -c 'source toaster start'" |
37 | p = subprocess.Popen( | 44 | start_process = subprocess.Popen( |
38 | cmd, | 45 | cmd, |
39 | cwd=os.environ.get("BUILDDIR"), | 46 | cwd=os.environ.get("BUILDDIR"), |
40 | shell=True) | 47 | shell=True) |
41 | if p.wait() != 0: | 48 | toaster_processes = [start_process.pid] |
42 | raise RuntimeError("Can't initialize toaster") | 49 | if start_process.wait() != 0: |
50 | port_use = os.popen("lsof -i -P -n | grep '8000 (LISTEN)'").read().strip() | ||
51 | message = '' | ||
52 | if port_use: | ||
53 | process_id = port_use.split()[1] | ||
54 | process = os.popen(f"ps -o cmd= -p {process_id}").read().strip() | ||
55 | message = f"Port 8000 occupied by {process}" | ||
56 | raise RuntimeError(f"Can't initialize toaster. {message}") | ||
57 | |||
58 | builddir = os.environ.get("BUILDDIR") | ||
59 | with open(os.path.join(builddir, '.toastermain.pid'), 'r') as f: | ||
60 | toaster_processes.append(int(f.read())) | ||
61 | with open(os.path.join(builddir, '.runbuilds.pid'), 'r') as f: | ||
62 | toaster_processes.append(int(f.read())) | ||
43 | 63 | ||
44 | super(SeleniumFunctionalTestCase, cls).setUpClass() | 64 | super(SeleniumFunctionalTestCase, cls).setUpClass() |
45 | cls.live_server_url = 'http://localhost:8000/' | 65 | cls.live_server_url = 'http://localhost:8000/' |
@@ -48,22 +68,30 @@ class SeleniumFunctionalTestCase(SeleniumTestCaseBase): | |||
48 | def tearDownClass(cls): | 68 | def tearDownClass(cls): |
49 | super(SeleniumFunctionalTestCase, cls).tearDownClass() | 69 | super(SeleniumFunctionalTestCase, cls).tearDownClass() |
50 | 70 | ||
51 | # XXX: source toaster stop gets blocked, to review why? | 71 | global toaster_processes |
52 | # from now send SIGTERM by hand | ||
53 | time.sleep(cls.wait_toaster_time) | ||
54 | builddir = os.environ.get("BUILDDIR") | ||
55 | 72 | ||
56 | with open(os.path.join(builddir, '.toastermain.pid'), 'r') as f: | 73 | cmd = "bash -c 'source toaster stop'" |
57 | toastermain_pid = int(f.read()) | 74 | stop_process = subprocess.Popen( |
58 | os.kill(toastermain_pid, signal.SIGTERM) | 75 | cmd, |
59 | with open(os.path.join(builddir, '.runbuilds.pid'), 'r') as f: | 76 | cwd=os.environ.get("BUILDDIR"), |
60 | runbuilds_pid = int(f.read()) | 77 | shell=True) |
61 | os.kill(runbuilds_pid, signal.SIGTERM) | 78 | # Toaster stop has been known to hang in these tests so force kill if it stalls |
79 | try: | ||
80 | if stop_process.wait(cls.wait_toaster_time) != 0: | ||
81 | raise Exception('Toaster stop process failed') | ||
82 | except Exception as e: | ||
83 | if e is subprocess.TimeoutExpired: | ||
84 | print('Toaster stop process took too long. Force killing toaster...') | ||
85 | else: | ||
86 | print('Toaster stop process failed. Force killing toaster...') | ||
87 | stop_process.kill() | ||
88 | for toaster_process in toaster_processes: | ||
89 | os.kill(toaster_process, signal.SIGTERM) | ||
62 | 90 | ||
63 | 91 | ||
64 | def get_URL(self): | 92 | def get_URL(self): |
65 | rc=self.get_page_source() | 93 | rc=self.get_page_source() |
66 | project_url=re.search("(projectPageUrl\s:\s\")(.*)(\",)",rc) | 94 | project_url=re.search(r"(projectPageUrl\s:\s\")(.*)(\",)",rc) |
67 | return project_url.group(2) | 95 | return project_url.group(2) |
68 | 96 | ||
69 | 97 | ||
@@ -74,8 +102,8 @@ class SeleniumFunctionalTestCase(SeleniumTestCaseBase): | |||
74 | """ | 102 | """ |
75 | try: | 103 | try: |
76 | table_element = self.get_table_element(table_id) | 104 | table_element = self.get_table_element(table_id) |
77 | element = table_element.find_element_by_link_text(link_text) | 105 | element = table_element.find_element(By.LINK_TEXT, link_text) |
78 | except self.NoSuchElementException: | 106 | except NoSuchElementException: |
79 | print('no element found') | 107 | print('no element found') |
80 | raise | 108 | raise |
81 | return element | 109 | return element |
@@ -85,8 +113,8 @@ class SeleniumFunctionalTestCase(SeleniumTestCaseBase): | |||
85 | #return whole-table element | 113 | #return whole-table element |
86 | element_xpath = "//*[@id='" + table_id + "']" | 114 | element_xpath = "//*[@id='" + table_id + "']" |
87 | try: | 115 | try: |
88 | element = self.driver.find_element_by_xpath(element_xpath) | 116 | element = self.driver.find_element(By.XPATH, element_xpath) |
89 | except self.NoSuchElementException: | 117 | except NoSuchElementException: |
90 | raise | 118 | raise |
91 | return element | 119 | return element |
92 | row = coordinate[0] | 120 | row = coordinate[0] |
@@ -95,8 +123,8 @@ class SeleniumFunctionalTestCase(SeleniumTestCaseBase): | |||
95 | #return whole-row element | 123 | #return whole-row element |
96 | element_xpath = "//*[@id='" + table_id + "']/tbody/tr[" + str(row) + "]" | 124 | element_xpath = "//*[@id='" + table_id + "']/tbody/tr[" + str(row) + "]" |
97 | try: | 125 | try: |
98 | element = self.driver.find_element_by_xpath(element_xpath) | 126 | element = self.driver.find_element(By.XPATH, element_xpath) |
99 | except self.NoSuchElementException: | 127 | except NoSuchElementException: |
100 | return False | 128 | return False |
101 | return element | 129 | return element |
102 | #now we are looking for an element with specified X and Y | 130 | #now we are looking for an element with specified X and Y |
@@ -104,7 +132,7 @@ class SeleniumFunctionalTestCase(SeleniumTestCaseBase): | |||
104 | 132 | ||
105 | element_xpath = "//*[@id='" + table_id + "']/tbody/tr[" + str(row) + "]/td[" + str(column) + "]" | 133 | element_xpath = "//*[@id='" + table_id + "']/tbody/tr[" + str(row) + "]/td[" + str(column) + "]" |
106 | try: | 134 | try: |
107 | element = self.driver.find_element_by_xpath(element_xpath) | 135 | element = self.driver.find_element(By.XPATH, element_xpath) |
108 | except self.NoSuchElementException: | 136 | except NoSuchElementException: |
109 | return False | 137 | return False |
110 | return element | 138 | return element |