Skip to content

Commit 0cfe793

Browse files
authored
feat: Add product version to API response headers (#5366)
1 parent ee9335d commit 0cfe793

3 files changed

Lines changed: 75 additions & 17 deletions

File tree

api/app/settings/common.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@
285285
],
286286
}
287287
MIDDLEWARE = [
288+
"common.core.middleware.APIResponseVersionHeaderMiddleware",
288289
"common.gunicorn.middleware.RouteLoggerMiddleware",
289290
"django.middleware.security.SecurityMiddleware",
290291
"whitenoise.middleware.WhiteNoiseMiddleware",

api/conftest.py

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import importlib
2-
import inspect
31
import logging
42
import os
3+
import site
54
import typing
65
from unittest.mock import MagicMock
76

@@ -22,7 +21,6 @@
2221
from moto import mock_dynamodb # type: ignore[import-untyped]
2322
from mypy_boto3_dynamodb.service_resource import DynamoDBServiceResource, Table
2423
from pyfakefs.fake_filesystem import FakeFilesystem
25-
from pyfakefs.fake_filesystem_unittest import Patcher
2624
from pytest_django.fixtures import SettingsWrapper
2725
from pytest_django.plugin import blocking_manager_key
2826
from pytest_mock import MockerFixture
@@ -138,21 +136,19 @@ def pytest_configure(config: pytest.Config) -> None:
138136

139137

140138
@pytest.fixture
141-
def fs() -> typing.Generator[FakeFilesystem | None, None, None]:
142-
app_path = os.path.dirname(os.path.abspath(__file__))
143-
real_paths = [app_path]
144-
145-
for module_name in (
146-
"django",
147-
"tzdata",
148-
):
149-
module_file = inspect.getfile(importlib.import_module(module_name))
150-
real_paths.append(os.path.dirname(os.path.abspath(module_file)))
139+
def fs(fs: FakeFilesystem) -> FakeFilesystem:
140+
"""
141+
Provide a fake filesystem for tests
151142
152-
with Patcher() as patcher:
153-
if fs := patcher.fs:
154-
fs.add_real_paths(real_paths)
155-
yield fs
143+
NOTE: Sometimes pyfakefs patching goes wonky, causing the fake file system
144+
to be cached across tests. This can lead tests failing to access real files
145+
even if they do not use this fixture. Because we can't fix this issue now,
146+
it's safer to allow site-packages [read-only] access from tests.
147+
"""
148+
app_path = os.path.dirname(os.path.abspath(__file__))
149+
site_packages = site.getsitepackages() # Allow files within dependencies
150+
fs.add_real_paths([*site_packages, app_path])
151+
return fs
156152

157153

158154
@pytest.fixture(scope="session")
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import pytest
2+
from common.core.utils import get_file_contents, get_versions_from_manifest
3+
from pyfakefs.fake_filesystem import FakeFilesystem
4+
from rest_framework import status
5+
from rest_framework.test import APIClient
6+
7+
8+
@pytest.fixture(autouse=True)
9+
def clear_lru_caches() -> None:
10+
get_file_contents.cache_clear()
11+
get_versions_from_manifest.cache_clear()
12+
13+
14+
@pytest.mark.parametrize(
15+
"url",
16+
[
17+
"/robots.txt",
18+
"/api/v1/auth/users/me/",
19+
],
20+
)
21+
@pytest.mark.parametrize(
22+
"version_file_contents, expected_version",
23+
[
24+
('{".": "v1.2.3"}', "v1.2.3"),
25+
('{"foo": "bar"}', "unknown"),
26+
("", "unknown"),
27+
],
28+
)
29+
def test_api_version_is_added_to_success_response_headers(
30+
admin_client: APIClient,
31+
expected_version: str,
32+
fs: FakeFilesystem,
33+
url: str,
34+
version_file_contents: str,
35+
) -> None:
36+
fs.create_file(".versions.json", contents=version_file_contents)
37+
38+
response = admin_client.get(url)
39+
assert response.status_code == status.HTTP_200_OK
40+
assert response.headers["Flagsmith-Version"] == expected_version
41+
42+
43+
@pytest.mark.parametrize(
44+
"version_file_contents, expected_version",
45+
[
46+
('{".": "v1.2.3"}', "v1.2.3"),
47+
('{"foo": "bar"}', "unknown"),
48+
("", "unknown"),
49+
],
50+
)
51+
def test_api_version_is_added_to_error_response_headers(
52+
client: APIClient,
53+
expected_version: str,
54+
fs: FakeFilesystem,
55+
version_file_contents: str,
56+
) -> None:
57+
fs.create_file(".versions.json", contents=version_file_contents)
58+
59+
response = client.get("/wat")
60+
assert response.status_code == status.HTTP_404_NOT_FOUND
61+
assert response.headers["Flagsmith-Version"] == expected_version

0 commit comments

Comments
 (0)