Skip to content

Commit 342bc24

Browse files
committed
chore: make selenium container management more reliable
1 parent 0ecdaae commit 342bc24

File tree

7 files changed

+83
-31
lines changed

7 files changed

+83
-31
lines changed

Taskfile.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,19 @@ tasks:
230230
generates:
231231
- out/junit/ui-selenium-test-results.xml
232232
cmds:
233-
- pytest {{.CLI_ARGS}}
233+
- >
234+
pytest
235+
-m=vscode
236+
--cov-branch
237+
--cov-context=test
238+
--cov-report=term-missing
239+
--cov-report=xml:out/coverage/ui-selenium/coverage.xml
240+
--cov=test
241+
--junit-xml=out/junit/ui-selenium-test-results.xml
242+
--no-cov-on-fail
243+
{{.CLI_ARGS}}
244+
# --reruns-delay=120
245+
# --reruns=3
234246
- defer: podman-compose down
235247
interactive: true
236248
unit:

pyproject.toml

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -62,21 +62,7 @@ exclude = "(.ansible|out|syntaxes).*"
6262
[tool.pytest]
6363
# do not add options here as this will likely break either console runs or IDE
6464
# integration like vscode or pycharm
65-
addopts = [
66-
"--cov-branch", # no parallel support with selenium
67-
"--cov-context=test",
68-
"--cov-report=term-missing",
69-
"--cov-report=xml:out/coverage/ui-selenium/coverage.xml",
70-
"--cov=test",
71-
"--durations=10",
72-
"--junit-xml=out/junit/ui-selenium-test-results.xml",
73-
"--no-cov-on-fail",
74-
"--reruns-delay=120",
75-
"--reruns=3",
76-
"-m=vscode",
77-
"-n0",
78-
"-v"
79-
]
65+
addopts = ["--durations-min=10", "--durations=10", "-n0", "-v"]
8066
filterwarnings = [
8167
"error",
8268
"once::pytest.PytestWarning",

test/selenium/conftest.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@
1313

1414
import pytest
1515

16+
from test.selenium.const import CONTAINER_NAME
1617
from test.selenium.utils.ui_utils import LIGHTSPEED_PASSWORD, LIGHTSPEED_USER
1718

1819
# Project root (vscode-ansible), assuming conftest at test/selenium/conftest.py
1920
_PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
2021

21-
logger = logging.getLogger(__name__)
22-
logging.basicConfig(level=logging.WARNING)
22+
logger = logging.getLogger(__package__)
23+
logging.basicConfig(level=logging.WARNING, format="%(levelname)s: %(message)s")
2324

2425
pytest_plugins = [
2526
# For screenshot_on_fail - must be loaded before fixtures that import it
@@ -83,8 +84,26 @@ def pytest_sessionfinish(
8384
session: pytest.Session, exitstatus: pytest.ExitCode
8485
) -> None: # pragma: no cover
8586
"""Teardown the selenium server after tests on CI."""
86-
subprocess.run(
87-
"podman-compose stats --no-stream --no-reset", check=False, shell=True
87+
result = subprocess.run(
88+
f"podman-compose stats --no-stream --no-reset {CONTAINER_NAME}",
89+
text=True,
90+
capture_output=True,
91+
check=False,
92+
shell=True,
8893
)
94+
if result.returncode:
95+
logger.info("podman-compose stats :\n%s\n%s", result.stdout, result.stderr)
8996
if os.environ.get("CI"):
90-
subprocess.run("podman-compose down", check=False, shell=True)
97+
result = subprocess.run(
98+
f"podman stop {CONTAINER_NAME} 2>/dev/null || true",
99+
# Apparently compose down can fail with various errors but stopping container works
100+
# "podman-compose down",
101+
capture_output=True,
102+
check=False,
103+
shell=True,
104+
text=True,
105+
)
106+
if result.returncode != 0:
107+
logger.error(
108+
"Failed to stop selenium server:\n%s\n%s", result.stdout, result.stderr
109+
)

test/selenium/const.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""Constants for the selenium tests."""
2+
3+
CONTAINER_NAME = "selenium-vscode"

test/selenium/fixtures/ui_fixtures.py

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""This module is a fixtures for the ui testing."""
22

3-
# cspell: ignore capmanager capturemanager pluginmanager getplugin
3+
# cspell: ignore capmanager capturemanager pluginmanager getplugin healthcheck
44
# pylint: disable=E0401
55
import contextlib
66
import logging
@@ -16,6 +16,8 @@
1616
from selenium.common import WebDriverException
1717
from selenium.webdriver.remote.webdriver import WebDriver
1818

19+
from test.selenium.const import CONTAINER_NAME
20+
1921
if TYPE_CHECKING:
2022
from _pytest.capture import CaptureManager
2123
from selenium.webdriver.common.options import ArgOptions
@@ -31,7 +33,19 @@
3133
)
3234

3335
# Initialize logging
34-
log = logging.getLogger(__name__)
36+
log = logging.getLogger(__package__)
37+
38+
39+
def is_container_healthy() -> bool:
40+
"""Check if the selenium container is healthy."""
41+
result = subprocess.run(
42+
f"podman healthcheck run {CONTAINER_NAME}",
43+
shell=True,
44+
check=False,
45+
text=True,
46+
capture_output=True,
47+
)
48+
return result.returncode == 0
3549

3650

3751
@pytest.fixture(scope="session")
@@ -46,15 +60,33 @@ def browser_setup(
4660
capmanager: CaptureManager = request.config.pluginmanager.getplugin(
4761
"capturemanager"
4862
) # type: ignore[name-defined]
49-
log.info(
50-
"Starting selenium server at http://localhost:4444 and vnc://localhost:5999"
51-
)
52-
with capmanager.global_and_fixture_disabled():
63+
if not is_container_healthy():
5364
subprocess.run(
54-
"podman-compose up --remove-orphans --timeout 5 -d selenium-vscode",
55-
check=True,
65+
f"podman stop {CONTAINER_NAME} 2>/dev/null || true",
5666
shell=True,
67+
check=False,
68+
text=True,
69+
capture_output=True,
70+
)
71+
log.info(
72+
"Starting selenium server at http://localhost:4444 and vnc://localhost:5999"
5773
)
74+
with capmanager.global_and_fixture_disabled():
75+
subprocess.run(
76+
f"podman-compose up --quiet-pull --remove-orphans --timeout 5 -d {CONTAINER_NAME}",
77+
check=True,
78+
shell=True,
79+
)
80+
count = 0
81+
while True:
82+
if is_container_healthy():
83+
break
84+
count += 1
85+
time.sleep(1)
86+
log.info(
87+
"Waiting for container %s to be healthy: %s", CONTAINER_NAME, count
88+
)
89+
5890
browser = os.environ.get("BROWSER_TYPE")
5991
options: ArgOptions # type: ignore[name-defined]
6092
if browser == "chrome":

test/selenium/ui/test_lightspeed.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def vscode_login_wrapper(driver: Any) -> None:
4545
logged_in_flag = True
4646

4747

48-
@pytest.mark.flaky(reruns=6, reruns_delay=10)
48+
# @pytest.mark.flaky(reruns=6, reruns_delay=10)
4949
@pytest.mark.vscode
5050
def test_vscode_widget(
5151
browser_setup: Any,

test/selenium/utils/settings_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from pathlib import Path
99
from typing import Any
1010

11-
log = logging.getLogger(__name__)
11+
log = logging.getLogger(__package__)
1212

1313
PROJECT_ROOT = Path(__file__).parent.parent.parent.parent
1414
USER_SETTINGS_PATH = PROJECT_ROOT / ".vscode-test/user-data/User/settings.json"

0 commit comments

Comments
 (0)