Skip to content

Commit dcd1c45

Browse files
authored
Refactor TrackedContainer run_detached/exec_cmd functions (#2256)
* Refactor TrackedContainer run_detached/exec_cmd functions * Add get_logs() method * Small fixes * Make get_health() a method * Remove kwargs, always print output * Small fixes
1 parent a916806 commit dcd1c45

File tree

15 files changed

+78
-129
lines changed

15 files changed

+78
-129
lines changed

docs/maintaining/tagging_examples/docker_runner.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
from tagging.utils.docker_runner import DockerRunner
44

55
with DockerRunner("ubuntu") as container:
6-
DockerRunner.exec_cmd(container, cmd="env", print_output=True)
6+
DockerRunner.exec_cmd(container, cmd="env")

tagging/taggers/versions.py

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ def _get_pip_package_version(container: Container, package: str) -> str:
1515
package_info = DockerRunner.exec_cmd(
1616
container,
1717
cmd=f"pip show {package}",
18-
print_output=False,
1918
)
2019
version_line = package_info.split("\n")[1]
2120
assert version_line.startswith(PIP_VERSION_PREFIX)

tagging/utils/docker_runner.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,11 @@ def __exit__(
4343
LOGGER.info(f"Container {self.container.name} removed")
4444

4545
@staticmethod
46-
def exec_cmd(container: Container, cmd: str, print_output: bool = True) -> str:
46+
def exec_cmd(container: Container, cmd: str) -> str:
4747
LOGGER.info(f"Running cmd: `{cmd}` on container: {container.name}")
4848
exec_result = container.exec_run(cmd)
4949
output = exec_result.output.decode().rstrip()
5050
assert isinstance(output, str)
51-
if print_output:
52-
LOGGER.info(f"Command output: {output}")
51+
LOGGER.info(f"Command output: {output}")
5352
assert exec_result.exit_code == 0, f"Command: `{cmd}` failed"
5453
return output

tagging/utils/quoted_output.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99

1010
def quoted_output(container: Container, cmd: str) -> str:
11-
cmd_output = DockerRunner.exec_cmd(container, cmd, print_output=False)
11+
cmd_output = DockerRunner.exec_cmd(container, cmd)
1212
# For example, `mamba info` adds redundant empty lines
1313
cmd_output = cmd_output.strip("\n")
1414
# For example, R packages list contains trailing backspaces

tests/by_image/base-notebook/test_container_options.py

+8-9
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@
1515
def test_cli_args(container: TrackedContainer, http_client: requests.Session) -> None:
1616
"""Image should respect command line args (e.g., disabling token security)"""
1717
host_port = find_free_port()
18-
running_container = container.run_detached(
18+
container.run_detached(
1919
command=["start-notebook.py", "--IdentityProvider.token=''"],
2020
ports={"8888/tcp": host_port},
2121
)
2222
resp = http_client.get(f"http://localhost:{host_port}")
2323
resp.raise_for_status()
24-
logs = running_container.logs().decode()
24+
logs = container.get_logs()
2525
LOGGER.debug(logs)
2626
assert "ERROR" not in logs
2727
warnings = TrackedContainer.get_warnings(logs)
@@ -32,7 +32,7 @@ def test_cli_args(container: TrackedContainer, http_client: requests.Session) ->
3232
def test_nb_user_change(container: TrackedContainer) -> None:
3333
"""Container should change the username (`NB_USER`) of the default user."""
3434
nb_user = "nayvoj"
35-
running_container = container.run_detached(
35+
container.run_detached(
3636
tty=True,
3737
user="root",
3838
environment=[f"NB_USER={nb_user}", "CHOWN_HOME=yes"],
@@ -47,8 +47,7 @@ def test_nb_user_change(container: TrackedContainer) -> None:
4747
)
4848
command = f'stat -c "%F %U %G" /home/{nb_user}/.jupyter'
4949
expected_output = f"directory {nb_user} users"
50-
exec_result = running_container.exec_run(command, workdir=f"/home/{nb_user}")
51-
output = exec_result.output.decode().strip("\n")
50+
output = container.exec_cmd(command, workdir=f"/home/{nb_user}")
5251
assert (
5352
output == expected_output
5453
), f"Hidden folder .jupyter was not copied properly to {nb_user} home folder. stat: {output}, expected {expected_output}"
@@ -62,7 +61,7 @@ def test_unsigned_ssl(
6261
and Jupyter Server should use it to enable HTTPS.
6362
"""
6463
host_port = find_free_port()
65-
running_container = container.run_detached(
64+
container.run_detached(
6665
environment=["GEN_CERT=yes"],
6766
ports={"8888/tcp": host_port},
6867
)
@@ -74,7 +73,7 @@ def test_unsigned_ssl(
7473
resp = http_client.get(f"https://localhost:{host_port}", verify=False)
7574
resp.raise_for_status()
7675
assert "login_submit" in resp.text
77-
logs = running_container.logs().decode()
76+
logs = container.get_logs()
7877
assert "ERROR" not in logs
7978
warnings = TrackedContainer.get_warnings(logs)
8079
assert not warnings
@@ -102,14 +101,14 @@ def test_custom_internal_port(
102101
when using custom internal port"""
103102
host_port = find_free_port()
104103
internal_port = env.get("JUPYTER_PORT", 8888)
105-
running_container = container.run_detached(
104+
container.run_detached(
106105
command=["start-notebook.py", "--IdentityProvider.token=''"],
107106
environment=env,
108107
ports={internal_port: host_port},
109108
)
110109
resp = http_client.get(f"http://localhost:{host_port}")
111110
resp.raise_for_status()
112-
logs = running_container.logs().decode()
111+
logs = container.get_logs()
113112
LOGGER.debug(logs)
114113
assert "ERROR" not in logs
115114
warnings = TrackedContainer.get_warnings(logs)

tests/by_image/base-notebook/test_healthcheck.py

+6-12
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,20 @@
33
import logging
44
import time
55

6-
import docker
76
import pytest # type: ignore
87

9-
from tests.utils.get_container_health import get_health
108
from tests.utils.tracked_container import TrackedContainer
119

1210
LOGGER = logging.getLogger(__name__)
1311

1412

1513
def get_healthy_status(
1614
container: TrackedContainer,
17-
docker_client: docker.DockerClient,
1815
env: list[str] | None,
1916
cmd: list[str] | None,
2017
user: str | None,
2118
) -> str:
22-
running_container = container.run_detached(
19+
container.run_detached(
2320
tty=True,
2421
environment=env,
2522
command=cmd,
@@ -32,11 +29,11 @@ def get_healthy_status(
3229
while time.time() < finish_time:
3330
time.sleep(sleep_time)
3431

35-
status = get_health(running_container, docker_client)
32+
status = container.get_health()
3633
if status == "healthy":
3734
return status
3835

39-
return get_health(running_container, docker_client)
36+
return status
4037

4138

4239
@pytest.mark.parametrize(
@@ -84,12 +81,11 @@ def get_healthy_status(
8481
)
8582
def test_healthy(
8683
container: TrackedContainer,
87-
docker_client: docker.DockerClient,
8884
env: list[str] | None,
8985
cmd: list[str] | None,
9086
user: str | None,
9187
) -> None:
92-
assert get_healthy_status(container, docker_client, env, cmd, user) == "healthy"
88+
assert get_healthy_status(container, env, cmd, user) == "healthy"
9389

9490

9591
@pytest.mark.parametrize(
@@ -118,12 +114,11 @@ def test_healthy(
118114
)
119115
def test_healthy_with_proxy(
120116
container: TrackedContainer,
121-
docker_client: docker.DockerClient,
122117
env: list[str] | None,
123118
cmd: list[str] | None,
124119
user: str | None,
125120
) -> None:
126-
assert get_healthy_status(container, docker_client, env, cmd, user) == "healthy"
121+
assert get_healthy_status(container, env, cmd, user) == "healthy"
127122

128123

129124
@pytest.mark.parametrize(
@@ -142,10 +137,9 @@ def test_healthy_with_proxy(
142137
)
143138
def test_not_healthy(
144139
container: TrackedContainer,
145-
docker_client: docker.DockerClient,
146140
env: list[str] | None,
147141
cmd: list[str] | None,
148142
) -> None:
149143
assert (
150-
get_healthy_status(container, docker_client, env, cmd, user=None) != "healthy"
144+
get_healthy_status(container, env, cmd, user=None) != "healthy"
151145
), "Container should not be healthy for this testcase"

tests/by_image/base-notebook/test_ips.py

+2-6
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,9 @@ def test_ipv46(container: TrackedContainer, ipv6_network: str) -> None:
3838
host_data_dir = THIS_DIR / "data"
3939
cont_data_dir = "/home/jovyan/data"
4040
LOGGER.info("Testing that server is listening on IPv4 and IPv6 ...")
41-
running_container = container.run_detached(
41+
container.run_detached(
4242
network=ipv6_network,
4343
volumes={str(host_data_dir): {"bind": cont_data_dir, "mode": "ro,z"}},
4444
tty=True,
4545
)
46-
47-
command = ["python", f"{cont_data_dir}/check_listening.py"]
48-
exec_result = running_container.exec_run(command)
49-
LOGGER.info(exec_result.output.decode())
50-
assert exec_result.exit_code == 0
46+
container.exec_cmd(f"python {cont_data_dir}/check_listening.py")

tests/by_image/base-notebook/test_start_container.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,14 @@ def test_start_notebook(
4242
f"Test that the start-notebook.py launches the {expected_command} server from the env {env} ..."
4343
)
4444
host_port = find_free_port()
45-
running_container = container.run_detached(
45+
container.run_detached(
4646
tty=True,
4747
environment=env,
4848
ports={"8888/tcp": host_port},
4949
)
5050
# sleeping some time to let the server start
5151
time.sleep(2)
52-
logs = running_container.logs().decode()
52+
logs = container.get_logs()
5353
LOGGER.debug(logs)
5454
# checking that the expected command is launched
5555
assert (
@@ -76,10 +76,9 @@ def test_tini_entrypoint(
7676
https://superuser.com/questions/632979/if-i-know-the-pid-number-of-a-process-how-can-i-get-its-name
7777
"""
7878
LOGGER.info(f"Test that {command} is launched as PID {pid} ...")
79-
running_container = container.run_detached(tty=True)
79+
container.run_detached(tty=True)
8080
# Select the PID 1 and get the corresponding command
81-
exec_result = running_container.exec_run(f"ps -p {pid} -o comm=")
82-
output = exec_result.output.decode().strip("\n")
81+
output = container.exec_cmd(f"ps -p {pid} -o comm=")
8382
assert "ERROR" not in output
8483
assert "WARNING" not in output
8584
assert output == command, f"{command} shall be launched as pid {pid}, got {output}"

tests/by_image/docker-stacks-foundation/test_packages.py

+2-11
Original file line numberDiff line numberDiff line change
@@ -109,25 +109,16 @@ def get_package_import_name(package: str) -> str:
109109
return PACKAGE_MAPPING.get(package, package)
110110

111111

112-
def _check_import_package(
113-
package_helper: CondaPackageHelper, command: list[str]
114-
) -> None:
115-
"""Generic function executing a command"""
116-
LOGGER.debug(f"Trying to import a package with [{command}] ...")
117-
exec_result = package_helper.running_container.exec_run(command)
118-
assert exec_result.exit_code == 0, exec_result.output.decode()
119-
120-
121112
def check_import_python_package(
122113
package_helper: CondaPackageHelper, package: str
123114
) -> None:
124115
"""Try to import a Python package from the command line"""
125-
_check_import_package(package_helper, ["python", "-c", f"import {package}"])
116+
package_helper.container.exec_cmd(f'python -c "import {package}"')
126117

127118

128119
def check_import_r_package(package_helper: CondaPackageHelper, package: str) -> None:
129120
"""Try to import an R package from the command line"""
130-
_check_import_package(package_helper, ["R", "--slave", "-e", f"library({package})"])
121+
package_helper.container.exec_cmd(f"R --slave -e library({package})")
131122

132123

133124
def _check_import_packages(

tests/by_image/docker-stacks-foundation/test_user_options.py

+5-10
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def test_gid_change(container: TrackedContainer) -> None:
3939
def test_nb_user_change(container: TrackedContainer) -> None:
4040
"""Container should change the username (`NB_USER`) of the default user."""
4141
nb_user = "nayvoj"
42-
running_container = container.run_detached(
42+
container.run_detached(
4343
tty=True,
4444
user="root",
4545
environment=[f"NB_USER={nb_user}", "CHOWN_HOME=yes"],
@@ -50,7 +50,7 @@ def test_nb_user_change(container: TrackedContainer) -> None:
5050
# Use sleep, not wait, because the container sleeps forever.
5151
time.sleep(1)
5252
LOGGER.info(f"Checking if the user is changed to {nb_user} by the start script ...")
53-
output = running_container.logs().decode()
53+
output = container.get_logs()
5454
assert "ERROR" not in output
5555
assert "WARNING" not in output
5656
assert (
@@ -60,17 +60,13 @@ def test_nb_user_change(container: TrackedContainer) -> None:
6060
LOGGER.info(f"Checking {nb_user} id ...")
6161
command = "id"
6262
expected_output = f"uid=1000({nb_user}) gid=100(users) groups=100(users)"
63-
exec_result = running_container.exec_run(
64-
command, user=nb_user, workdir=f"/home/{nb_user}"
65-
)
66-
output = exec_result.output.decode().strip("\n")
63+
output = container.exec_cmd(command, user=nb_user, workdir=f"/home/{nb_user}")
6764
assert output == expected_output, f"Bad user {output}, expected {expected_output}"
6865

6966
LOGGER.info(f"Checking if {nb_user} owns his home folder ...")
7067
command = f'stat -c "%U %G" /home/{nb_user}/'
7168
expected_output = f"{nb_user} users"
72-
exec_result = running_container.exec_run(command, workdir=f"/home/{nb_user}")
73-
output = exec_result.output.decode().strip("\n")
69+
output = container.exec_cmd(command, workdir=f"/home/{nb_user}")
7470
assert (
7571
output == expected_output
7672
), f"Bad owner for the {nb_user} home folder {output}, expected {expected_output}"
@@ -80,8 +76,7 @@ def test_nb_user_change(container: TrackedContainer) -> None:
8076
)
8177
command = f'stat -c "%F %U %G" /home/{nb_user}/work'
8278
expected_output = f"directory {nb_user} users"
83-
exec_result = running_container.exec_run(command, workdir=f"/home/{nb_user}")
84-
output = exec_result.output.decode().strip("\n")
79+
output = container.exec_cmd(command, workdir=f"/home/{nb_user}")
8580
assert (
8681
output == expected_output
8782
), f"Folder work was not copied properly to {nb_user} home folder. stat: {output}, expected {expected_output}"

tests/by_image/scipy-notebook/test_matplotlib.py

+5-7
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,16 @@ def test_matplotlib(
3838
cont_data_dir = "/home/jovyan/data"
3939
output_dir = "/tmp"
4040
LOGGER.info(description)
41-
running_container = container.run_detached(
41+
container.run_detached(
4242
volumes={str(host_data_dir): {"bind": cont_data_dir, "mode": "ro"}},
4343
tty=True,
4444
command=["bash", "-c", "sleep infinity"],
4545
)
46+
4647
command = f"python {cont_data_dir}/{test_file}"
47-
exec_result = running_container.exec_run(command)
48-
LOGGER.debug(exec_result.output.decode())
49-
assert exec_result.exit_code == 0, f"Command {command} failed"
48+
container.exec_cmd(command)
49+
5050
# Checking if the file is generated
5151
# https://stackoverflow.com/a/15895594/4413446
5252
command = f"test -s {output_dir}/{expected_file}"
53-
exec_result = running_container.exec_run(command)
54-
LOGGER.debug(exec_result.output.decode())
55-
assert exec_result.exit_code == 0, f"Command {command} failed"
53+
container.exec_cmd(command)

tests/conftest.py

-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ def container(
5151
container = TrackedContainer(
5252
docker_client,
5353
image_name,
54-
detach=True,
5554
)
5655
yield container
5756
container.remove()

0 commit comments

Comments
 (0)