Skip to content

Commit

Permalink
Chore: Use pytest-docker for managing the images (#36)
Browse files Browse the repository at this point in the history
  • Loading branch information
stumpylog authored Oct 9, 2024
1 parent 0d5215c commit 36fb3f5
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 105 deletions.
32 changes: 2 additions & 30 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,6 @@ jobs:
steps:
-
uses: actions/checkout@v4
-
name: Start containers
run: |
docker compose --file ${GITHUB_WORKSPACE}/.docker/docker-compose.ci-test.yml pull --quiet
docker compose --file ${GITHUB_WORKSPACE}/.docker/docker-compose.ci-test.yml up --detach
echo "Wait for container to be started"
sleep 5
docker inspect gotenberg-client-test-server
-
name: Install poppler-utils
run: |
Expand All @@ -97,20 +89,13 @@ jobs:
name: Run tests
run: |
hatch test --cover --python ${{ matrix.python-version }}
ls -ahl .
-
name: Upload coverage to Codecov
if: matrix.python-version == '3.10'
uses: codecov/codecov-action@v4
with:
# not required for public repos, but intermittently fails otherwise
token: ${{ secrets.CODECOV_TOKEN }}
-
name: Stop containers
if: always()
run: |
docker compose --file ${GITHUB_WORKSPACE}/.docker/docker-compose.ci-test.yml logs
docker compose --file ${GITHUB_WORKSPACE}/.docker/docker-compose.ci-test.yml down

test-edge:
name: Test Gotenberg :edge
Expand All @@ -119,17 +104,11 @@ jobs:
contents: read
needs:
- lint
env:
GOTENBERG_CLIENT_EDGE_TEST: 1
steps:
-
uses: actions/checkout@v4
-
name: Start containers
run: |
docker compose --file ${GITHUB_WORKSPACE}/.docker/docker-compose.ci-test-edge.yml pull --quiet
docker compose --file ${GITHUB_WORKSPACE}/.docker/docker-compose.ci-test-edge.yml up --detach
echo "Wait for container to be started"
sleep 5
docker inspect gotenberg-client-test-edge-server
-
name: Install poppler-utils
run: |
Expand All @@ -154,13 +133,6 @@ jobs:
name: Run tests
run: |
hatch test --cover --python 3.11
ls -ahl .
-
name: Stop containers
if: always()
run: |
docker compose --file ${GITHUB_WORKSPACE}/.docker/docker-compose.ci-test-edge.yml logs
docker compose --file ${GITHUB_WORKSPACE}/.docker/docker-compose.ci-test-edge.yml down
build:
name: Build
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Changed

- Use `pytest-docker` to manage Docker image services ([#36](https://github.com/stumpylog/gotenberg-client/pull/36))

## [0.7.0] - 2024-10-08

### Fixed
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ extra-dependencies = [
"pytest-httpx ~= 0.22; python_version < '3.9'",
"pikepdf",
"python-magic",
"pytest-docker ~= 3.1",
]
extra-args = [ "--maxprocesses=8", "--pythonwarnings=all" ]

Expand Down
67 changes: 63 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,80 @@
from typing import Generator
from typing import Union

import httpx
import pytest

from gotenberg_client import GotenbergClient
from gotenberg_client import SingleFileResponse
from gotenberg_client import ZipFileResponse

logger = logging.getLogger("gotenberg-client.tests")


def is_responsive(url):
try:
response = httpx.get(url)
except httpx.HTTPError:
logger.exception("Error connecting to service")
return False
else:
return response.status_code == httpx.codes.OK


@pytest.fixture(scope="session")
def docker_compose_file() -> Path:
if "GOTENBERG_CLIENT_EDGE_TEST" in os.environ:
return Path(__file__).parent / "docker" / "docker-compose.ci-test-edge.yml"
else:
return Path(__file__).parent / "docker" / "docker-compose.ci-test.yml"


@pytest.fixture(scope="session")
def gotenberg_service_name() -> str:
if "GOTENBERG_CLIENT_EDGE_TEST" in os.environ:
return "gotenberg-client-test-edge-server"
else:
return "gotenberg-client-test-edge-server"


@pytest.fixture(scope="session")
def gotenberg_host() -> str:
return os.getenv("GOTENBERG_URL", "http://localhost:3000")
def webserver_service_name() -> str:
if "GOTENBERG_CLIENT_EDGE_TEST" in os.environ:
return "nginx-webserver-edge"
else:
return "nginx-webserver"


@pytest.fixture(scope="session")
def web_server_host() -> str:
return os.getenv("WEBSERVER_HOST", "http://localhost:8888")
def webserver_docker_internal_url(webserver_service_name: str) -> str:
"""
The URL by which Gotenberg can access the webserver
"""
return f"http://{webserver_service_name}"


@pytest.fixture(scope="session")
def gotenberg_host(docker_services, docker_ip: str, gotenberg_service_name: str) -> str:
url = f"http://{docker_ip}:{docker_services.port_for(gotenberg_service_name, 3000)}"

docker_services.wait_until_responsive(
timeout=30.0,
pause=1,
check=lambda: is_responsive(f"{url}/version"),
)
return url


@pytest.fixture(scope="session")
def web_server_host(docker_services, docker_ip: str, webserver_service_name: str) -> str:
url = f"http://{docker_ip}:{docker_services.port_for(webserver_service_name, 80)}"

docker_services.wait_until_responsive(
timeout=30.0,
pause=1,
check=lambda: is_responsive(url),
)
return url


@pytest.fixture(scope="session")
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
# docker-compose file for running testing with gotenberg container
# Can be used locally or by the CI to start the necessary container with the
# correct networking for the tests

version: "3"
networks:
gotenberg-test-edge-net:
services:
gotenberg-client-test-edge-server:
image: docker.io/gotenberg/gotenberg:edge
hostname: gotenberg-client-test-edge-server
container_name: gotenberg-client-test-edge-server
network_mode: host
restart: unless-stopped
networks:
- gotenberg-test-edge-net
ports:
- "3000/tcp"
command:
- "gotenberg"
- "--log-level=info"
- "--log-format=text"
nginx-webserver:
nginx-webserver-edge:
image: docker.io/nginx:1-alpine
hostname: nginx-webserver
container_name: nginx-webserver
networks:
- gotenberg-test-edge-net
ports:
- "8888:80"
restart: unless-stopped
- "80/tcp"
volumes:
- ./content:/usr/share/nginx/html:ro
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
# docker-compose file for running testing with gotenberg container
# Can be used locally or by the CI to start the necessary container with the
# correct networking for the tests

version: "3"
networks:
gotenberg-test-net:
services:
gotenberg-client-test-server:
gotenberg-client-test-edge-server:
image: docker.io/gotenberg/gotenberg:8.11.0
hostname: gotenberg-client-test-server
container_name: gotenberg-client-test-server
network_mode: host
restart: unless-stopped
networks:
- gotenberg-test-net
ports:
- "3000/tcp"
command:
- "gotenberg"
- "--log-level=warn"
- "--log-level=info"
- "--log-format=text"
nginx-webserver:
image: docker.io/nginx:1-alpine
hostname: nginx-webserver
container_name: nginx-webserver
networks:
- gotenberg-test-net
ports:
- "8888:80"
restart: unless-stopped
environment:
NGINX_ENTRYPOINT_QUIET_LOGS: 1
- "80/tcp"
volumes:
- ./content:/usr/share/nginx/html:ro
45 changes: 23 additions & 22 deletions tests/test_convert_chromium_screenshots.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
from gotenberg_client import GotenbergClient


@pytest.mark.usefixtures("web_server_host")
class TestChromiumScreenshots:
def test_basic_screenshot(self, client: GotenbergClient, web_server_host: str):
def test_basic_screenshot(self, client: GotenbergClient, webserver_docker_internal_url: str):
with client.chromium.screenshot_url() as route:
resp = route.url(web_server_host).run_with_retry()
resp = route.url(webserver_docker_internal_url).run_with_retry()

assert resp.status_code == codes.OK
assert "Content-Type" in resp.headers
Expand All @@ -26,83 +27,83 @@ def test_basic_screenshot(self, client: GotenbergClient, web_server_host: str):
def test_screenshot_formats(
self,
client: GotenbergClient,
web_server_host: str,
webserver_docker_internal_url: str,
image_format: Literal["png", "webp", "jpeg"],
):
with client.chromium.screenshot_url() as route:
resp = route.url(web_server_host).output_format(image_format).run_with_retry()
resp = route.url(webserver_docker_internal_url).output_format(image_format).run_with_retry()

assert resp.status_code == codes.OK
assert "Content-Type" in resp.headers
assert resp.headers["Content-Type"] == f"image/{image_format}"

def test_screenshot_quality_valid(self, client: GotenbergClient, web_server_host: str):
def test_screenshot_quality_valid(self, client: GotenbergClient, webserver_docker_internal_url: str):
with client.chromium.screenshot_url() as route:
resp = route.url(web_server_host).quality(80).run_with_retry()
resp = route.url(webserver_docker_internal_url).quality(80).run_with_retry()

assert resp.status_code == codes.OK
assert "Content-Type" in resp.headers
assert resp.headers["Content-Type"] == "image/png"

def test_screenshot_quality_too_low(self, client: GotenbergClient, web_server_host: str):
def test_screenshot_quality_too_low(self, client: GotenbergClient, webserver_docker_internal_url: str):
with client.chromium.screenshot_url() as route:
resp = route.url(web_server_host).quality(-10).run_with_retry()
resp = route.url(webserver_docker_internal_url).quality(-10).run_with_retry()

assert resp.status_code == codes.OK
assert "Content-Type" in resp.headers
assert resp.headers["Content-Type"] == "image/png"

def test_screenshot_quality_too_high(self, client: GotenbergClient, web_server_host: str):
def test_screenshot_quality_too_high(self, client: GotenbergClient, webserver_docker_internal_url: str):
with client.chromium.screenshot_url() as route:
resp = route.url(web_server_host).quality(101).run_with_retry()
resp = route.url(webserver_docker_internal_url).quality(101).run_with_retry()

assert resp.status_code == codes.OK
assert "Content-Type" in resp.headers
assert resp.headers["Content-Type"] == "image/png"

def test_screenshot_optimize_speed(self, client: GotenbergClient, web_server_host: str):
def test_screenshot_optimize_speed(self, client: GotenbergClient, webserver_docker_internal_url: str):
with client.chromium.screenshot_url() as route:
resp = route.url(web_server_host).optimize_speed().run_with_retry()
resp = route.url(webserver_docker_internal_url).optimize_speed().run_with_retry()

assert resp.status_code == codes.OK
assert "Content-Type" in resp.headers
assert resp.headers["Content-Type"] == "image/png"

def test_screenshot_optimize_quality(self, client: GotenbergClient, web_server_host: str):
def test_screenshot_optimize_quality(self, client: GotenbergClient, webserver_docker_internal_url: str):
with client.chromium.screenshot_url() as route:
resp = route.url(web_server_host).optimize_size().run_with_retry()
resp = route.url(webserver_docker_internal_url).optimize_size().run_with_retry()

assert resp.status_code == codes.OK
assert "Content-Type" in resp.headers
assert resp.headers["Content-Type"] == "image/png"

def test_network_idle_on(self, client: GotenbergClient, web_server_host: str):
def test_network_idle_on(self, client: GotenbergClient, webserver_docker_internal_url: str):
with client.chromium.screenshot_url() as route:
resp = route.url(web_server_host).skip_network_idle().run_with_retry()
resp = route.url(webserver_docker_internal_url).skip_network_idle().run_with_retry()

assert resp.status_code == codes.OK
assert "Content-Type" in resp.headers
assert resp.headers["Content-Type"] == "image/png"

def test_network_idle_off(self, client: GotenbergClient, web_server_host: str):
def test_network_idle_off(self, client: GotenbergClient, webserver_docker_internal_url: str):
with client.chromium.screenshot_url() as route:
resp = route.url(web_server_host).use_network_idle().run_with_retry()
resp = route.url(webserver_docker_internal_url).use_network_idle().run_with_retry()

assert resp.status_code == codes.OK
assert "Content-Type" in resp.headers
assert resp.headers["Content-Type"] == "image/png"

def test_status_codes(self, client: GotenbergClient, web_server_host: str):
def test_status_codes(self, client: GotenbergClient, webserver_docker_internal_url: str):
with client.chromium.screenshot_url() as route:
resp = route.url(web_server_host).fail_on_status_codes([499, 599]).run_with_retry()
resp = route.url(webserver_docker_internal_url).fail_on_status_codes([499, 599]).run_with_retry()

assert resp.status_code == codes.OK
assert "Content-Type" in resp.headers
assert resp.headers["Content-Type"] == "image/png"

def test_status_codes_empty(self, client: GotenbergClient, web_server_host: str):
def test_status_codes_empty(self, client: GotenbergClient, webserver_docker_internal_url: str):
with client.chromium.screenshot_url() as route:
resp = route.url(web_server_host).fail_on_status_codes([]).run_with_retry()
resp = route.url(webserver_docker_internal_url).fail_on_status_codes([]).run_with_retry()

assert resp.status_code == codes.OK
assert "Content-Type" in resp.headers
Expand Down
Loading

0 comments on commit 36fb3f5

Please sign in to comment.