Skip to content

Commit 9f23a7d

Browse files
authored
feat(test-tools): SaaS/Enterprise mode markers, update documentation (#53)
* feat(test-tools): SaaS/Enterprise mode markers, update documentation
1 parent 8e2b042 commit 9f23a7d

File tree

6 files changed

+122
-6
lines changed

6 files changed

+122
-6
lines changed

README.md

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,56 @@ make install-packages opts="--extras 'feature1 feature2'"
4646

4747
#### Installation
4848

49-
1. Make sure `"common.core"` is in the `INSTALLED_APPS` of your settings module.
49+
1. To make use of the `test_tools` Pytest plugin, install the packages with the `test-tools` extra, e.g. `pip install flagsmith-common[test-tools]`.
50+
51+
2. Make sure `"common.core"` is in the `INSTALLED_APPS` of your settings module.
5052
This enables the `manage.py flagsmith` commands.
5153

52-
2. Add `"common.gunicorn.middleware.RouteLoggerMiddleware"` to `MIDDLEWARE` in your settings module.
54+
3. Add `"common.gunicorn.middleware.RouteLoggerMiddleware"` to `MIDDLEWARE` in your settings module.
5355
This enables the `route` label for Prometheus HTTP metrics.
5456

55-
3. To enable the `/metrics` endpoint, set the `PROMETHEUS_ENABLED` setting to `True`.
57+
4. To enable the `/metrics` endpoint, set the `PROMETHEUS_ENABLED` setting to `True`.
58+
59+
#### Test tools
60+
61+
##### Fixtures
62+
63+
###### `assert_metric`
64+
65+
To test your metrics using the `assert_metric` fixture:
66+
67+
```python
68+
from common.test_tools import AssertMetricFixture
69+
70+
def test_my_code__expected_metrics(assert_metric: AssertMetricFixture) -> None:
71+
# When
72+
my_code()
73+
74+
# Then
75+
assert_metric(
76+
name="flagsmith_distance_from_earth_au_sum",
77+
labels={"engine_type": "solar_sail"},
78+
value=1.0,
79+
)
80+
```
81+
82+
###### `saas_mode`
83+
84+
The `saas_mode` fixture makes all `common.core.utils.is_saas` calls return `True`.
85+
86+
###### `enterprise_mode`
87+
88+
The `enterprise_mode` fixture makes all `common.core.utils.is_enterprise` calls return `True`.
89+
90+
##### Markers
91+
92+
###### `pytest.mark.saas_mode`
93+
94+
Use this mark to auto-use the `saas_mode` fixture.
95+
96+
###### `pytest.mark.enterprise_mode`
97+
98+
Use this mark to auto-use the `enterprise_mode` fixture.
5699

57100
#### Metrics
58101

@@ -87,14 +130,18 @@ It's generally a good idea to allow users to define histogram buckets of their o
87130
import prometheus_client
88131
from django.conf import settings
89132

90-
flagsmith_distance_from_earth_au = prometheus.Histogram(
133+
flagsmith_distance_from_earth_au = prometheus_client.Histogram(
91134
"flagsmith_distance_from_earth_au",
92135
"Distance from Earth in astronomical units",
136+
labels=["engine_type"],
93137
buckets=settings.DISTANCE_FROM_EARTH_AU_HISTOGRAM_BUCKETS,
94138
)
95139
```
96140

141+
For testing your metrics, refer to [`assert_metric` documentation][5].
142+
97143
[1]: https://prometheus.io/docs/practices/naming/
98144
[2]: https://github.com/Flagsmith/flagsmith-common/blob/main/src/common/gunicorn/metrics.py
99145
[3]: https://docs.gunicorn.org/en/stable/design.html#server-model
100146
[4]: https://prometheus.github.io/client_python/multiprocess
147+
[5]: #assert_metric

poetry.lock

Lines changed: 5 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ dependencies = [
1818
"psycopg2-binary (>=2.9,<3)",
1919
"simplejson (>=3,<4)",
2020
]
21+
optional-dependencies = { test-tools = ["pyfakefs (>=5,<6)"] }
2122
authors = [
2223
{ name = "Matthew Elwell" },
2324
{ name = "Gagan Trivedi" },

src/common/test_tools/plugin.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import prometheus_client
44
import pytest
55
from prometheus_client.metrics import MetricWrapperBase
6+
from pyfakefs.fake_filesystem import FakeFilesystem
67

78
from common.test_tools.types import AssertMetricFixture
89

@@ -32,3 +33,38 @@ def _assert_metric(
3233

3334

3435
assert_metric = pytest.fixture(assert_metric_impl)
36+
37+
38+
@pytest.fixture()
39+
def saas_mode(fs: FakeFilesystem) -> Generator[None, None, None]:
40+
from common.core.utils import is_saas
41+
42+
is_saas.cache_clear()
43+
fs.create_file("./SAAS_DEPLOYMENT")
44+
45+
yield
46+
47+
is_saas.cache_clear()
48+
49+
50+
@pytest.fixture()
51+
def enterprise_mode(fs: FakeFilesystem) -> Generator[None, None, None]:
52+
from common.core.utils import is_enterprise
53+
54+
is_enterprise.cache_clear()
55+
fs.create_file("./ENTERPRISE_VERSION")
56+
57+
yield
58+
59+
is_enterprise.cache_clear()
60+
61+
62+
@pytest.fixture(autouse=True)
63+
def flagsmith_markers_marked(
64+
request: pytest.FixtureRequest,
65+
) -> None:
66+
for marker in request.node.iter_markers():
67+
if marker.name == "saas_mode":
68+
request.getfixturevalue("saas_mode")
69+
if marker.name == "enterprise_mode":
70+
request.getfixturevalue("enterprise_mode")

src/common/test_tools/utils.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from typing import Literal
2+
3+
from common.core.utils import is_enterprise, is_saas
4+
5+
6+
def edition_printer() -> Literal["saas!", "enterprise!", "oss!"]:
7+
if is_saas():
8+
return "saas!"
9+
if is_enterprise():
10+
return "enterprise!"
11+
return "oss!"

tests/unit/common/test_tools/test_plugin.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from common.test_tools import AssertMetricFixture
55
from common.test_tools.plugin import assert_metric_impl
6+
from common.test_tools.utils import edition_printer
67

78

89
def test_assert_metrics__asserts_expected(
@@ -37,3 +38,20 @@ def test_assert_metrics__registry_reset_expected(
3738
labels={"test_name": "test_assert_metrics__registry_reset_expected"},
3839
value=1,
3940
)
41+
42+
43+
def test_no_marker__oss_edition_expected() -> None:
44+
# When & Then
45+
assert edition_printer() == "oss!"
46+
47+
48+
@pytest.mark.saas_mode
49+
def test_saas_mode_marker__is_saas_returns_expected() -> None:
50+
# When & Then
51+
assert edition_printer() == "saas!"
52+
53+
54+
@pytest.mark.enterprise_mode
55+
def test_enterprise_mode_marker__is_enterprise_returns_expected() -> None:
56+
# When & Then
57+
assert edition_printer() == "enterprise!"

0 commit comments

Comments
 (0)