Skip to content

Commit 54ca634

Browse files
authored
ISSUE #887: add fixtures to skip test if it's not jupyterlab/codeserver/rstudio image (#918)
1 parent 1703ea2 commit 54ca634

File tree

4 files changed

+68
-50
lines changed

4 files changed

+68
-50
lines changed

tests/containers/conftest.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010

1111
import pytest
1212

13+
import docker.errors
14+
import docker.models.images
15+
import docker.types
16+
1317
from tests.containers import docker_utils
1418

1519
if TYPE_CHECKING:
@@ -45,13 +49,65 @@ def pytest_generate_tests(metafunc: Metafunc) -> None:
4549
metafunc.parametrize(image.__name__, metafunc.config.getoption("--image"))
4650

4751

52+
def skip_if_not_workbench_image(image: str) -> docker.models.images.Image:
53+
client = testcontainers.core.container.DockerClient()
54+
try:
55+
image_metadata = client.client.images.get(image)
56+
except docker.errors.ImageNotFound:
57+
image_metadata = client.client.images.pull(image)
58+
assert isinstance(image_metadata, docker.models.images.Image)
59+
60+
ide_server_label_fragments = ('-code-server-', '-jupyter-', '-rstudio-')
61+
if not any(ide in image_metadata.labels['name'] for ide in ide_server_label_fragments):
62+
pytest.skip(
63+
f"Image {image} does not have any of '{ide_server_label_fragments=} in {image_metadata.labels['name']=}'")
64+
65+
return image_metadata
66+
67+
4868
# https://docs.pytest.org/en/stable/how-to/fixtures.html#parametrizing-fixtures
4969
# indirect parametrization https://stackoverflow.com/questions/18011902/how-to-pass-a-parameter-to-a-fixture-function-in-pytest
5070
@pytest.fixture(scope="session")
5171
def image(request):
5272
yield request.param
5373

5474

75+
@pytest.fixture(scope="function")
76+
def workbench_image(image: str):
77+
skip_if_not_workbench_image(image)
78+
yield image
79+
80+
81+
@pytest.fixture(scope="function")
82+
def jupyterlab_image(image: str):
83+
image_metadata = skip_if_not_workbench_image(image)
84+
if "-jupyter-" not in image_metadata.labels['name']:
85+
pytest.skip(
86+
f"Image {image} does not have '-jupyter-' in {image_metadata.labels['name']=}'")
87+
88+
return image_metadata
89+
90+
91+
@pytest.fixture(scope="function")
92+
def rstudio_image(image: str):
93+
image_metadata = skip_if_not_workbench_image(image)
94+
if "-rstudio-" not in image_metadata.labels['name']:
95+
pytest.skip(
96+
f"Image {image} does not have '-rstudio-' in {image_metadata.labels['name']=}'")
97+
98+
return image_metadata
99+
100+
101+
@pytest.fixture(scope="function")
102+
def codeserver_image(image: str):
103+
image_metadata = skip_if_not_workbench_image(image)
104+
if "-code-server-" not in image_metadata.labels['name']:
105+
pytest.skip(
106+
f"Image {image} does not have '-code-server-' in {image_metadata.labels['name']=}'")
107+
108+
return image_metadata
109+
110+
55111
# https://docs.pytest.org/en/latest/reference/reference.html#pytest.hookspec.pytest_sessionstart
56112
def pytest_sessionstart(session: Session) -> None:
57113
# first preflight check: ping the Docker API

tests/containers/workbenches/jupyterlab/jupyterlab_test.py

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import pytest
99

1010
from tests.containers import docker_utils
11-
from tests.containers.workbenches.workbench_image_test import WorkbenchContainer, skip_if_not_workbench_image
11+
from tests.containers.workbenches.workbench_image_test import WorkbenchContainer
1212

1313
if TYPE_CHECKING:
1414
import docker.models.images
@@ -21,10 +21,9 @@ class TestJupyterLabImage:
2121

2222
@allure.issue("RHOAIENG-11156")
2323
@allure.description("Check that the HTML for the spinner is contained in the initial page.")
24-
def test_spinner_html_loaded(self, image: str) -> None:
25-
skip_if_not_jupyterlab_image(image)
24+
def test_spinner_html_loaded(self, jupyterlab_image: str) -> None:
2625

27-
container = WorkbenchContainer(image=image, user=4321, group_add=[0])
26+
container = WorkbenchContainer(image=jupyterlab_image, user=4321, group_add=[0])
2827
# if no env is specified, the image will run
2928
# > 4321 3334 3319 0 10:36 pts/0 00:00:01 /mnt/rosetta /opt/app-root/bin/python3.11 /opt/app-root/bin/jupyter-lab
3029
# > --ServerApp.root_dir=/opt/app-root/src --ServerApp.ip= --ServerApp.allow_origin=* --ServerApp.open_browser=False
@@ -52,12 +51,3 @@ def test_spinner_html_loaded(self, image: str) -> None:
5251
assert 'class="pf-v6-c-spinner"' in response.text
5352
finally:
5453
docker_utils.NotebookContainer(container).stop(timeout=0)
55-
56-
57-
def skip_if_not_jupyterlab_image(image: str) -> docker.models.images.Image:
58-
image_metadata = skip_if_not_workbench_image(image)
59-
if "-jupyter-" not in image_metadata.labels['name']:
60-
pytest.skip(
61-
f"Image {image} does not have '-jupyter-' in {image_metadata.labels['name']=}'")
62-
63-
return image_metadata

tests/containers/workbenches/rstudio/rstudio_test.py

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import pytest
1414

1515
from tests.containers import docker_utils
16-
from tests.containers.workbenches.workbench_image_test import WorkbenchContainer, skip_if_not_workbench_image
16+
from tests.containers.workbenches.workbench_image_test import WorkbenchContainer
1717

1818
if TYPE_CHECKING:
1919
import docker.models.images
@@ -25,15 +25,13 @@ class TestRStudioImage:
2525
APP_ROOT_HOME = "/opt/app-root/src"
2626

2727
@allure.issue("RHOAIENG-17256")
28-
def test_rmd_to_pdf_rendering(self, image: str) -> None:
28+
def test_rmd_to_pdf_rendering(self, rstudio_image: str) -> None:
2929
"""
3030
References:
3131
https://stackoverflow.com/questions/40563479/relationship-between-r-markdown-knitr-pandoc-and-bookdown
3232
https://www.earthdatascience.org/courses/earth-analytics/document-your-science/knit-rmarkdown-document-to-pdf/
3333
"""
34-
skip_if_not_rstudio_image(image)
35-
36-
container = WorkbenchContainer(image=image, user=1000, group_add=[0])
34+
container = WorkbenchContainer(image=rstudio_image, user=1000, group_add=[0])
3735
try:
3836
container.start(wait_for_readiness=False)
3937

@@ -101,12 +99,11 @@ def test_rmd_to_pdf_rendering(self, image: str) -> None:
10199
docker_utils.NotebookContainer(container).stop(timeout=0)
102100

103101
@allure.issue("RHOAIENG-16604")
104-
def test_http_proxy_env_propagates(self, image: str, subtests: pytest_subtests.plugin.SubTests) -> None:
102+
def test_http_proxy_env_propagates(self, rstudio_image: str, subtests: pytest_subtests.plugin.SubTests) -> None:
105103
"""
106104
This checks that the lowercased proxy configuration is propagated into the RStudio
107105
environment so that the appropriate values are then accepted and followed.
108106
"""
109-
skip_if_not_rstudio_image(image)
110107

111108
class TestCase(NamedTuple):
112109
name: str
@@ -119,7 +116,7 @@ class TestCase(NamedTuple):
119116
TestCase("NO_PROXY", "no_proxy", "google.com"),
120117
]
121118

122-
container = WorkbenchContainer(image=image, user=1000, group_add=[0])
119+
container = WorkbenchContainer(image=rstudio_image, user=1000, group_add=[0])
123120
for tc in test_cases:
124121
container.with_env(tc.name, tc.value)
125122

@@ -160,15 +157,6 @@ def check_output(container: WorkbenchContainer, cmd: str) -> str:
160157
return result
161158

162159

163-
def skip_if_not_rstudio_image(image: str) -> docker.models.images.Image:
164-
image_metadata = skip_if_not_workbench_image(image)
165-
if "-rstudio-" not in image_metadata.labels['name']:
166-
pytest.skip(
167-
f"Image {image} does not have '-rstudio-' in {image_metadata.labels['name']=}'")
168-
169-
return image_metadata
170-
171-
172160
class StructuredMessage:
173161
"""https://docs.python.org/3/howto/logging-cookbook.html#implementing-structured-logging"""
174162

tests/containers/workbenches/workbench_image_test.py

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,9 @@ class TestWorkbenchImage:
3333
# disable ipv6 https://danwalsh.livejournal.com/47118.html
3434
{"net.ipv6.conf.all.disable_ipv6": "1"}
3535
])
36-
def test_image_entrypoint_starts(self, subtests: pytest_subtests.SubTests, image: str, sysctls) -> None:
37-
skip_if_not_workbench_image(image)
36+
def test_image_entrypoint_starts(self, subtests: pytest_subtests.SubTests, workbench_image: str, sysctls) -> None:
3837

39-
container = WorkbenchContainer(image=image, user=1000, group_add=[0],
38+
container = WorkbenchContainer(image=workbench_image, user=1000, group_add=[0],
4039
sysctls=sysctls)
4140
try:
4241
try:
@@ -51,10 +50,9 @@ def test_image_entrypoint_starts(self, subtests: pytest_subtests.SubTests, image
5150
docker_utils.NotebookContainer(container).stop(timeout=0)
5251

5352
@pytest.mark.skip(reason="RHOAIENG-17305: currently our Workbench images don't tolerate IPv6")
54-
def test_ipv6_only(self, subtests: pytest_subtests.SubTests, image: str, test_frame):
53+
def test_ipv6_only(self, subtests: pytest_subtests.SubTests, workbench_image: str, test_frame):
5554
"""Test that workbench image is accessible via IPv6.
5655
Workarounds for macOS will be needed, so that's why it's a separate test."""
57-
skip_if_not_workbench_image(image)
5856

5957
# network is made ipv6 by only defining the ipv6 subnet for it
6058
# do _not_ set the ipv6=true option, that would actually make it dual-stack
@@ -68,7 +66,7 @@ def test_ipv6_only(self, subtests: pytest_subtests.SubTests, image: str, test_fr
6866
})
6967
test_frame.append(network)
7068

71-
container = WorkbenchContainer(image=image)
69+
container = WorkbenchContainer(image=workbench_image)
7270
container.with_network(network)
7371
try:
7472
try:
@@ -180,20 +178,6 @@ def start(self, wait_for_readiness: bool = True) -> WorkbenchContainer:
180178
return self
181179

182180

183-
def skip_if_not_workbench_image(image: str) -> docker.models.images.Image:
184-
client = testcontainers.core.container.DockerClient()
185-
try:
186-
image_metadata = client.client.images.get(image)
187-
except docker.errors.ImageNotFound:
188-
image_metadata = client.client.images.pull(image)
189-
assert isinstance(image_metadata, docker.models.images.Image)
190-
191-
ide_server_label_fragments = ('-code-server-', '-jupyter-', '-rstudio-')
192-
if not any(ide in image_metadata.labels['name'] for ide in ide_server_label_fragments):
193-
pytest.skip(
194-
f"Image {image} does not have any of '{ide_server_label_fragments=} in {image_metadata.labels['name']=}'")
195-
196-
return image_metadata
197181

198182
def grab_and_check_logs(subtests: pytest_subtests.SubTests, container: WorkbenchContainer) -> None:
199183
# Here is a list of blocked keywords we don't want to see in the log messages during the container/workbench

0 commit comments

Comments
 (0)