summaryrefslogtreecommitdiffstats
path: root/bitbake
diff options
context:
space:
mode:
authorAlexander Lussier-Cullen <alexander.lussier-cullen@savoirfairelinux.com>2023-12-14 09:21:43 -0500
committerRichard Purdie <richard.purdie@linuxfoundation.org>2023-12-15 14:37:28 +0000
commite63d6cb38ef63ccb64756ae225f2f38722137efd (patch)
tree299b1bc08c966d566c11dd4a10ccdb55ee79af15 /bitbake
parente9c2003bd0802dfd5221660eb808d4cde18d3a44 (diff)
downloadpoky-e63d6cb38ef63ccb64756ae225f2f38722137efd.tar.gz
bitbake: toaster/tests: fix functional tests setup and teardown
Functional tests sometimes do not properly wait for previous tests to close their instance of Toaster before launching their own, which causes failures. Track test created Toaster processes globally and wait for them to be exited before executing further tests which need a Toaster instance to fix this. Additionally, quit Toaster in the teardown using the stop command with a fallback of manually killing the processes in case of documented stalling problem. (Bitbake rev: 16aad11ce8eadd93b4b00dc65826329ff5526c84) Signed-off-by: Alexander Lussier-Cullen <alexander.lussier-cullen@savoirfairelinux.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake')
-rw-r--r--bitbake/lib/toaster/tests/functional/functional_helpers.py51
1 files changed, 37 insertions, 14 deletions
diff --git a/bitbake/lib/toaster/tests/functional/functional_helpers.py b/bitbake/lib/toaster/tests/functional/functional_helpers.py
index 09cf3ba8e0..6039d736e9 100644
--- a/bitbake/lib/toaster/tests/functional/functional_helpers.py
+++ b/bitbake/lib/toaster/tests/functional/functional_helpers.py
@@ -19,9 +19,10 @@ from selenium.webdriver.common.by import By
19from selenium.common.exceptions import NoSuchElementException 19from selenium.common.exceptions import NoSuchElementException
20 20
21logger = logging.getLogger("toaster") 21logger = logging.getLogger("toaster")
22toaster_processes = []
22 23
23class SeleniumFunctionalTestCase(SeleniumTestCaseBase): 24class SeleniumFunctionalTestCase(SeleniumTestCaseBase):
24 wait_toaster_time = 5 25 wait_toaster_time = 10
25 26
26 @classmethod 27 @classmethod
27 def setUpClass(cls): 28 def setUpClass(cls):
@@ -31,13 +32,22 @@ class SeleniumFunctionalTestCase(SeleniumTestCaseBase):
31 raise RuntimeError("Please initialise django with the tests settings: " 32 raise RuntimeError("Please initialise django with the tests settings: "
32 "DJANGO_SETTINGS_MODULE='toastermain.settings_test'") 33 "DJANGO_SETTINGS_MODULE='toastermain.settings_test'")
33 34
35 # Wait for any known toaster processes to exit
36 global toaster_processes
37 for toaster_process in toaster_processes:
38 try:
39 os.waitpid(toaster_process, os.WNOHANG)
40 except ChildProcessError:
41 pass
42
34 # start toaster 43 # start toaster
35 cmd = "bash -c 'source toaster start'" 44 cmd = "bash -c 'source toaster start'"
36 cls.p = subprocess.Popen( 45 start_process = subprocess.Popen(
37 cmd, 46 cmd,
38 cwd=os.environ.get("BUILDDIR"), 47 cwd=os.environ.get("BUILDDIR"),
39 shell=True) 48 shell=True)
40 if cls.p.wait() != 0: 49 toaster_processes = [start_process.pid]
50 if start_process.wait() != 0:
41 port_use = os.popen("lsof -i -P -n | grep '8000 (LISTEN)'").read().strip() 51 port_use = os.popen("lsof -i -P -n | grep '8000 (LISTEN)'").read().strip()
42 message = '' 52 message = ''
43 if port_use: 53 if port_use:
@@ -46,6 +56,12 @@ class SeleniumFunctionalTestCase(SeleniumTestCaseBase):
46 message = f"Port 8000 occupied by {process}" 56 message = f"Port 8000 occupied by {process}"
47 raise RuntimeError(f"Can't initialize toaster. {message}") 57 raise RuntimeError(f"Can't initialize toaster. {message}")
48 58
59 builddir = os.environ.get("BUILDDIR")
60 with open(os.path.join(builddir, '.toastermain.pid'), 'r') as f:
61 toaster_processes.append(int(f.read()))
62 with open(os.path.join(builddir, '.runbuilds.pid'), 'r') as f:
63 toaster_processes.append(int(f.read()))
64
49 super(SeleniumFunctionalTestCase, cls).setUpClass() 65 super(SeleniumFunctionalTestCase, cls).setUpClass()
50 cls.live_server_url = 'http://localhost:8000/' 66 cls.live_server_url = 'http://localhost:8000/'
51 67
@@ -53,18 +69,25 @@ class SeleniumFunctionalTestCase(SeleniumTestCaseBase):
53 def tearDownClass(cls): 69 def tearDownClass(cls):
54 super(SeleniumFunctionalTestCase, cls).tearDownClass() 70 super(SeleniumFunctionalTestCase, cls).tearDownClass()
55 71
56 # XXX: source toaster stop gets blocked, to review why? 72 global toaster_processes
57 # from now send SIGTERM by hand
58 time.sleep(cls.wait_toaster_time)
59 builddir = os.environ.get("BUILDDIR")
60 73
61 with open(os.path.join(builddir, '.toastermain.pid'), 'r') as f: 74 cmd = "bash -c 'source toaster stop'"
62 toastermain_pid = int(f.read()) 75 stop_process = subprocess.Popen(
63 os.kill(toastermain_pid, signal.SIGTERM) 76 cmd,
64 with open(os.path.join(builddir, '.runbuilds.pid'), 'r') as f: 77 cwd=os.environ.get("BUILDDIR"),
65 runbuilds_pid = int(f.read()) 78 shell=True)
66 os.kill(runbuilds_pid, signal.SIGTERM) 79 # Toaster stop has been known to hang in these tests so force kill if it stalls
67 cls.p.kill() 80 try:
81 if stop_process.wait(cls.wait_toaster_time) != 0:
82 raise Exception('Toaster stop process failed')
83 except Exception as e:
84 if e is subprocess.TimeoutExpired:
85 print('Toaster stop process took too long. Force killing toaster...')
86 else:
87 print('Toaster stop process failed. Force killing toaster...')
88 stop_process.kill()
89 for toaster_process in toaster_processes:
90 os.kill(toaster_process, signal.SIGTERM)
68 91
69 92
70 def get_URL(self): 93 def get_URL(self):