Skip to content

Commit

Permalink
ISSUE #887: add fixtures to skip test if it's not jupyterlab/codeserv…
Browse files Browse the repository at this point in the history
…er/rstudio image (#918)
  • Loading branch information
RomanFilip authored Feb 25, 2025
1 parent 1703ea2 commit 54ca634
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 50 deletions.
56 changes: 56 additions & 0 deletions tests/containers/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@

import pytest

import docker.errors
import docker.models.images
import docker.types

from tests.containers import docker_utils

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


def skip_if_not_workbench_image(image: str) -> docker.models.images.Image:
client = testcontainers.core.container.DockerClient()
try:
image_metadata = client.client.images.get(image)
except docker.errors.ImageNotFound:
image_metadata = client.client.images.pull(image)
assert isinstance(image_metadata, docker.models.images.Image)

ide_server_label_fragments = ('-code-server-', '-jupyter-', '-rstudio-')
if not any(ide in image_metadata.labels['name'] for ide in ide_server_label_fragments):
pytest.skip(
f"Image {image} does not have any of '{ide_server_label_fragments=} in {image_metadata.labels['name']=}'")

return image_metadata


# https://docs.pytest.org/en/stable/how-to/fixtures.html#parametrizing-fixtures
# indirect parametrization https://stackoverflow.com/questions/18011902/how-to-pass-a-parameter-to-a-fixture-function-in-pytest
@pytest.fixture(scope="session")
def image(request):
yield request.param


@pytest.fixture(scope="function")
def workbench_image(image: str):
skip_if_not_workbench_image(image)
yield image


@pytest.fixture(scope="function")
def jupyterlab_image(image: str):
image_metadata = skip_if_not_workbench_image(image)
if "-jupyter-" not in image_metadata.labels['name']:
pytest.skip(
f"Image {image} does not have '-jupyter-' in {image_metadata.labels['name']=}'")

return image_metadata


@pytest.fixture(scope="function")
def rstudio_image(image: str):
image_metadata = skip_if_not_workbench_image(image)
if "-rstudio-" not in image_metadata.labels['name']:
pytest.skip(
f"Image {image} does not have '-rstudio-' in {image_metadata.labels['name']=}'")

return image_metadata


@pytest.fixture(scope="function")
def codeserver_image(image: str):
image_metadata = skip_if_not_workbench_image(image)
if "-code-server-" not in image_metadata.labels['name']:
pytest.skip(
f"Image {image} does not have '-code-server-' in {image_metadata.labels['name']=}'")

return image_metadata


# https://docs.pytest.org/en/latest/reference/reference.html#pytest.hookspec.pytest_sessionstart
def pytest_sessionstart(session: Session) -> None:
# first preflight check: ping the Docker API
Expand Down
16 changes: 3 additions & 13 deletions tests/containers/workbenches/jupyterlab/jupyterlab_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import pytest

from tests.containers import docker_utils
from tests.containers.workbenches.workbench_image_test import WorkbenchContainer, skip_if_not_workbench_image
from tests.containers.workbenches.workbench_image_test import WorkbenchContainer

if TYPE_CHECKING:
import docker.models.images
Expand All @@ -21,10 +21,9 @@ class TestJupyterLabImage:

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

container = WorkbenchContainer(image=image, user=4321, group_add=[0])
container = WorkbenchContainer(image=jupyterlab_image, user=4321, group_add=[0])
# if no env is specified, the image will run
# > 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
# > --ServerApp.root_dir=/opt/app-root/src --ServerApp.ip= --ServerApp.allow_origin=* --ServerApp.open_browser=False
Expand Down Expand Up @@ -52,12 +51,3 @@ def test_spinner_html_loaded(self, image: str) -> None:
assert 'class="pf-v6-c-spinner"' in response.text
finally:
docker_utils.NotebookContainer(container).stop(timeout=0)


def skip_if_not_jupyterlab_image(image: str) -> docker.models.images.Image:
image_metadata = skip_if_not_workbench_image(image)
if "-jupyter-" not in image_metadata.labels['name']:
pytest.skip(
f"Image {image} does not have '-jupyter-' in {image_metadata.labels['name']=}'")

return image_metadata
22 changes: 5 additions & 17 deletions tests/containers/workbenches/rstudio/rstudio_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import pytest

from tests.containers import docker_utils
from tests.containers.workbenches.workbench_image_test import WorkbenchContainer, skip_if_not_workbench_image
from tests.containers.workbenches.workbench_image_test import WorkbenchContainer

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

@allure.issue("RHOAIENG-17256")
def test_rmd_to_pdf_rendering(self, image: str) -> None:
def test_rmd_to_pdf_rendering(self, rstudio_image: str) -> None:
"""
References:
https://stackoverflow.com/questions/40563479/relationship-between-r-markdown-knitr-pandoc-and-bookdown
https://www.earthdatascience.org/courses/earth-analytics/document-your-science/knit-rmarkdown-document-to-pdf/
"""
skip_if_not_rstudio_image(image)

container = WorkbenchContainer(image=image, user=1000, group_add=[0])
container = WorkbenchContainer(image=rstudio_image, user=1000, group_add=[0])
try:
container.start(wait_for_readiness=False)

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

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

class TestCase(NamedTuple):
name: str
Expand All @@ -119,7 +116,7 @@ class TestCase(NamedTuple):
TestCase("NO_PROXY", "no_proxy", "google.com"),
]

container = WorkbenchContainer(image=image, user=1000, group_add=[0])
container = WorkbenchContainer(image=rstudio_image, user=1000, group_add=[0])
for tc in test_cases:
container.with_env(tc.name, tc.value)

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


def skip_if_not_rstudio_image(image: str) -> docker.models.images.Image:
image_metadata = skip_if_not_workbench_image(image)
if "-rstudio-" not in image_metadata.labels['name']:
pytest.skip(
f"Image {image} does not have '-rstudio-' in {image_metadata.labels['name']=}'")

return image_metadata


class StructuredMessage:
"""https://docs.python.org/3/howto/logging-cookbook.html#implementing-structured-logging"""

Expand Down
24 changes: 4 additions & 20 deletions tests/containers/workbenches/workbench_image_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,9 @@ class TestWorkbenchImage:
# disable ipv6 https://danwalsh.livejournal.com/47118.html
{"net.ipv6.conf.all.disable_ipv6": "1"}
])
def test_image_entrypoint_starts(self, subtests: pytest_subtests.SubTests, image: str, sysctls) -> None:
skip_if_not_workbench_image(image)
def test_image_entrypoint_starts(self, subtests: pytest_subtests.SubTests, workbench_image: str, sysctls) -> None:

container = WorkbenchContainer(image=image, user=1000, group_add=[0],
container = WorkbenchContainer(image=workbench_image, user=1000, group_add=[0],
sysctls=sysctls)
try:
try:
Expand All @@ -51,10 +50,9 @@ def test_image_entrypoint_starts(self, subtests: pytest_subtests.SubTests, image
docker_utils.NotebookContainer(container).stop(timeout=0)

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

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

container = WorkbenchContainer(image=image)
container = WorkbenchContainer(image=workbench_image)
container.with_network(network)
try:
try:
Expand Down Expand Up @@ -180,20 +178,6 @@ def start(self, wait_for_readiness: bool = True) -> WorkbenchContainer:
return self


def skip_if_not_workbench_image(image: str) -> docker.models.images.Image:
client = testcontainers.core.container.DockerClient()
try:
image_metadata = client.client.images.get(image)
except docker.errors.ImageNotFound:
image_metadata = client.client.images.pull(image)
assert isinstance(image_metadata, docker.models.images.Image)

ide_server_label_fragments = ('-code-server-', '-jupyter-', '-rstudio-')
if not any(ide in image_metadata.labels['name'] for ide in ide_server_label_fragments):
pytest.skip(
f"Image {image} does not have any of '{ide_server_label_fragments=} in {image_metadata.labels['name']=}'")

return image_metadata

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

0 comments on commit 54ca634

Please sign in to comment.