Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chore: Use pytest fixtures in place of custom globals, etc #34

Merged
merged 5 commits into from
Sep 30, 2024
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Bump pypa/gh-action-pypi-publish from 1.9.0 to 1.10.2 by @dependabot ([#31](https://github.com/stumpylog/gotenberg-client/pull/31))
- CI testing now runs against Gotenberg 8.11 ([#32](https://github.com/stumpylog/gotenberg-client/pull/32))
- Development tool updates in `pyproject.toml` and pre-commit hook updates
- Properly use `pytest` fixtures in all testing ([#34](https://github.com/stumpylog/gotenberg-client/pull/34))

## [0.6.0] - 2024-06-13

Expand Down
137 changes: 119 additions & 18 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,137 @@
import logging
import os
import shutil
import tempfile
from pathlib import Path
from typing import Final
from typing import Generator
from typing import Union

import pytest

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

GOTENBERG_URL: Final[str] = os.getenv("GOTENBERG_URL", "http://localhost:3000")

SAMPLE_DIR: Final[Path] = Path(__file__).parent.resolve() / "samples"
SAVE_DIR: Final[Path] = Path(__file__).parent.resolve() / "outputs"
SAVE_OUTPUTS: Final[bool] = "SAVE_TEST_OUTPUT" in os.environ
@pytest.fixture(scope="session")
def gotenberg_host() -> str:
return os.getenv("GOTENBERG_URL", "http://localhost:3000")

if SAVE_OUTPUTS:
shutil.rmtree(SAVE_DIR, ignore_errors=True)
SAVE_DIR.mkdir()

@pytest.fixture(scope="session")
def web_server_host() -> str:
return os.getenv("WEBSERVER_HOST", "http://localhost:8888")


@pytest.fixture(scope="session")
def sample_directory() -> Path:
return Path(__file__).parent.resolve() / "samples"


@pytest.fixture(scope="session")
def basic_html_file(sample_directory: Path) -> Path:
return sample_directory / "basic.html"


@pytest.fixture(scope="session")
def footer_html_file(sample_directory: Path) -> Path:
return sample_directory / "footer.html"


@pytest.fixture(scope="session")
def complex_html_file(sample_directory: Path) -> Path:
return sample_directory / "complex.html"


@pytest.fixture(scope="session")
def header_html_file(sample_directory: Path) -> Path:
return sample_directory / "header.html"


@pytest.fixture(scope="session")
def img_gif_file(sample_directory: Path) -> Path:
return sample_directory / "img.gif"


@pytest.fixture(scope="session")
def font_file(sample_directory: Path) -> Path:
return sample_directory / "font.woff"


@pytest.fixture(scope="session")
def css_style_file(sample_directory: Path) -> Path:
return sample_directory / "style.css"


@pytest.fixture(scope="session")
def markdown_index_file(sample_directory: Path) -> Path:
return sample_directory / "markdown_index.html"


@pytest.fixture(scope="session")
def markdown_sample_one_file(sample_directory: Path) -> Path:
return sample_directory / "markdown1.md"


@pytest.fixture(scope="session")
def markdown_sample_two_file(sample_directory: Path) -> Path:
return sample_directory / "markdown2.md"


@pytest.fixture(scope="session")
def docx_sample_file(sample_directory: Path) -> Path:
return sample_directory / "sample.docx"


@pytest.fixture(scope="session")
def odt_sample_file(sample_directory: Path) -> Path:
return sample_directory / "sample.odt"


@pytest.fixture(scope="session")
def xlsx_sample_file(sample_directory: Path) -> Path:
return sample_directory / "sample.xlsx"


@pytest.fixture(scope="session")
def ods_sample_file(sample_directory: Path) -> Path:
return sample_directory / "sample.ods"


@pytest.fixture(scope="session")
def pdf_sample_one_file(sample_directory: Path) -> Path:
return sample_directory / "sample1.pdf"


@pytest.fixture(scope="session")
def output_file_save_directory() -> Path:
return Path(__file__).parent.resolve() / "outputs"


@pytest.fixture(scope="session")
def save_output_files(output_file_save_directory: Path) -> bool:
val = True
if val:
shutil.rmtree(output_file_save_directory, ignore_errors=True)
output_file_save_directory.mkdir()
return val


@pytest.fixture
def client() -> Generator[GotenbergClient, None, None]:
with GotenbergClient(host=GOTENBERG_URL, log_level=logging.INFO) as client:
yield client
def output_saver_factory(request, save_output_files: bool, output_file_save_directory: Path): # noqa: FBT001
def _save_the_item(response: Union[SingleFileResponse, ZipFileResponse], extra: str = ""): # noqa: ARG001
if save_output_files:
extension_mapping = {
"application/zip": ".zip",
"application/pdf": ".pdf",
"image/png": ".png",
}
extension = extension_mapping[response.headers["Content-Type"]]
response.to_file(output_file_save_directory / f"{request.node.originalname}{extension}")

return _save_the_item


@pytest.fixture
def temporary_dir() -> Generator[Path, None, None]:
"""
Creates and cleans up a temporary directory for tests
"""
with tempfile.TemporaryDirectory() as tmp_dir:
yield Path(tmp_dir).resolve()
def client(gotenberg_host: str) -> Generator[GotenbergClient, None, None]:
with GotenbergClient(host=gotenberg_host, log_level=logging.INFO) as client:
yield client
74 changes: 37 additions & 37 deletions tests/test_convert_chromium_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,84 +15,83 @@
from gotenberg_client.options import PageMarginsType
from gotenberg_client.options import PageOrientation
from gotenberg_client.options import PdfAFormat
from tests.conftest import SAMPLE_DIR
from tests.conftest import SAVE_DIR
from tests.conftest import SAVE_OUTPUTS
from tests.utils import verify_stream_contains


class TestConvertChromiumHtmlRoute:
def test_basic_convert(self, client: GotenbergClient):
test_file = SAMPLE_DIR / "basic.html"

def test_basic_convert(self, client: GotenbergClient, basic_html_file: Path):
with client.chromium.html_to_pdf() as route:
resp = route.index(test_file).run_with_retry()
resp = route.index(basic_html_file).run_with_retry()

assert resp.status_code == codes.OK
assert "Content-Type" in resp.headers
assert resp.headers["Content-Type"] == "application/pdf"
if SAVE_OUTPUTS:
resp.to_file(SAVE_DIR / "test_basic_convert.pdf")

def test_convert_with_header_footer(self, client: GotenbergClient):
test_file = SAMPLE_DIR / "basic.html"
header_file = SAMPLE_DIR / "header.html"
footer_file = SAMPLE_DIR / "footer.html"

def test_convert_with_header_footer(
self,
client: GotenbergClient,
basic_html_file: Path,
header_html_file: Path,
footer_html_file: Path,
):
with client.chromium.html_to_pdf() as route:
resp = route.index(test_file).header(header_file).footer(footer_file).run_with_retry()
resp = route.index(basic_html_file).header(header_html_file).footer(footer_html_file).run_with_retry()

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

def test_convert_additional_files(self, client: GotenbergClient):
test_file = SAMPLE_DIR / "complex.html"
img = SAMPLE_DIR / "img.gif"
font = SAMPLE_DIR / "font.woff"
style = SAMPLE_DIR / "style.css"

def test_convert_additional_files(
self,
client: GotenbergClient,
complex_html_file: Path,
img_gif_file: Path,
font_file: Path,
css_style_file: Path,
):
with client.chromium.html_to_pdf() as route:
resp = route.index(test_file).resource(img).resource(font).resource(style).run_with_retry()
resp = (
route.index(complex_html_file)
.resource(img_gif_file)
.resource(font_file)
.resource(css_style_file)
.run_with_retry()
)

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

if SAVE_OUTPUTS:
resp.to_file(SAVE_DIR / "test_convert_additional_files.pdf")

@pytest.mark.parametrize(
("gt_format", "pike_format"),
[(PdfAFormat.A2b, "2B"), (PdfAFormat.A3b, "3B")],
)
def test_convert_pdfa_format(
self,
client: GotenbergClient,
temporary_dir: Path,
basic_html_file: Path,
tmp_path: Path,
gt_format: PdfAFormat,
pike_format: str,
):
test_file = SAMPLE_DIR / "basic.html"

with client.chromium.html_to_pdf() as route:
resp = route.index(test_file).pdf_format(gt_format).run_with_retry()
resp = route.index(basic_html_file).pdf_format(gt_format).run_with_retry()

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

output = temporary_dir / "test_convert_pdfa_format.pdf"
output = tmp_path / "test_convert_pdfa_format.pdf"
resp.to_file(output)
with pikepdf.open(output) as pdf:
meta = pdf.open_metadata()
assert meta.pdfa_status == pike_format


class TestConvertChromiumHtmlRouteMocked:
def test_convert_page_size(self, client: GotenbergClient, httpx_mock: HTTPXMock):
def test_convert_page_size(self, client: GotenbergClient, sample_directory: Path, httpx_mock: HTTPXMock):
httpx_mock.add_response(method="POST")
test_file = SAMPLE_DIR / "basic.html"
test_file = sample_directory / "basic.html"

with client.chromium.html_to_pdf() as route:
_ = route.index(test_file).size(A4).run()
Expand All @@ -101,9 +100,9 @@ def test_convert_page_size(self, client: GotenbergClient, httpx_mock: HTTPXMock)
verify_stream_contains("paperWidth", "8.27", request.stream)
verify_stream_contains("paperHeight", "11.7", request.stream)

def test_convert_margin(self, client: GotenbergClient, httpx_mock: HTTPXMock):
def test_convert_margin(self, client: GotenbergClient, sample_directory: Path, httpx_mock: HTTPXMock):
httpx_mock.add_response(method="POST")
test_file = SAMPLE_DIR / "basic.html"
test_file = sample_directory / "basic.html"

with client.chromium.html_to_pdf() as route:
_ = (
Expand All @@ -125,9 +124,9 @@ def test_convert_margin(self, client: GotenbergClient, httpx_mock: HTTPXMock):
verify_stream_contains("marginLeft", "3mm", request.stream)
verify_stream_contains("marginRight", "4", request.stream)

def test_convert_render_control(self, client: GotenbergClient, httpx_mock: HTTPXMock):
def test_convert_render_control(self, client: GotenbergClient, sample_directory: Path, httpx_mock: HTTPXMock):
httpx_mock.add_response(method="POST")
test_file = SAMPLE_DIR / "basic.html"
test_file = sample_directory / "basic.html"

with client.chromium.html_to_pdf() as route:
_ = route.index(test_file).render_wait(500.0).run()
Expand All @@ -142,11 +141,12 @@ def test_convert_render_control(self, client: GotenbergClient, httpx_mock: HTTPX
def test_convert_orientation(
self,
client: GotenbergClient,
sample_directory: Path,
httpx_mock: HTTPXMock,
orientation: PageOrientation,
):
httpx_mock.add_response(method="POST")
test_file = SAMPLE_DIR / "basic.html"
test_file = sample_directory / "basic.html"

with client.chromium.html_to_pdf() as route:
_ = route.index(test_file).orient(orientation).run()
Expand Down
27 changes: 19 additions & 8 deletions tests/test_convert_chromium_markdown.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,32 @@
# SPDX-FileCopyrightText: 2023-present Trenton H <[email protected]>
#
# SPDX-License-Identifier: MPL-2.0
from pathlib import Path

from httpx import codes

from gotenberg_client import GotenbergClient
from tests.conftest import SAMPLE_DIR


class TestConvertChromiumUrlRoute:
def test_basic_convert(self, client: GotenbergClient):
index = SAMPLE_DIR / "markdown_index.html"
md_files = [SAMPLE_DIR / "markdown1.md", SAMPLE_DIR / "markdown2.md"]
img = SAMPLE_DIR / "img.gif"
font = SAMPLE_DIR / "font.woff"
style = SAMPLE_DIR / "style.css"
def test_basic_convert(
self,
client: GotenbergClient,
markdown_index_file: Path,
markdown_sample_one_file: Path,
markdown_sample_two_file: Path,
img_gif_file: Path,
font_file: Path,
css_style_file: Path,
):
with client.chromium.markdown_to_pdf() as route:
resp = route.index(index).markdown_files(md_files).resources([img, font]).resource(style).run_with_retry()
resp = (
route.index(markdown_index_file)
.markdown_files([markdown_sample_one_file, markdown_sample_two_file])
.resources([img_gif_file, font_file])
.resource(css_style_file)
.run_with_retry()
)

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