Skip to content

Commit 324f88f

Browse files
committed
Test Gunicorn settings
#11 https://docs.gunicorn.org/en/latest/settings.html#print-config https://docs.pytest.org/en/latest/how-to/capture-stdout-stderr.html The Gunicorn configuration file was technically covered by unit tests, but the individual settings were not tested. This commit will add tests of the Gunicorn settings. The tests use Gunicorn's `--print-config` option to load and output the configuration. The pytest fixture `capfd` is used to read the Gunicorn output.
1 parent aaef2f0 commit 324f88f

1 file changed

Lines changed: 80 additions & 0 deletions

File tree

tests/test_gunicorn_conf.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import multiprocessing
2+
import subprocess
3+
from pathlib import Path
24
from typing import Optional
35

46
import pytest
@@ -50,3 +52,81 @@ def test_calculate_workers_both_max_and_total(
5052
"""
5153
result = gunicorn_conf.calculate_workers(max_workers, total_workers)
5254
assert result == min(int(max_workers), int(total_workers))
55+
56+
57+
class TestGunicornSettings:
58+
"""Test Gunicorn configuration setup and settings.
59+
---
60+
"""
61+
62+
@pytest.mark.parametrize("module", ("base", "fastapi", "starlette"))
63+
@pytest.mark.timeout(2)
64+
def test_gunicorn_config(self, capfd: pytest.CaptureFixture, module: str) -> None:
65+
"""Load Gunicorn configuration file and verify output."""
66+
app_module = f"inboard.app.main_{module}:app"
67+
gunicorn_conf_path = gunicorn_conf.__file__
68+
gunicorn_options = [
69+
"gunicorn",
70+
"--print-config",
71+
"-c",
72+
gunicorn_conf_path,
73+
"-k",
74+
"uvicorn.workers.UvicornWorker",
75+
app_module,
76+
]
77+
subprocess.run(gunicorn_options)
78+
captured = capfd.readouterr()
79+
captured_and_cleaned = captured.out.replace(" ", "").splitlines()
80+
assert app_module in captured.out
81+
assert gunicorn_conf_path in captured.out
82+
assert "INFO" in captured.out
83+
assert "uvicorn.logging.DefaultFormatter" in captured.out
84+
assert "graceful_timeout=120" in captured_and_cleaned
85+
assert "keepalive=5" in captured_and_cleaned
86+
assert "loglevel=info" in captured_and_cleaned
87+
assert "timeout=120" in captured_and_cleaned
88+
assert f"workers={max(multiprocessing.cpu_count(), 2)}" in captured_and_cleaned
89+
90+
@pytest.mark.parametrize("module", ("base", "fastapi", "starlette"))
91+
@pytest.mark.timeout(2)
92+
def test_gunicorn_config_with_custom_options(
93+
self,
94+
capfd: pytest.CaptureFixture,
95+
gunicorn_conf_tmp_file_path: Path,
96+
logging_conf_tmp_file_path: Path,
97+
monkeypatch: pytest.MonkeyPatch,
98+
module: str,
99+
) -> None:
100+
"""Customize options, load Gunicorn configuration file and verify output."""
101+
app_module = f"inboard.app.main_{module}:app"
102+
gunicorn_conf_path = str(gunicorn_conf_tmp_file_path)
103+
logging_conf_file = f"{logging_conf_tmp_file_path}/tmp_log.py"
104+
monkeypatch.setenv("GRACEFUL_TIMEOUT", "240")
105+
monkeypatch.setenv("KEEP_ALIVE", "10")
106+
monkeypatch.setenv("LOG_FORMAT", "verbose")
107+
monkeypatch.setenv("LOG_LEVEL", "debug")
108+
monkeypatch.setenv("LOGGING_CONF", logging_conf_file)
109+
monkeypatch.setenv("MAX_WORKERS", "10")
110+
monkeypatch.setenv("TIMEOUT", "240")
111+
monkeypatch.setenv("WEB_CONCURRENCY", "15")
112+
gunicorn_options = [
113+
"gunicorn",
114+
"--print-config",
115+
"-c",
116+
gunicorn_conf_path,
117+
"-k",
118+
"uvicorn.workers.UvicornWorker",
119+
app_module,
120+
]
121+
subprocess.run(gunicorn_options)
122+
captured = capfd.readouterr()
123+
captured_and_cleaned = captured.out.replace(" ", "").splitlines()
124+
assert app_module in captured.out
125+
assert gunicorn_conf_path in captured.out
126+
assert "DEBUG" in captured.out
127+
assert "uvicorn.logging.DefaultFormatter" in captured.out
128+
assert "graceful_timeout=240" in captured_and_cleaned
129+
assert "keepalive=10" in captured_and_cleaned
130+
assert "loglevel=debug" in captured_and_cleaned
131+
assert "timeout=240" in captured_and_cleaned
132+
assert "workers=10" in captured_and_cleaned

0 commit comments

Comments
 (0)