Loading data/nginx/server.conf +6 −1 Original line number Diff line number Diff line Loading @@ -8,6 +8,11 @@ map $http_x_forwarded_proto $forwarded_https { https on; } map $arg_ver $cache_control { "" "public, max-age=7776000, stale-while-revalidate=86400, stale-if-error=604800"; default "public, max-age=7776000, immutable"; } server { listen 80; server_name _; Loading @@ -23,7 +28,7 @@ server { real_ip_header X-Forwarded-For; # Add Cache-Control headers for static files, removed in *.php location add_header Cache-Control "public, max-age=7776000, stale-while-revalidate=86400, stale-if-error=604800"; add_header Cache-Control "$cache_control"; error_page 404 /errors/generated/404.html; error_page 502 /errors/static/502.html; Loading tests/static-assets.feature 0 → 100644 +11 −0 Original line number Diff line number Diff line Feature: Static assests in Wordpress are served by the Nginx image, which must configure any response headers itself. Scenario: Assets with a 'ver' parameter get a Cache-Control header with "immutable" When /wp-includes/js/jquery/jquery.min.js?ver=3.7.1 is requested Then the Cache-Control header contains "immutable" Scenario: Assets without a 'ver' parameter get a Cache-Control header without "immutable" When /wp-includes/js/jquery/jquery.min.js is requested Then the Cache-Control header contains "max-age" And the Cache-Control header does not contain "immutable" tests/steps/request_steps.py +52 −5 Original line number Diff line number Diff line # Copyright 2021-2023 Dominik Sekotill <dom.sekotill@kodo.org.uk> # Copyright 2021-2024 Dominik Sekotill <dom.sekotill@kodo.org.uk> # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this Loading @@ -25,6 +25,7 @@ from behave.runner import Context from behave_utils import URL from behave_utils import PatternEnum from behave_utils.http import redirect from requests import Response from requests import Session from wp import running_site_fixture Loading Loading @@ -156,19 +157,65 @@ def assert_response(context: Context, response: ResponseCode) -> None: f"Expected response {response}: got {context.response.status_code}" @then('''the {header_name} header contains "{header_value}"''') @then('''the "{header_name}" header contains "{header_value}"''') def assert_header_contains(context: Context, header_name: str, header_value: str) -> None: """ Assert that an expected header was received during a previous step, matching a substring """ value = get_header(context, header_name) assert normalise_header_value(context, header_value) in value, \ f"Expected header value not found: got {value}" @then('''the {header_name} header does not contain "{header_value}"''') @then('''the "{header_name}" header does not contain "{header_value}"''') def assert_header_missing(context: Context, header_name: str, header_value: str) -> None: """ Assert that an expected header was received during a previous step, without a substring """ value = get_header(context, header_name) assert normalise_header_value(context, header_value) not in value, \ f"Unwanted header value found: {value}" @then('''the {header_name} header's value is "{header_value}"''') @then('''the "{header_name}" header's value is "{header_value}"''') def assert_header(context: Context, header_name: str, header_value: str) -> None: """ Assert that an expected header was received during a previous step """ value = get_header(context, header_name) assert normalise_header_value(context, header_value) == value, \ f"Expected header value not found: got {value}" def normalise_header_value(context: Context, header_value: str) -> str: """ Replace any sample HTTP URL hosts with the actual host name for fixtures """ if SAMPLE_SITE_NAME in header_value: site = use_fixture(running_site_fixture, context) header_value = header_value.replace(SAMPLE_SITE_NAME, site.url) headers = context.response.headers return header_value.replace(SAMPLE_SITE_NAME, site.url) return header_value def get_header(context: Context, header_name: str) -> str: """ Assert a header exists in a response and return it """ headers = get_response(context).headers assert header_name in headers, \ f"Expected header not found in response: {header_name!r}" assert headers[header_name] == header_value, \ f"Expected header value not found: got {headers[header_name]!r}" return headers[header_name] def get_response(context: Context) -> Response: """ Return the last response received that is stored in the content """ assert isinstance(context.response, Response) return context.response @then("the response body is JSON") Loading Loading
data/nginx/server.conf +6 −1 Original line number Diff line number Diff line Loading @@ -8,6 +8,11 @@ map $http_x_forwarded_proto $forwarded_https { https on; } map $arg_ver $cache_control { "" "public, max-age=7776000, stale-while-revalidate=86400, stale-if-error=604800"; default "public, max-age=7776000, immutable"; } server { listen 80; server_name _; Loading @@ -23,7 +28,7 @@ server { real_ip_header X-Forwarded-For; # Add Cache-Control headers for static files, removed in *.php location add_header Cache-Control "public, max-age=7776000, stale-while-revalidate=86400, stale-if-error=604800"; add_header Cache-Control "$cache_control"; error_page 404 /errors/generated/404.html; error_page 502 /errors/static/502.html; Loading
tests/static-assets.feature 0 → 100644 +11 −0 Original line number Diff line number Diff line Feature: Static assests in Wordpress are served by the Nginx image, which must configure any response headers itself. Scenario: Assets with a 'ver' parameter get a Cache-Control header with "immutable" When /wp-includes/js/jquery/jquery.min.js?ver=3.7.1 is requested Then the Cache-Control header contains "immutable" Scenario: Assets without a 'ver' parameter get a Cache-Control header without "immutable" When /wp-includes/js/jquery/jquery.min.js is requested Then the Cache-Control header contains "max-age" And the Cache-Control header does not contain "immutable"
tests/steps/request_steps.py +52 −5 Original line number Diff line number Diff line # Copyright 2021-2023 Dominik Sekotill <dom.sekotill@kodo.org.uk> # Copyright 2021-2024 Dominik Sekotill <dom.sekotill@kodo.org.uk> # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this Loading @@ -25,6 +25,7 @@ from behave.runner import Context from behave_utils import URL from behave_utils import PatternEnum from behave_utils.http import redirect from requests import Response from requests import Session from wp import running_site_fixture Loading Loading @@ -156,19 +157,65 @@ def assert_response(context: Context, response: ResponseCode) -> None: f"Expected response {response}: got {context.response.status_code}" @then('''the {header_name} header contains "{header_value}"''') @then('''the "{header_name}" header contains "{header_value}"''') def assert_header_contains(context: Context, header_name: str, header_value: str) -> None: """ Assert that an expected header was received during a previous step, matching a substring """ value = get_header(context, header_name) assert normalise_header_value(context, header_value) in value, \ f"Expected header value not found: got {value}" @then('''the {header_name} header does not contain "{header_value}"''') @then('''the "{header_name}" header does not contain "{header_value}"''') def assert_header_missing(context: Context, header_name: str, header_value: str) -> None: """ Assert that an expected header was received during a previous step, without a substring """ value = get_header(context, header_name) assert normalise_header_value(context, header_value) not in value, \ f"Unwanted header value found: {value}" @then('''the {header_name} header's value is "{header_value}"''') @then('''the "{header_name}" header's value is "{header_value}"''') def assert_header(context: Context, header_name: str, header_value: str) -> None: """ Assert that an expected header was received during a previous step """ value = get_header(context, header_name) assert normalise_header_value(context, header_value) == value, \ f"Expected header value not found: got {value}" def normalise_header_value(context: Context, header_value: str) -> str: """ Replace any sample HTTP URL hosts with the actual host name for fixtures """ if SAMPLE_SITE_NAME in header_value: site = use_fixture(running_site_fixture, context) header_value = header_value.replace(SAMPLE_SITE_NAME, site.url) headers = context.response.headers return header_value.replace(SAMPLE_SITE_NAME, site.url) return header_value def get_header(context: Context, header_name: str) -> str: """ Assert a header exists in a response and return it """ headers = get_response(context).headers assert header_name in headers, \ f"Expected header not found in response: {header_name!r}" assert headers[header_name] == header_value, \ f"Expected header value not found: got {headers[header_name]!r}" return headers[header_name] def get_response(context: Context) -> Response: """ Return the last response received that is stored in the content """ assert isinstance(context.response, Response) return context.response @then("the response body is JSON") Loading