Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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]:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe not in this PR, but perhaps it might be better to build the images lazily rather than building them all in advance, because right now even if you run one specific test it will build all images.

Copy link
Contributor Author

@Jongy Jongy Sep 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#480 :)

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:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added it but after a refactor I won't need it. Still useful, so keeping it

assert isinstance(arg, typ)
return arg