mockstack 0.5.0__tar.gz → 0.5.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mockstack-0.5.0 → mockstack-0.5.2}/PKG-INFO +1 -1
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/display.py +2 -2
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/middleware.py +5 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/strategies/base.py +9 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/strategies/create_mixin.py +14 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/strategies/filefixtures.py +10 -1
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/strategies/proxyrules.py +27 -5
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/tests/conftest.py +11 -1
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/tests/strategies/test_filefixtures.py +6 -3
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/tests/strategies/test_proxyrules.py +10 -5
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/tests/test_display.py +1 -1
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack.egg-info/PKG-INFO +1 -1
- {mockstack-0.5.0 → mockstack-0.5.2}/.env.example +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/.github/workflows/ci.yml +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/.github/workflows/publish-docs.yml +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/.github/workflows/publish-to-pypi.yml +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/.gitignore +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/.pre-commit-config.yaml +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/CODE_OF_CONDUCT.md +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/LICENSE +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/README.md +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/SECURITY.md +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/docs/assets/favicon.ico +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/docs/assets/logo.png +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/docs/assets/mockstack.png +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/examples/filefixtures-with-templates/.env.example +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/examples/filefixtures-with-templates/README.md +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/examples/filefixtures-with-templates/templates/servicename-api-v1-items.j2 +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/examples/filefixtures-with-templates/templates/servicename2-api-v2-user.533ec889-7c68-45c8-b21e-4a7e455d1234.j2 +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/examples/proxyrules-with-rules-file/.env.example +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/examples/proxyrules-with-rules-file/README.md +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/examples/proxyrules-with-rules-file/rules.yml +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mkdocs.yml +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/__init__.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/config.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/constants.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/identifiers.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/intent.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/lifespan.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/main.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/routers/__init__.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/routers/catchall.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/routers/homepage.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/strategies/__init__.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/strategies/factory.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/telemetry.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/templating.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/tests/__init__.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/tests/fixtures/proxyrules.yml +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/tests/fixtures/templates/__init__.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/tests/fixtures/templates/example-template.j2 +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/tests/routers/__init__.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/tests/routers/test_catchall.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/tests/routers/test_homepage.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/tests/test_identifiers.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/tests/test_middleware.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack/tests/test_templating.py +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack.egg-info/SOURCES.txt +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack.egg-info/dependency_links.txt +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack.egg-info/entry_points.txt +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack.egg-info/requires.txt +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/mockstack.egg-info/top_level.txt +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/pyproject.toml +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/setup.cfg +0 -0
- {mockstack-0.5.0 → mockstack-0.5.2}/uv.lock +0 -0
|
@@ -20,8 +20,8 @@ def announce(app: FastAPI, settings: Settings):
|
|
|
20
20
|
)
|
|
21
21
|
logger.info(str(app.state.strategy), extra=extra)
|
|
22
22
|
logger.info(
|
|
23
|
-
f"OpenTelemetry enabled: [medium_purple]{settings.opentelemetry.enabled}[/medium_purple]
|
|
24
|
-
f"endpoint: [medium_purple]{settings.opentelemetry.endpoint}[/medium_purple]
|
|
23
|
+
f"[medium_purple]OpenTelemetry[/medium_purple] enabled: [medium_purple]{settings.opentelemetry.enabled}[/medium_purple],\n "
|
|
24
|
+
f"endpoint: [medium_purple]{settings.opentelemetry.endpoint}[/medium_purple],\n "
|
|
25
25
|
f"capture_response_body: [medium_purple]{settings.opentelemetry.capture_response_body}[/medium_purple]",
|
|
26
26
|
extra=extra,
|
|
27
27
|
)
|
|
@@ -36,6 +36,11 @@ def middleware_provider(app: FastAPI, settings: Settings) -> None:
|
|
|
36
36
|
request, span, sensitive_headers=SENSITIVE_HEADERS
|
|
37
37
|
)
|
|
38
38
|
|
|
39
|
+
# Make the current opentelemetry span available to the request.
|
|
40
|
+
# This is useful for strategies that need to add custom attributes
|
|
41
|
+
# to the span associated with the request.
|
|
42
|
+
request.state.span = span
|
|
43
|
+
|
|
39
44
|
response = await call_next(request)
|
|
40
45
|
|
|
41
46
|
span = with_response_attributes(
|
|
@@ -17,3 +17,12 @@ class BaseStrategy(ABC):
|
|
|
17
17
|
async def apply(self, request: Request) -> Response:
|
|
18
18
|
"""Apply the strategy to the request and response."""
|
|
19
19
|
pass
|
|
20
|
+
|
|
21
|
+
def update_opentelemetry(self, request: Request, *args, **kwargs) -> None:
|
|
22
|
+
"""Update the opentelemetry span with strategy-specific attributes.
|
|
23
|
+
|
|
24
|
+
A span is made available on `request.state.span` to use.
|
|
25
|
+
When OpenTelemetry is not enabled, this span will exist but will not be reported.
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
pass
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from datetime import datetime, timezone
|
|
4
4
|
from uuid import uuid4
|
|
5
|
+
import json
|
|
5
6
|
|
|
6
7
|
from fastapi import Request, Response, status
|
|
7
8
|
from fastapi.responses import JSONResponse
|
|
@@ -16,6 +17,9 @@ class CreateMixin:
|
|
|
16
17
|
async def _create(
|
|
17
18
|
self, request: Request, *, env: Environment, created_resource_metadata: dict
|
|
18
19
|
) -> Response:
|
|
20
|
+
"""Simulate creation of a resource."""
|
|
21
|
+
self._create_mixin_update_opentelemetry(request, created_resource_metadata)
|
|
22
|
+
|
|
19
23
|
if wants_json(request):
|
|
20
24
|
# We return a 201 CREATED response with the resource as the body,
|
|
21
25
|
# potentially injecting the resource ID into the response.
|
|
@@ -79,3 +83,13 @@ class CreateMixin:
|
|
|
79
83
|
"uuid4": uuid4,
|
|
80
84
|
"request": request,
|
|
81
85
|
}
|
|
86
|
+
|
|
87
|
+
def _create_mixin_update_opentelemetry(
|
|
88
|
+
self, request: Request, created_resource_metadata: dict
|
|
89
|
+
) -> None:
|
|
90
|
+
"""Update the opentelemetry span with the create mixin details."""
|
|
91
|
+
span = request.state.span
|
|
92
|
+
span.set_attribute(
|
|
93
|
+
"mockstack.create_mixin.created_resource_metadata",
|
|
94
|
+
json.dumps(created_resource_metadata),
|
|
95
|
+
)
|
|
@@ -39,7 +39,7 @@ class FileFixturesStrategy(BaseStrategy, CreateMixin):
|
|
|
39
39
|
|
|
40
40
|
def __str__(self) -> str:
|
|
41
41
|
return (
|
|
42
|
-
f"[medium_purple]filefixtures[/medium_purple] "
|
|
42
|
+
f"[medium_purple]filefixtures[/medium_purple]\n "
|
|
43
43
|
f"templates_dir: [medium_purple]{self.templates_dir}[/medium_purple]. "
|
|
44
44
|
)
|
|
45
45
|
|
|
@@ -129,6 +129,7 @@ class FileFixturesStrategy(BaseStrategy, CreateMixin):
|
|
|
129
129
|
continue
|
|
130
130
|
|
|
131
131
|
self.logger.debug("Found template filename: %s", filename)
|
|
132
|
+
self.update_opentelemetry(request, template_args)
|
|
132
133
|
template = self.env.get_template(template_args["name"])
|
|
133
134
|
|
|
134
135
|
return Response(
|
|
@@ -149,3 +150,11 @@ class FileFixturesStrategy(BaseStrategy, CreateMixin):
|
|
|
149
150
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
150
151
|
)
|
|
151
152
|
"""
|
|
153
|
+
|
|
154
|
+
def update_opentelemetry(self, request: Request, template_args: dict) -> None:
|
|
155
|
+
"""Update the opentelemetry span with the file fixtures details."""
|
|
156
|
+
span = request.state.span
|
|
157
|
+
|
|
158
|
+
span.set_attribute(
|
|
159
|
+
"mockstack.filefixtures.template_name", template_args["name"]
|
|
160
|
+
)
|
|
@@ -23,10 +23,17 @@ from mockstack.strategies.create_mixin import CreateMixin
|
|
|
23
23
|
class Rule:
|
|
24
24
|
"""A rule for the proxy rules strategy."""
|
|
25
25
|
|
|
26
|
-
def __init__(
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
pattern: str,
|
|
29
|
+
replacement: str,
|
|
30
|
+
method: str | None = None,
|
|
31
|
+
name: str | None = None,
|
|
32
|
+
):
|
|
27
33
|
self.pattern = pattern
|
|
28
34
|
self.replacement = replacement
|
|
29
35
|
self.method = method
|
|
36
|
+
self.name = name
|
|
30
37
|
|
|
31
38
|
@classmethod
|
|
32
39
|
def from_dict(cls, data: dict[str, str]) -> Self:
|
|
@@ -34,6 +41,7 @@ class Rule:
|
|
|
34
41
|
pattern=data["pattern"],
|
|
35
42
|
replacement=data["replacement"],
|
|
36
43
|
method=data.get("method", None),
|
|
44
|
+
name=data.get("name", None),
|
|
37
45
|
)
|
|
38
46
|
|
|
39
47
|
def matches(self, request: Request) -> bool:
|
|
@@ -69,10 +77,11 @@ class ProxyRulesStrategy(BaseStrategy, CreateMixin):
|
|
|
69
77
|
|
|
70
78
|
def __str__(self) -> str:
|
|
71
79
|
return (
|
|
72
|
-
f"[medium_purple]proxyrules[/medium_purple] "
|
|
73
|
-
f"rules_filename:
|
|
74
|
-
f"redirect_via: [medium_purple]{self.redirect_via}[/medium_purple]
|
|
75
|
-
f"simulate_create_on_missing:
|
|
80
|
+
f"[medium_purple]proxyrules[/medium_purple]\n "
|
|
81
|
+
f"rules_filename: {self.rules_filename}.\n "
|
|
82
|
+
f"redirect_via: [medium_purple]{self.redirect_via}[/medium_purple].\n "
|
|
83
|
+
f"simulate_create_on_missing: {self.simulate_create_on_missing}.\n "
|
|
84
|
+
f"reverse_proxy_timeout: {self.reverse_proxy_timeout}"
|
|
76
85
|
)
|
|
77
86
|
|
|
78
87
|
@cached_property
|
|
@@ -115,6 +124,7 @@ class ProxyRulesStrategy(BaseStrategy, CreateMixin):
|
|
|
115
124
|
|
|
116
125
|
url = rule.apply(request)
|
|
117
126
|
self.logger.info(f"Redirecting to: {url}")
|
|
127
|
+
self.update_opentelemetry(request, rule, url)
|
|
118
128
|
|
|
119
129
|
match self.redirect_via:
|
|
120
130
|
case ProxyRulesRedirectVia.HTTP_TEMPORARY_REDIRECT:
|
|
@@ -165,3 +175,15 @@ class ProxyRulesStrategy(BaseStrategy, CreateMixin):
|
|
|
165
175
|
_headers["host"] = urlparse(url).netloc
|
|
166
176
|
|
|
167
177
|
return _headers
|
|
178
|
+
|
|
179
|
+
def update_opentelemetry(self, request: Request, rule: Rule, url: str) -> None:
|
|
180
|
+
"""Update the opentelemetry span with the proxy rules rule details."""
|
|
181
|
+
span = request.state.span
|
|
182
|
+
if rule.name is not None:
|
|
183
|
+
span.set_attribute("mockstack.proxyrules.rule_name", rule.name)
|
|
184
|
+
if rule.method is not None:
|
|
185
|
+
span.set_attribute("mockstack.proxyrules.rule_method", rule.method)
|
|
186
|
+
|
|
187
|
+
span.set_attribute("mockstack.proxyrules.rule_pattern", rule.pattern)
|
|
188
|
+
span.set_attribute("mockstack.proxyrules.rule_replacement", rule.replacement)
|
|
189
|
+
span.set_attribute("mockstack.proxyrules.rewritten_url", url)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Shared fixtures for the unit-tests."""
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
+
from unittest.mock import MagicMock
|
|
4
5
|
|
|
5
6
|
import pytest
|
|
6
7
|
from fastapi import FastAPI
|
|
@@ -11,10 +12,19 @@ from mockstack.strategies.filefixtures import FileFixturesStrategy
|
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
@pytest.fixture
|
|
14
|
-
def
|
|
15
|
+
def span():
|
|
16
|
+
"""Create a mock span object for testing."""
|
|
17
|
+
span = MagicMock()
|
|
18
|
+
span.set_attribute = MagicMock()
|
|
19
|
+
return span
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.fixture
|
|
23
|
+
def app(settings, span):
|
|
15
24
|
"""Create a FastAPI app for testing."""
|
|
16
25
|
app = FastAPI()
|
|
17
26
|
app.state.strategy = FileFixturesStrategy(settings)
|
|
27
|
+
app.state.span = span
|
|
18
28
|
return app
|
|
19
29
|
|
|
20
30
|
|
|
@@ -18,7 +18,7 @@ def test_filefixtures_strategy_init(settings):
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
@pytest.mark.asyncio
|
|
21
|
-
async def test_filefixtures_strategy_apply(settings):
|
|
21
|
+
async def test_filefixtures_strategy_apply(settings, span):
|
|
22
22
|
"""Test the FileFixturesStrategy apply method."""
|
|
23
23
|
strategy = FileFixturesStrategy(settings)
|
|
24
24
|
request = Request(
|
|
@@ -30,6 +30,7 @@ async def test_filefixtures_strategy_apply(settings):
|
|
|
30
30
|
"headers": [],
|
|
31
31
|
}
|
|
32
32
|
)
|
|
33
|
+
request.state.span = span
|
|
33
34
|
|
|
34
35
|
with pytest.raises(HTTPException) as exc_info:
|
|
35
36
|
await strategy.apply(request)
|
|
@@ -38,7 +39,7 @@ async def test_filefixtures_strategy_apply(settings):
|
|
|
38
39
|
|
|
39
40
|
|
|
40
41
|
@pytest.mark.asyncio
|
|
41
|
-
async def test_file_fixtures_strategy_apply_success(settings):
|
|
42
|
+
async def test_file_fixtures_strategy_apply_success(settings, span):
|
|
42
43
|
"""Test the FileFixturesStrategy apply method when template exists."""
|
|
43
44
|
# Setup
|
|
44
45
|
strategy = FileFixturesStrategy(settings)
|
|
@@ -61,6 +62,7 @@ async def test_file_fixtures_strategy_apply_success(settings):
|
|
|
61
62
|
"headers": [],
|
|
62
63
|
}
|
|
63
64
|
)
|
|
65
|
+
request.state.span = span
|
|
64
66
|
|
|
65
67
|
# Execute
|
|
66
68
|
response = await strategy.apply(request)
|
|
@@ -72,7 +74,7 @@ async def test_file_fixtures_strategy_apply_success(settings):
|
|
|
72
74
|
|
|
73
75
|
|
|
74
76
|
@pytest.mark.asyncio
|
|
75
|
-
async def test_file_fixtures_strategy_apply_template_not_found(settings):
|
|
77
|
+
async def test_file_fixtures_strategy_apply_template_not_found(settings, span):
|
|
76
78
|
"""Test the FileFixturesStrategy apply method when template doesn't exist."""
|
|
77
79
|
# Setup
|
|
78
80
|
strategy = FileFixturesStrategy(settings)
|
|
@@ -88,6 +90,7 @@ async def test_file_fixtures_strategy_apply_template_not_found(settings):
|
|
|
88
90
|
"headers": [],
|
|
89
91
|
}
|
|
90
92
|
)
|
|
93
|
+
request.state.span = span
|
|
91
94
|
|
|
92
95
|
# Execute and Assert
|
|
93
96
|
with pytest.raises(HTTPException) as exc_info:
|
|
@@ -124,7 +124,7 @@ def test_proxy_rules_strategy_load_rules(settings):
|
|
|
124
124
|
assert all(isinstance(rule, Rule) for rule in rules)
|
|
125
125
|
|
|
126
126
|
|
|
127
|
-
def test_proxy_rules_strategy_rule_for(settings):
|
|
127
|
+
def test_proxy_rules_strategy_rule_for(settings, span):
|
|
128
128
|
"""Test finding a matching rule for a request."""
|
|
129
129
|
strategy = ProxyRulesStrategy(settings)
|
|
130
130
|
request = Request(
|
|
@@ -136,12 +136,13 @@ def test_proxy_rules_strategy_rule_for(settings):
|
|
|
136
136
|
"headers": [],
|
|
137
137
|
}
|
|
138
138
|
)
|
|
139
|
+
request.state.span = span
|
|
139
140
|
rule = strategy.rule_for(request)
|
|
140
141
|
assert rule is not None
|
|
141
142
|
assert isinstance(rule, Rule)
|
|
142
143
|
|
|
143
144
|
|
|
144
|
-
def test_proxy_rules_strategy_rule_for_no_match(settings):
|
|
145
|
+
def test_proxy_rules_strategy_rule_for_no_match(settings, span):
|
|
145
146
|
"""Test when no rule matches a request."""
|
|
146
147
|
strategy = ProxyRulesStrategy(settings)
|
|
147
148
|
request = Request(
|
|
@@ -153,12 +154,13 @@ def test_proxy_rules_strategy_rule_for_no_match(settings):
|
|
|
153
154
|
"headers": [],
|
|
154
155
|
}
|
|
155
156
|
)
|
|
157
|
+
request.state.span = span
|
|
156
158
|
rule = strategy.rule_for(request)
|
|
157
159
|
assert rule is None
|
|
158
160
|
|
|
159
161
|
|
|
160
162
|
@pytest.mark.asyncio
|
|
161
|
-
async def test_proxy_rules_strategy_apply(settings):
|
|
163
|
+
async def test_proxy_rules_strategy_apply(settings, span):
|
|
162
164
|
"""Test applying a rule to a request."""
|
|
163
165
|
strategy = ProxyRulesStrategy(settings)
|
|
164
166
|
request = Request(
|
|
@@ -170,13 +172,14 @@ async def test_proxy_rules_strategy_apply(settings):
|
|
|
170
172
|
"headers": [],
|
|
171
173
|
}
|
|
172
174
|
)
|
|
175
|
+
request.state.span = span
|
|
173
176
|
response = await strategy.apply(request)
|
|
174
177
|
assert isinstance(response, RedirectResponse)
|
|
175
178
|
assert response.headers["location"] == "/projects/123"
|
|
176
179
|
|
|
177
180
|
|
|
178
181
|
@pytest.mark.asyncio
|
|
179
|
-
async def test_proxy_rules_strategy_apply_no_match(settings):
|
|
182
|
+
async def test_proxy_rules_strategy_apply_no_match(settings, span):
|
|
180
183
|
"""Test applying strategy when no rule matches."""
|
|
181
184
|
strategy = ProxyRulesStrategy(settings)
|
|
182
185
|
request = Request(
|
|
@@ -188,13 +191,14 @@ async def test_proxy_rules_strategy_apply_no_match(settings):
|
|
|
188
191
|
"headers": [],
|
|
189
192
|
}
|
|
190
193
|
)
|
|
194
|
+
request.state.span = span
|
|
191
195
|
response = await strategy.apply(request)
|
|
192
196
|
assert response.status_code == 404
|
|
193
197
|
|
|
194
198
|
|
|
195
199
|
@pytest.mark.asyncio
|
|
196
200
|
@pytest.mark.skip(reason="TODO: Fix this test")
|
|
197
|
-
async def test_proxy_rules_strategy_apply_reverse_proxy(settings_reverse_proxy):
|
|
201
|
+
async def test_proxy_rules_strategy_apply_reverse_proxy(settings_reverse_proxy, span):
|
|
198
202
|
"""Test applying a rule to a request with reverse proxy enabled."""
|
|
199
203
|
# Mock the httpx.AsyncClient to avoid making real HTTP requests
|
|
200
204
|
mock_response = MagicMock() # Use MagicMock for response to avoid async attributes
|
|
@@ -218,6 +222,7 @@ async def test_proxy_rules_strategy_apply_reverse_proxy(settings_reverse_proxy):
|
|
|
218
222
|
"headers": [("host", "example.com")],
|
|
219
223
|
}
|
|
220
224
|
)
|
|
225
|
+
request.state.span = span
|
|
221
226
|
response = await strategy.apply(request)
|
|
222
227
|
|
|
223
228
|
# Verify the response
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|