mockstack 0.14.1__tar.gz → 0.14.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.14.1 → mockstack-0.14.2}/.env.example +4 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/.github/workflows/smoke-test-pypi.yml +15 -6
- {mockstack-0.14.1 → mockstack-0.14.2}/CLAUDE.md +3 -1
- {mockstack-0.14.1 → mockstack-0.14.2}/Dockerfile +1 -1
- {mockstack-0.14.1 → mockstack-0.14.2}/PKG-INFO +1 -1
- {mockstack-0.14.1 → mockstack-0.14.2}/docs/configuration.md +1 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/config.py +5 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/main.py +6 -1
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/test_config.py +24 -0
- mockstack-0.14.2/mockstack/tests/test_main.py +61 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack.egg-info/PKG-INFO +1 -1
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack.egg-info/scm_version.json +2 -2
- mockstack-0.14.1/mockstack/tests/test_main.py +0 -20
- {mockstack-0.14.1 → mockstack-0.14.2}/.dockerignore +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/.github/workflows/ci.yml +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/.github/workflows/publish-docs.yml +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/.github/workflows/publish-to-pypi.yml +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/.gitignore +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/.pre-commit-config.yaml +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/CODE_OF_CONDUCT.md +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/CONTRIBUTING.md +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/LICENSE +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/README.md +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/SECURITY.md +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/docker-entrypoint.sh +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/docs/assets/favicon.ico +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/docs/assets/logo.png +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/docs/assets/mockstack.png +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/docs/guides/proxyrules-cookbook.md +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/docs/ollama.md +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/docs/strategies/base.md +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/docs/strategies/filefixtures.md +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/docs/strategies/proxyrules.md +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/filefixtures-with-templates/.env.example +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/filefixtures-with-templates/README.md +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/filefixtures-with-templates/templates/servicename-api-v1-items.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/filefixtures-with-templates/templates/servicename2-api-v2-user.533ec889-7c68-45c8-b21e-4a7e455d1234.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/llm/README.md +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/llm/mockstack-langchain-example.ipynb +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/llm/templates/ollama-openai-v1-chat-completions.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/llm/templates/openai-v1-chat-completions.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/llm/templates/openai-v1-deployments-gpt-4o-chat-completions.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/01-tagged-traffic/fixtures/projects/project.json.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/01-tagged-traffic/rules.yml +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/02-scenario-directories/fixtures/archived/projects/project.json.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/02-scenario-directories/fixtures/healthy/projects/project.json.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/02-scenario-directories/rules.yml +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/03-sql-gateway/fixtures/analytics/sales_facts.json.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/03-sql-gateway/rules.yml +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/04-json-literals/fixtures/orders/search.json.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/04-json-literals/rules.yml +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/05-query-parameters/fixtures/users/archived.json.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/05-query-parameters/fixtures/users/page.json.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/05-query-parameters/rules.yml +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/06-asserting-in-tests/fixture_assertions.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/06-asserting-in-tests/fixtures/orders/echo.json.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/06-asserting-in-tests/fixtures/projects/project.json.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/06-asserting-in-tests/fixtures/users/user-1.json.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/06-asserting-in-tests/rules.yml +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/07-redirect-mode/fixtures/users/user-1.json.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/07-redirect-mode/rules.yml +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/08-status-and-headers/fixtures/errors/rate-limited.json.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/08-status-and-headers/fixtures/errors/unavailable.json.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/08-status-and-headers/fixtures/orders/created.json.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/08-status-and-headers/rules.yml +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/09-recording/rules.yml +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/09-recording/scrubbers.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/README.md +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/upstream.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-eval-isolation/.env.example +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-eval-isolation/README.md +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-eval-isolation/fixtures/healthy/analytics/sales_facts.json.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-eval-isolation/fixtures/healthy/projects/project.json.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-eval-isolation/rules.yml +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-eval-isolation/upstream.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-with-rules-file/.env.example +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-with-rules-file/README.md +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-with-rules-file/rules.yml +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mkdocs.yml +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/__init__.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/constants.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/display.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/exceptions.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/identifiers.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/intent.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/lifespan.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/llm/__init__.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/llm/ollama.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/middleware.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/recording.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/routers/__init__.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/routers/catchall.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/rules.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/strategies/__init__.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/strategies/base.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/strategies/create_mixin.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/strategies/factory.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/strategies/filefixtures.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/strategies/proxyrules.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/telemetry.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/templating.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/__init__.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/conftest.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/fixtures/__init__.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/fixtures/proxyrules.yml +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/fixtures/templates/__init__.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/fixtures/templates/example-template.j2 +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/live/__init__.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/live/conftest.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/live/test_cookbook.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/live/test_example_eval_isolation.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/live/test_fixture_status_live.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/live/test_predicates_live.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/live/test_record_mode_live.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/live/test_reverse_proxy_live.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/llm/__init__.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/llm/test_ollama.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/routers/__init__.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/routers/test_catchall.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/strategies/__init__.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/strategies/conftest.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/strategies/test_create_mixin.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/strategies/test_filefixtures.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/strategies/test_filefixtures_example.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/strategies/test_proxyrules.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/strategies/test_proxyrules_record.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/test_display.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/test_docs_settings.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/test_docs_yaml.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/test_identifiers.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/test_intent.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/test_middleware.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/test_recording.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/test_rules.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/test_telemetry.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/test_templating.py +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack.egg-info/SOURCES.txt +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack.egg-info/dependency_links.txt +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack.egg-info/entry_points.txt +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack.egg-info/requires.txt +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack.egg-info/scm_file_list.json +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/mockstack.egg-info/top_level.txt +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/pyproject.toml +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/setup.cfg +0 -0
- {mockstack-0.14.1 → mockstack-0.14.2}/uv.lock +0 -0
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
# the strategy to use: filefixtures (the default) or proxyrules
|
|
6
6
|
MOCKSTACK__STRATEGY = filefixtures
|
|
7
7
|
|
|
8
|
+
# serve FastAPI's documentation routes (/docs, /redoc, /openapi.json and
|
|
9
|
+
# /docs/oauth2-redirect) instead of passing those paths to the strategy (default: false)
|
|
10
|
+
MOCKSTACK__OPENAPI_DOCS_ENABLED = false
|
|
11
|
+
|
|
8
12
|
# strategy-specific settings
|
|
9
13
|
|
|
10
14
|
# base dir for all templates. Required by the 'filefixtures' strategy
|
|
@@ -46,16 +46,18 @@ jobs:
|
|
|
46
46
|
run: |
|
|
47
47
|
set -euo pipefail
|
|
48
48
|
mkdir -p /tmp/mockstack-templates
|
|
49
|
+
echo '{"message": "Hello from mockstack!"}' > /tmp/mockstack-templates/index.j2
|
|
49
50
|
uvx mockstack --templates-dir /tmp/mockstack-templates --port 18999 \
|
|
50
51
|
> server.log 2>&1 &
|
|
51
52
|
SERVER_PID=$!
|
|
52
53
|
echo "started mockstack pid=$SERVER_PID"
|
|
53
54
|
|
|
54
|
-
# Poll for readiness for up to 30s. /
|
|
55
|
-
#
|
|
56
|
-
# +
|
|
55
|
+
# Poll for readiness for up to 30s. GET / is rendered from index.j2 by the
|
|
56
|
+
# filefixtures strategy, so a 200 here proves import + app construction +
|
|
57
|
+
# uvicorn boot + request handling are all healthy end-to-end. (FastAPI's
|
|
58
|
+
# /openapi.json is off by default since mockstack 0.14.2.)
|
|
57
59
|
for i in $(seq 1 30); do
|
|
58
|
-
if curl -fsS http://127.0.0.1:18999/
|
|
60
|
+
if curl -fsS http://127.0.0.1:18999/ -o /dev/null; then
|
|
59
61
|
echo "ready after ${i}s"
|
|
60
62
|
READY=1
|
|
61
63
|
break
|
|
@@ -75,8 +77,15 @@ jobs:
|
|
|
75
77
|
exit 1
|
|
76
78
|
fi
|
|
77
79
|
|
|
78
|
-
# Final assertion
|
|
79
|
-
curl -fsS http://127.0.0.1:18999/
|
|
80
|
+
# Final assertion: the strategy rendered the template.
|
|
81
|
+
BODY=$(curl -fsS http://127.0.0.1:18999/)
|
|
82
|
+
echo "GET / -> $BODY"
|
|
83
|
+
if [ "$BODY" != '{"message": "Hello from mockstack!"}' ]; then
|
|
84
|
+
echo "unexpected response; logs:"
|
|
85
|
+
cat server.log
|
|
86
|
+
kill "$SERVER_PID" 2>/dev/null || true
|
|
87
|
+
exit 1
|
|
88
|
+
fi
|
|
80
89
|
echo "smoke test passed"
|
|
81
90
|
|
|
82
91
|
kill "$SERVER_PID" 2>/dev/null || true
|
|
@@ -32,7 +32,9 @@ CLI flags, `MOCKSTACK__*` environment variables, or a `.env` file.
|
|
|
32
32
|
- `mockstack/templating.py`: Jinja environment and path-to-template-name resolution
|
|
33
33
|
- `mockstack/intent.py`, `mockstack/identifiers.py`: POST intent (search, command,
|
|
34
34
|
create) and path-identifier heuristics
|
|
35
|
-
- `mockstack/routers/`: the catch-all route; every path, `/` included, reaches the strategy
|
|
35
|
+
- `mockstack/routers/`: the catch-all route; every path, `/` included, reaches the strategy.
|
|
36
|
+
FastAPI's `/docs`, `/redoc`, `/openapi.json` and `/docs/oauth2-redirect` routes are
|
|
37
|
+
only registered, ahead of the catch-all, when `openapi_docs_enabled` is set
|
|
36
38
|
- `mockstack/tests/`: unit tests; `conftest.py` holds fixtures shared by unit and live
|
|
37
39
|
tests (`make_settings`, `make_request`, `write_rules`, `write_template`, `span`, and
|
|
38
40
|
`asgi_client`, an httpx client that calls the `app` fixture in-process), and
|
|
@@ -22,6 +22,7 @@ options (`--opentelemetry.enabled`); boolean options are flags with a `--no-` fo
|
|
|
22
22
|
| `debug` | boolean | `false` | Whether to run in debug mode |
|
|
23
23
|
| `host` | string | `0.0.0.0` | Host to run the server on |
|
|
24
24
|
| `port` | integer | `8000` | Port to run the server on |
|
|
25
|
+
| `openapi_docs_enabled` | boolean | `false` | Whether to serve FastAPI's documentation routes: `/docs`, `/redoc`, `/openapi.json` and `/docs/oauth2-redirect`. They take precedence over the catch-all route and document only that route, so by default they are off and those paths reach the strategy like any other |
|
|
25
26
|
| `strategy` | string | `filefixtures` | Strategy to use for handling requests. Options: `filefixtures`, `proxyrules` |
|
|
26
27
|
|
|
27
28
|
## OpenTelemetry Settings
|
|
@@ -55,6 +55,11 @@ class Settings(BaseSettings):
|
|
|
55
55
|
# port to run the server on
|
|
56
56
|
port: int = 8000
|
|
57
57
|
|
|
58
|
+
# whether to serve FastAPI's documentation routes (/docs, /redoc, /openapi.json and
|
|
59
|
+
# /docs/oauth2-redirect). They take precedence over the catch-all route, so they are
|
|
60
|
+
# off by default and those paths reach the strategy like any other.
|
|
61
|
+
openapi_docs_enabled: CliImplicitFlag[bool] = False
|
|
62
|
+
|
|
58
63
|
# OpenTelemetry configuration
|
|
59
64
|
opentelemetry: OpenTelemetrySettings = OpenTelemetrySettings()
|
|
60
65
|
|
|
@@ -19,7 +19,12 @@ def create_app(settings: Settings | None = None) -> FastAPI:
|
|
|
19
19
|
"""Create the fastapi app and bootstrap all dependencies."""
|
|
20
20
|
settings = settings or settings_provider()
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
# FastAPI adds its documentation routes ahead of the catch-all route; without an
|
|
23
|
+
# OpenAPI URL it adds none of them.
|
|
24
|
+
app = FastAPI(
|
|
25
|
+
lifespan=lifespan_provider(settings),
|
|
26
|
+
openapi_url="/openapi.json" if settings.openapi_docs_enabled else None,
|
|
27
|
+
)
|
|
23
28
|
|
|
24
29
|
strategy_provider(app, settings)
|
|
25
30
|
middleware_provider(app, settings)
|
|
@@ -62,6 +62,30 @@ def test_filefixtures_without_templates_dir_names_the_right_strategy():
|
|
|
62
62
|
Settings(strategy="filefixtures", templates_dir=None)
|
|
63
63
|
|
|
64
64
|
|
|
65
|
+
def test_openapi_docs_enabled_defaults_to_off(make_settings, templates_dir):
|
|
66
|
+
assert make_settings(templates_dir=templates_dir).openapi_docs_enabled is False
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_openapi_docs_enabled_env_var(monkeypatch, templates_dir):
|
|
70
|
+
"""``MOCKSTACK__OPENAPI_DOCS_ENABLED`` turns FastAPI's documentation routes on."""
|
|
71
|
+
monkeypatch.setenv("MOCKSTACK__OPENAPI_DOCS_ENABLED", "true")
|
|
72
|
+
|
|
73
|
+
assert Settings(templates_dir=templates_dir).openapi_docs_enabled is True
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def test_openapi_docs_enabled_cli_flag(templates_dir):
|
|
77
|
+
"""``--openapi-docs-enabled`` turns the documentation routes on and its ``--no-`` form off."""
|
|
78
|
+
enabled = CliSettings(
|
|
79
|
+
_cli_parse_args=["--templates-dir", templates_dir, "--openapi-docs-enabled"] # type: ignore[call-arg]
|
|
80
|
+
)
|
|
81
|
+
assert enabled.openapi_docs_enabled is True
|
|
82
|
+
|
|
83
|
+
disabled = CliSettings(
|
|
84
|
+
_cli_parse_args=["--templates-dir", templates_dir, "--no-openapi-docs-enabled"] # type: ignore[call-arg]
|
|
85
|
+
)
|
|
86
|
+
assert disabled.openapi_docs_enabled is False
|
|
87
|
+
|
|
88
|
+
|
|
65
89
|
def test_record_mode_defaults_to_off(make_settings, templates_dir):
|
|
66
90
|
settings = make_settings(templates_dir=templates_dir)
|
|
67
91
|
assert settings.proxyrules_record_mode == ProxyRulesRecordMode.OFF
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Tests for the application factory."""
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
from mockstack.main import create_app
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
OPENAPI_DOCS_PATHS = ["/openapi.json", "/docs", "/docs/oauth2-redirect", "/redoc"]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _route_paths(app):
|
|
13
|
+
return {route.path for route in app.routes}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@pytest.mark.asyncio
|
|
17
|
+
async def test_create_app_routes_root_path_to_strategy(make_settings, write_template, tmp_path):
|
|
18
|
+
"""``GET /`` reaches the strategy through the catch-all route: the app registers no
|
|
19
|
+
route of its own at the root path."""
|
|
20
|
+
write_template("index.j2", '{"message": "root fixture"}')
|
|
21
|
+
app = create_app(make_settings(strategy="filefixtures", templates_dir=tmp_path))
|
|
22
|
+
|
|
23
|
+
async with httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url="http://testserver") as client:
|
|
24
|
+
response = await client.get("/")
|
|
25
|
+
|
|
26
|
+
assert response.status_code == 200
|
|
27
|
+
assert response.json() == {"message": "root fixture"}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@pytest.mark.asyncio
|
|
31
|
+
@pytest.mark.parametrize("path", OPENAPI_DOCS_PATHS)
|
|
32
|
+
async def test_create_app_passes_openapi_docs_paths_to_strategy_by_default(make_settings, tmp_path, path):
|
|
33
|
+
"""FastAPI's documentation routes are off by default, so their paths reach the strategy
|
|
34
|
+
like any other: a filefixtures app with no templates answers them with its 404."""
|
|
35
|
+
app = create_app(make_settings(strategy="filefixtures", templates_dir=tmp_path))
|
|
36
|
+
|
|
37
|
+
assert not _route_paths(app) & set(OPENAPI_DOCS_PATHS)
|
|
38
|
+
async with httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url="http://testserver") as client:
|
|
39
|
+
response = await client.get(path)
|
|
40
|
+
|
|
41
|
+
assert response.status_code == 404
|
|
42
|
+
assert response.json()["message"] == "mockstack: resource not found"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@pytest.mark.asyncio
|
|
46
|
+
async def test_create_app_serves_openapi_docs_when_enabled(make_settings, tmp_path):
|
|
47
|
+
"""With ``openapi_docs_enabled`` FastAPI serves its documentation routes, ahead of the
|
|
48
|
+
catch-all route."""
|
|
49
|
+
app = create_app(make_settings(strategy="filefixtures", templates_dir=tmp_path, openapi_docs_enabled=True))
|
|
50
|
+
|
|
51
|
+
assert set(OPENAPI_DOCS_PATHS) <= _route_paths(app)
|
|
52
|
+
async with httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url="http://testserver") as client:
|
|
53
|
+
docs = await client.get("/docs")
|
|
54
|
+
# FastAPI gives every method of one route the same operation ID, and says so.
|
|
55
|
+
with pytest.warns(UserWarning, match="Duplicate Operation ID"):
|
|
56
|
+
schema = await client.get("/openapi.json")
|
|
57
|
+
|
|
58
|
+
assert docs.status_code == 200
|
|
59
|
+
assert docs.headers["content-type"].startswith("text/html")
|
|
60
|
+
assert schema.status_code == 200
|
|
61
|
+
assert "/{full_path}" in schema.json()["paths"]
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
"""Tests for the application factory."""
|
|
2
|
-
|
|
3
|
-
import httpx
|
|
4
|
-
import pytest
|
|
5
|
-
|
|
6
|
-
from mockstack.main import create_app
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@pytest.mark.asyncio
|
|
10
|
-
async def test_create_app_routes_root_path_to_strategy(make_settings, write_template, tmp_path):
|
|
11
|
-
"""``GET /`` reaches the strategy through the catch-all route: the app registers no
|
|
12
|
-
route of its own at the root path."""
|
|
13
|
-
write_template("index.j2", '{"message": "root fixture"}')
|
|
14
|
-
app = create_app(make_settings(strategy="filefixtures", templates_dir=tmp_path))
|
|
15
|
-
|
|
16
|
-
async with httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url="http://testserver") as client:
|
|
17
|
-
response = await client.get("/")
|
|
18
|
-
|
|
19
|
-
assert response.status_code == 200
|
|
20
|
-
assert response.json() == {"message": "root fixture"}
|
|
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
|
{mockstack-0.14.1 → mockstack-0.14.2}/examples/llm/templates/ollama-openai-v1-chat-completions.j2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/01-tagged-traffic/rules.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/02-scenario-directories/rules.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/04-json-literals/rules.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/05-query-parameters/rules.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/06-asserting-in-tests/rules.yml
RENAMED
|
File without changes
|
|
File without changes
|
{mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/07-redirect-mode/rules.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/08-status-and-headers/rules.yml
RENAMED
|
File without changes
|
|
File without changes
|
{mockstack-0.14.1 → mockstack-0.14.2}/examples/proxyrules-cookbook/09-recording/scrubbers.py
RENAMED
|
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
|
{mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/fixtures/templates/example-template.j2
RENAMED
|
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
|
{mockstack-0.14.1 → mockstack-0.14.2}/mockstack/tests/strategies/test_filefixtures_example.py
RENAMED
|
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
|