Skip to content
Open
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
Empty file added test/modules/brotli/__init__.py
Empty file.
32 changes: 32 additions & 0 deletions test/modules/brotli/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import logging
import os
import sys

import pytest

from .env import BrotliTestEnv

sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))


def pytest_report_header(config, start_path):
env = BrotliTestEnv()
return f"brotli [apache: {env.get_httpd_version()}, mpm: {env.mpm_module}, {env.prefix}]"


@pytest.fixture(scope="package")
def env(pytestconfig) -> BrotliTestEnv:
logging.getLogger('').setLevel(level=logging.INFO)
env = BrotliTestEnv(pytestconfig=pytestconfig)
if not env.has_shared_module("brotli"):
pytest.skip("mod_brotli not available")
env.setup_httpd()
env.apache_access_log_clear()
env.httpd_error_log.clear_log()
return env


@pytest.fixture(autouse=True, scope="package")
def _stop_package_scope(env):
yield
assert env.apache_stop() == 0
25 changes: 25 additions & 0 deletions test/modules/brotli/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import inspect
import logging
import os

from pyhttpd.env import HttpdTestEnv, HttpdTestSetup

log = logging.getLogger(__name__)


class BrotliTestSetup(HttpdTestSetup):

def __init__(self, env: 'HttpdTestEnv'):
super().__init__(env=env)
self.add_source_dir(os.path.dirname(inspect.getfile(BrotliTestSetup)))
self.add_modules(["brotli"])


class BrotliTestEnv(HttpdTestEnv):

def __init__(self, pytestconfig=None):
super().__init__(pytestconfig=pytestconfig)
self.add_httpd_log_modules(["brotli", "core"])

def setup_httpd(self, setup: HttpdTestSetup = None):
super().setup_httpd(setup=BrotliTestSetup(env=self))
1 change: 1 addition & 0 deletions test/modules/brotli/htdocs/test1/greeting.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Good morning, fellow!
19 changes: 19 additions & 0 deletions test/modules/brotli/htdocs/test1/lorem.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
est laborum.

Curabitur pretium tincidunt lacus. Nulla gravida orci a odio. Nullam varius,
turpis et commodo pharetra, est eros bibendum elit, nec luctus magna felis
sollicitudin mauris. Integer in mauris eu nibh euismod gravida. Duis ac
tellus et risus vulputate vehicula. Donec lobortis risus a elit. Etiam
tempor. Ut ullamcorper, ligula ut dictum pharetra, nisi nunc fringilla
magna, in commodo elit erat nec turpis. Ut pharetra augue nec augue.
Nam elit agna, endrerit sit amet, tincidunt ac, viverra sed, nulla.
Donec porta diam eu massa. Quisque diam lorem, interdum vitae, dapibus
ac, scelerisque vitae, pede. Donec eget tellus non erat lacinia fermentum.
Donec in velit vel ipsum auctor pulvinar. Class aptent taciti sociosqu ad
litora torquent per conubia nostra, per inceptos hymenaeos.
89 changes: 89 additions & 0 deletions test/modules/brotli/test_001_compression.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import os

import pytest

from pyhttpd.conf import HttpdConf


class TestBrotliCompression:

@pytest.fixture(autouse=True, scope='class')
def _class_scope(self, env):
conf = HttpdConf(env, extras={
f"test1.{env.http_tld}": """
<Location "/">
AddOutputFilterByType BROTLI_COMPRESS text/plain text/html text/css
</Location>
""",
})
conf.add_vhost_test1()
conf.install()
assert env.apache_restart() == 0

# Request a small text file with Accept-Encoding: br.
# Verify Content-Encoding: br header is present.
def test_brotli_001_01(self, env):
url = env.mkurl("http", "test1", "/greeting.txt")
r = env.curl_get(url, options=[
"-H", "Accept-Encoding: br",
])
assert r.response, "no response"
assert r.response["status"] == 200
assert r.response["header"].get("content-encoding") == "br", \
f"expected Content-Encoding: br, got: {r.response['header']}"
raw_body = r.response["body"]
assert len(raw_body) > 0, "compressed body should not be empty"
original = b"Good morning, fellow!"
assert len(raw_body) != len(original) or raw_body != original, \
"body should be compressed, not plain text"

# Request a larger text file; verify brotli compression is applied.
def test_brotli_001_02(self, env):
url = env.mkurl("http", "test1", "/lorem.txt")
r = env.curl_get(url, options=[
"-H", "Accept-Encoding: br",
])
assert r.response, "no response"
assert r.response["status"] == 200
assert r.response["header"].get("content-encoding") == "br", \
f"expected Content-Encoding: br, got: {r.response['header']}"
lorem_path = os.path.join(env.server_dir, "htdocs", "test1",
"lorem.txt")
orig_size = os.path.getsize(lorem_path)
assert len(r.response["body"]) < orig_size, \
"compressed response should be smaller than the original"

# When the client does not advertise Accept-Encoding: br the response
# must be served uncompressed -- no Content-Encoding header.
def test_brotli_001_03(self, env):
url = env.mkurl("http", "test1", "/greeting.txt")
r = env.curl_get(url)
assert r.response, "no response"
assert r.response["status"] == 200
assert "content-encoding" not in r.response["header"], \
f"unexpected Content-Encoding present: " \
f"{r.response['header'].get('content-encoding')}"
body = r.response["body"].decode()
assert body.strip() == "Good morning, fellow!"

# Binary / non-matching content types must not be compressed.
def test_brotli_001_04(self, env):
bin_dir = os.path.join(env.server_dir, "htdocs", "test1")
bin_path = os.path.join(bin_dir, "pixel.png")
with open(bin_path, "wb") as f:
f.write(
b'\x89PNG\r\n\x1a\n'
b'\x00\x00\x00\rIHDR\x00\x00\x00\x01'
b'\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90wS\xde'
b'\x00\x00\x00\x0cIDATx'
b'\x9cc\xf8\x0f\x00\x00\x01\x01\x00\x05'
b'\x18\xd8N\x00\x00\x00\x00IEND\xaeB`\x82'
)
url = env.mkurl("http", "test1", "/pixel.png")
r = env.curl_get(url, options=[
"-H", "Accept-Encoding: br",
])
assert r.response, "no response"
assert r.response["status"] == 200
assert r.response["header"].get("content-encoding") != "br", \
"binary content should not be brotli-compressed"