Skip to content

Commit

Permalink
tests: Break up application_docker_images() (#477)
Browse files Browse the repository at this point in the history
More lines-of-code for the same task, but the image generators are much more clear now. This code
has become a hassle to work with, and now it's simple again :)
  • Loading branch information
Jongy authored Sep 21, 2022
1 parent 43e1e16 commit f59bbf3
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 58 deletions.
92 changes: 53 additions & 39 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@
# Copyright (c) Granulate. All rights reserved.
# Licensed under the AGPL3 License. See LICENSE.md in the project root for license information.
#
import glob
import os
import stat
import subprocess
from contextlib import _GeneratorContextManager, contextmanager
from functools import partial
from pathlib import Path
from typing import Any, Callable, Generator, Iterable, Iterator, List, Mapping, Optional, cast
from typing import Any, Callable, Dict, Generator, Iterable, Iterator, List, Mapping, Optional, cast

import docker
import pytest
Expand Down Expand Up @@ -184,58 +183,73 @@ def gprofiler_docker_image(docker_client: DockerClient) -> Iterable[Image]:
yield docker_client.images.get("gprofiler")


def _build_image(
docker_client: DockerClient, runtime: str, dockerfile: str = "Dockerfile", **kwargs: Mapping[str, Any]
) -> Image:
base_path = CONTAINERS_DIRECTORY / runtime
return docker_client.images.build(path=str(base_path), rm=True, dockerfile=str(base_path / dockerfile), **kwargs)[0]


def image_name(runtime: str, image_tag: str) -> str:
return runtime + ("_" + image_tag if image_tag else "")


@fixture(scope="session")
def application_docker_images(docker_client: DockerClient) -> Mapping[str, Image]:
images = {}
for runtime in os.listdir(str(CONTAINERS_DIRECTORY)):
if runtime == "native":
for dockerfile in glob.glob(str(CONTAINERS_DIRECTORY / runtime / "*.Dockerfile")):
suffix = os.path.splitext(os.path.basename(dockerfile))[0]
images[f"{runtime}_{suffix}"], _ = docker_client.images.build(
path=str(CONTAINERS_DIRECTORY / runtime), dockerfile=str(dockerfile), rm=True
)
continue

images[runtime], _ = docker_client.images.build(path=str(CONTAINERS_DIRECTORY / runtime), rm=True)

# for java - add additional images
if runtime == "java":
images[runtime + "_j9"], _ = docker_client.images.build(
path=str(CONTAINERS_DIRECTORY / runtime),
rm=True,
buildargs={"JAVA_BASE_IMAGE": "adoptopenjdk/openjdk8-openj9"},
)

images[runtime + "_zing"], _ = docker_client.images.build(
path=str(CONTAINERS_DIRECTORY / runtime),
rm=True,
dockerfile=str(CONTAINERS_DIRECTORY / runtime / "zing.Dockerfile"),
)

# build musl image if exists
musl_dockerfile = CONTAINERS_DIRECTORY / runtime / "musl.Dockerfile"
if musl_dockerfile.exists():
images[runtime + "_musl"], _ = docker_client.images.build(
path=str(CONTAINERS_DIRECTORY / runtime), dockerfile=str(musl_dockerfile), rm=True
)
runtime_image_listing: Dict[str, Dict[str, Dict[str, Any]]] = {
"dotnet": {
"": {},
},
"golang": {
"": {},
},
"java": {
"": {},
"j9": dict(buildargs={"JAVA_BASE_IMAGE": "adoptopenjdk/openjdk8-openj9"}),
"zing": dict(dockerfile="zing.Dockerfile"),
"musl": dict(dockerfile="musl.Dockerfile"),
},
"native": {
"fp": dict(dockerfile="fp.Dockerfile"),
"dwarf": dict(dockerfile="dwarf.Dockerfile"),
"change_comm": dict(dockerfile="change_comm.Dockerfile"),
"thread_comm": dict(dockerfile="thread_comm.Dockerfile"),
},
"nodejs": {
"": {},
},
"php": {
"": {},
},
"python": {
"": {},
"libpython": dict(dockerfile="libpython.Dockerfile"),
},
"ruby": {"": {}},
}

images = {}
for runtime, tags_listing in runtime_image_listing.items():
for tag, args in tags_listing.items():
name = image_name(runtime, tag)
assert name not in images
images[name] = _build_image(docker_client, runtime, **args)
return images


@fixture
def image_suffix() -> str:
# lets tests override this value and use a suffixed image, e.g _musl or _j9.
def application_image_tag() -> str:
# lets tests override this value and use a "tagged" image, e.g "musl" or "j9".
return ""


@fixture
def application_docker_image(
application_docker_images: Mapping[str, Image],
runtime: str,
image_suffix: str,
application_image_tag: str,
) -> Iterable[Image]:
runtime = runtime + image_suffix
yield application_docker_images[runtime]
yield application_docker_images[image_name(runtime, application_image_tag)]


@fixture
Expand Down
14 changes: 7 additions & 7 deletions tests/test_java.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@
)


@pytest.fixture
def runtime() -> str:
return "java"


def get_lib_path(application_pid: int, path: str) -> str:
libs = set()
for m in psutil.Process(application_pid).memory_maps():
Expand Down Expand Up @@ -78,11 +83,6 @@ def status_async_profiler(self) -> None:
)


@pytest.fixture
def runtime() -> str:
return "java"


def test_async_profiler_already_running(
application_pid: int, assert_collapsed: AssertInCollapsed, tmp_path: Path, caplog: LogCaptureFixture
) -> None:
Expand Down Expand Up @@ -146,7 +146,7 @@ def test_java_async_profiler_cpu_mode(


@pytest.mark.parametrize("in_container", [True])
@pytest.mark.parametrize("image_suffix", ["_musl"])
@pytest.mark.parametrize("application_image_tag", ["musl"])
def test_java_async_profiler_musl_and_cpu(
tmp_path: Path,
application_pid: int,
Expand Down Expand Up @@ -339,7 +339,7 @@ def test_async_profiler_stops_after_given_timeout(


@pytest.mark.parametrize("in_container", [True])
@pytest.mark.parametrize("image_suffix,search_for", [("_j9", "OpenJ9"), ("_zing", "Zing")])
@pytest.mark.parametrize("application_image_tag,search_for", [("j9", "OpenJ9"), ("zing", "Zing")])
def test_sanity_other_jvms(
tmp_path: Path,
application_pid: int,
Expand Down
12 changes: 1 addition & 11 deletions tests/test_libpython.py → tests/test_python.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,9 @@
from threading import Event

import pytest
from docker import DockerClient
from docker.models.containers import Container
from docker.models.images import Image

from gprofiler.profilers.python import PythonProfiler
from tests import CONTAINERS_DIRECTORY
from tests.conftest import AssertInCollapsed
from tests.utils import snapshot_pid_collapsed

Expand All @@ -21,15 +18,8 @@ def runtime() -> str:
return "python"


@pytest.fixture(scope="session")
def application_docker_image(docker_client: DockerClient) -> Image:
dockerfile = CONTAINERS_DIRECTORY / "python" / "Dockerfile.libpython"
image: Image = docker_client.images.build(path=str(dockerfile.parent), dockerfile=str(dockerfile), rm=True)[0]
yield image
docker_client.images.remove(image.id, force=True)


@pytest.mark.parametrize("in_container", [True])
@pytest.mark.parametrize("application_image_tag", ["libpython"])
def test_python_select_by_libpython(
tmp_path: Path,
application_docker_container: Container,
Expand Down
7 changes: 6 additions & 1 deletion tests/type_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@
# Copyright (c) Granulate. All rights reserved.
# Licensed under the AGPL3 License. See LICENSE.md in the project root for license information.
#
from typing import Optional, TypeVar
from typing import Any, Optional, Type, TypeVar

T = TypeVar("T")


def cast_away_optional(arg: Optional[T]) -> T:
assert arg is not None
return arg


def assert_cast(typ: Type[T], arg: Any) -> T:
assert isinstance(arg, typ)
return arg

0 comments on commit f59bbf3

Please sign in to comment.