summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/tests/functional/functional_helpers.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/toaster/tests/functional/functional_helpers.py')
-rw-r--r--bitbake/lib/toaster/tests/functional/functional_helpers.py82
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
11import logging 11import logging
12import subprocess 12import subprocess
13import signal 13import signal
14import time
15import re 14import re
16 15
17from tests.browser.selenium_helpers_base import SeleniumTestCaseBase 16from tests.browser.selenium_helpers_base import SeleniumTestCaseBase
18from tests.builds.buildtest import load_build_environment 17from selenium.webdriver.common.by import By
18from selenium.common.exceptions import NoSuchElementException
19 19
20logger = logging.getLogger("toaster") 20logger = logging.getLogger("toaster")
21toaster_processes = []
21 22
22class SeleniumFunctionalTestCase(SeleniumTestCaseBase): 23class 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