From patchwork Thu Dec 14 14:21:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Lussier-Cullen X-Patchwork-Id: 36257 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id D054EC4167B for ; Thu, 14 Dec 2023 14:22:08 +0000 (UTC) Received: from mail.savoirfairelinux.com (mail.savoirfairelinux.com [208.88.110.44]) by mx.groups.io with SMTP id smtpd.web11.23352.1702563718658824443 for ; Thu, 14 Dec 2023 06:21:59 -0800 Authentication-Results: mx.groups.io; dkim=pass header.i=@savoirfairelinux.com header.s=DFC430D2-D198-11EC-948E-34200CB392D2 header.b=aoBKf6mA; spf=pass (domain: savoirfairelinux.com, ip: 208.88.110.44, mailfrom: alexander.lussier-cullen@savoirfairelinux.com) Received: from localhost (localhost [127.0.0.1]) by mail.savoirfairelinux.com (Postfix) with ESMTP id 2D6D19C4029 for ; Thu, 14 Dec 2023 09:21:57 -0500 (EST) Received: from mail.savoirfairelinux.com ([127.0.0.1]) by localhost (mail.savoirfairelinux.com [127.0.0.1]) (amavis, port 10032) with ESMTP id WkRrbT5omloB; Thu, 14 Dec 2023 09:21:56 -0500 (EST) Received: from localhost (localhost [127.0.0.1]) by mail.savoirfairelinux.com (Postfix) with ESMTP id 5CA1D9C3A2E; Thu, 14 Dec 2023 09:21:56 -0500 (EST) DKIM-Filter: OpenDKIM Filter v2.10.3 mail.savoirfairelinux.com 5CA1D9C3A2E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=savoirfairelinux.com; s=DFC430D2-D198-11EC-948E-34200CB392D2; t=1702563716; bh=9fpYsI++ZACZ/p39qUu9Q5A0QgY2FtdVEBPE88UEWfs=; h=From:To:Date:Message-Id:MIME-Version; b=aoBKf6mAUaaPCELSYOshPwtWVOZsoPAIjE9Z1vOR1AxRYQbnquSQMcJBEunNW7XtA fxDi3aMF5s4s8cEKKdvik7WMTIcEcz9wsbppptRrfEX2EVJnqF6+t0aBjYnHyp5gKz Km+B61e60w/2SmzIEeiijReDPfVKJtr5BqekqCKMjbCy+LEYliyDRkW6pIpHOiz988 hxBEaPaYC5fuFsiLWwixWd8FPDDNLqbiIVnAkj3SmLxzGp+Zwit6JrPAJmF/JIGtb3 k1CFpiEfQEnkdzJquGXdZ4OvA/M2n0BwR2ETDLbI+acVwYJ3EjldD4/zX3w1MNEJAb oJX0SyAGDaBNg== X-Virus-Scanned: amavis at mail.savoirfairelinux.com Received: from mail.savoirfairelinux.com ([127.0.0.1]) by localhost (mail.savoirfairelinux.com [127.0.0.1]) (amavis, port 10026) with ESMTP id OEKOaGubN4j9; Thu, 14 Dec 2023 09:21:56 -0500 (EST) Received: from ubuntu.home (bras-base-mtrlpq427kw-grc-24-184-147-255-35.dsl.bell.ca [184.147.255.35]) by mail.savoirfairelinux.com (Postfix) with ESMTPSA id 427989C4029; Thu, 14 Dec 2023 09:21:56 -0500 (EST) From: alexander.lussier-cullen@savoirfairelinux.com To: toaster@lists.yoctoproject.org Cc: Alexander Lussier-Cullen Subject: [Toaster] toaster: fix functional tests setup and teardown Date: Thu, 14 Dec 2023 09:21:43 -0500 Message-Id: <20231214142143.8363-1-alexander.lussier-cullen@savoirfairelinux.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Thu, 14 Dec 2023 14:22:08 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/toaster/message/6093 From: Alexander Lussier-Cullen 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. Signed-off-by: Alexander Lussier-Cullen --- .../tests/functional/functional_helpers.py | 51 ++++++++++++++----- 1 file 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 from selenium.common.exceptions import NoSuchElementException logger = logging.getLogger("toaster") +toaster_processes = [] class SeleniumFunctionalTestCase(SeleniumTestCaseBase): - wait_toaster_time = 5 + wait_toaster_time = 10 @classmethod def setUpClass(cls): @@ -31,13 +32,22 @@ class SeleniumFunctionalTestCase(SeleniumTestCaseBase): raise RuntimeError("Please initialise django with the tests settings: " "DJANGO_SETTINGS_MODULE='toastermain.settings_test'") + # Wait for any known toaster processes to exit + global toaster_processes + for toaster_process in toaster_processes: + try: + os.waitpid(toaster_process, os.WNOHANG) + except ChildProcessError: + pass + # start toaster cmd = "bash -c 'source toaster start'" - cls.p = subprocess.Popen( + start_process = subprocess.Popen( cmd, cwd=os.environ.get("BUILDDIR"), shell=True) - if cls.p.wait() != 0: + toaster_processes = [start_process.pid] + if start_process.wait() != 0: port_use = os.popen("lsof -i -P -n | grep '8000 (LISTEN)'").read().strip() message = '' if port_use: @@ -46,6 +56,12 @@ class SeleniumFunctionalTestCase(SeleniumTestCaseBase): message = f"Port 8000 occupied by {process}" raise RuntimeError(f"Can't initialize toaster. {message}") + builddir = os.environ.get("BUILDDIR") + with open(os.path.join(builddir, '.toastermain.pid'), 'r') as f: + toaster_processes.append(int(f.read())) + with open(os.path.join(builddir, '.runbuilds.pid'), 'r') as f: + toaster_processes.append(int(f.read())) + super(SeleniumFunctionalTestCase, cls).setUpClass() cls.live_server_url = 'http://localhost:8000/' @@ -53,18 +69,25 @@ class SeleniumFunctionalTestCase(SeleniumTestCaseBase): def tearDownClass(cls): super(SeleniumFunctionalTestCase, cls).tearDownClass() - # XXX: source toaster stop gets blocked, to review why? - # from now send SIGTERM by hand - time.sleep(cls.wait_toaster_time) - builddir = os.environ.get("BUILDDIR") + global toaster_processes - with open(os.path.join(builddir, '.toastermain.pid'), 'r') as f: - toastermain_pid = int(f.read()) - os.kill(toastermain_pid, signal.SIGTERM) - with open(os.path.join(builddir, '.runbuilds.pid'), 'r') as f: - runbuilds_pid = int(f.read()) - os.kill(runbuilds_pid, signal.SIGTERM) - cls.p.kill() + cmd = "bash -c 'source toaster stop'" + stop_process = subprocess.Popen( + cmd, + cwd=os.environ.get("BUILDDIR"), + shell=True) + # Toaster stop has been known to hang in these tests so force kill if it stalls + try: + if stop_process.wait(cls.wait_toaster_time) != 0: + raise Exception('Toaster stop process failed') + except Exception as e: + if e is subprocess.TimeoutExpired: + print('Toaster stop process took too long. Force killing toaster...') + else: + print('Toaster stop process failed. Force killing toaster...') + stop_process.kill() + for toaster_process in toaster_processes: + os.kill(toaster_process, signal.SIGTERM) def get_URL(self):