mockstack 0.9.0__tar.gz → 0.9.1__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.9.0 → mockstack-0.9.1}/PKG-INFO +1 -1
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/intent.py +7 -1
- mockstack-0.9.1/mockstack/tests/test_intent.py +162 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack.egg-info/PKG-INFO +1 -1
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack.egg-info/SOURCES.txt +1 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/.dockerignore +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/.env.example +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/.github/workflows/ci.yml +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/.github/workflows/publish-docs.yml +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/.github/workflows/publish-to-dockerhub.yml +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/.github/workflows/publish-to-pypi.yml +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/.gitignore +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/.pre-commit-config.yaml +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/CODE_OF_CONDUCT.md +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/Dockerfile +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/LICENSE +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/README.md +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/SECURITY.md +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/docker-entrypoint.sh +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/docs/assets/favicon.ico +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/docs/assets/logo.png +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/docs/assets/mockstack.png +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/docs/configuration.md +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/docs/ollama.md +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/docs/strategies/base.md +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/docs/strategies/filefixtures.md +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/docs/strategies/proxyrules.md +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/examples/filefixtures-with-templates/.env.example +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/examples/filefixtures-with-templates/README.md +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/examples/filefixtures-with-templates/templates/servicename-api-v1-items.j2 +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/examples/filefixtures-with-templates/templates/servicename2-api-v2-user.533ec889-7c68-45c8-b21e-4a7e455d1234.j2 +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/examples/llm/README.md +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/examples/llm/mockstack-langchain-example.ipynb +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/examples/llm/templates/ollama-openai-v1-chat-completions.j2 +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/examples/llm/templates/openai-v1-chat-completions.j2 +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/examples/llm/templates/openai-v1-deployments-gpt-4o-chat-completions.j2 +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/examples/proxyrules-with-rules-file/.env.example +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/examples/proxyrules-with-rules-file/README.md +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/examples/proxyrules-with-rules-file/rules.yml +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mkdocs.yml +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/__init__.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/config.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/constants.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/display.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/exceptions.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/identifiers.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/lifespan.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/llm/__init__.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/llm/ollama.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/main.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/middleware.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/routers/__init__.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/routers/catchall.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/routers/homepage.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/strategies/__init__.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/strategies/base.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/strategies/create_mixin.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/strategies/factory.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/strategies/filefixtures.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/strategies/proxyrules.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/telemetry.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/templating.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/tests/__init__.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/tests/conftest.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/tests/fixtures/proxyrules.yml +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/tests/fixtures/templates/__init__.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/tests/fixtures/templates/example-template.j2 +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/tests/llm/__init__.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/tests/llm/test_ollama.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/tests/routers/__init__.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/tests/routers/test_catchall.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/tests/routers/test_homepage.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/tests/strategies/test_create_mixin.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/tests/strategies/test_filefixtures.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/tests/strategies/test_proxyrules.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/tests/test_display.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/tests/test_identifiers.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/tests/test_middleware.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/tests/test_telemetry.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack/tests/test_templating.py +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack.egg-info/dependency_links.txt +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack.egg-info/entry_points.txt +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack.egg-info/requires.txt +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/mockstack.egg-info/top_level.txt +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/pyproject.toml +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/setup.cfg +0 -0
- {mockstack-0.9.0 → mockstack-0.9.1}/uv.lock +0 -0
|
@@ -62,7 +62,13 @@ def looks_like_a_create(request: Request) -> bool:
|
|
|
62
62
|
"""
|
|
63
63
|
return any(
|
|
64
64
|
(
|
|
65
|
-
request.method == "POST"
|
|
65
|
+
request.method == "POST"
|
|
66
|
+
and not any(
|
|
67
|
+
(
|
|
68
|
+
looks_like_a_search(request),
|
|
69
|
+
looks_like_a_command(request),
|
|
70
|
+
)
|
|
71
|
+
),
|
|
66
72
|
request.url.path.endswith("/create"),
|
|
67
73
|
),
|
|
68
74
|
)
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""Unit tests for the intent module."""
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from fastapi import Request
|
|
5
|
+
from starlette.datastructures import Headers
|
|
6
|
+
|
|
7
|
+
from mockstack.intent import (
|
|
8
|
+
wants_json,
|
|
9
|
+
looks_like_a_search,
|
|
10
|
+
looks_like_a_command,
|
|
11
|
+
looks_like_a_create,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.fixture
|
|
16
|
+
def mock_request():
|
|
17
|
+
"""Create a mock FastAPI request object."""
|
|
18
|
+
|
|
19
|
+
def _create_request(
|
|
20
|
+
method="GET",
|
|
21
|
+
path="/",
|
|
22
|
+
headers=None,
|
|
23
|
+
):
|
|
24
|
+
return Request(
|
|
25
|
+
{
|
|
26
|
+
"type": "http",
|
|
27
|
+
"method": method,
|
|
28
|
+
"path": path,
|
|
29
|
+
"headers": Headers(headers or {}).raw,
|
|
30
|
+
}
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
return _create_request
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@pytest.fixture
|
|
37
|
+
def json_content_types():
|
|
38
|
+
"""Return a list of valid JSON content types."""
|
|
39
|
+
return [
|
|
40
|
+
"application/json",
|
|
41
|
+
"text/json",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@pytest.fixture
|
|
46
|
+
def non_json_content_types():
|
|
47
|
+
"""Return a list of non-JSON content types."""
|
|
48
|
+
return [
|
|
49
|
+
"text/plain",
|
|
50
|
+
"application/xml",
|
|
51
|
+
"text/html",
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@pytest.fixture
|
|
56
|
+
def search_paths():
|
|
57
|
+
"""Return a list of paths that should be identified as search requests."""
|
|
58
|
+
return [
|
|
59
|
+
"/api/_search",
|
|
60
|
+
"/api/search",
|
|
61
|
+
"/api/_query",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@pytest.fixture
|
|
66
|
+
def command_paths():
|
|
67
|
+
"""Return a list of paths that should be identified as command requests."""
|
|
68
|
+
return [
|
|
69
|
+
"/api/_command",
|
|
70
|
+
"/api/command",
|
|
71
|
+
"/api/_request",
|
|
72
|
+
"/api/request",
|
|
73
|
+
"/api/_run",
|
|
74
|
+
"/api/run",
|
|
75
|
+
"/api/_execute",
|
|
76
|
+
"/api/execute",
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@pytest.fixture
|
|
81
|
+
def create_paths():
|
|
82
|
+
"""Return a list of paths that should be identified as create requests."""
|
|
83
|
+
return [
|
|
84
|
+
"/api/create",
|
|
85
|
+
"/api/data", # POST without search/command
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_wants_json_with_content_type(
|
|
90
|
+
mock_request, json_content_types, non_json_content_types
|
|
91
|
+
):
|
|
92
|
+
"""Test wants_json with different content types."""
|
|
93
|
+
# Test valid JSON content types
|
|
94
|
+
for content_type in json_content_types:
|
|
95
|
+
request = mock_request(headers={"Content-Type": content_type})
|
|
96
|
+
assert wants_json(request) is True
|
|
97
|
+
|
|
98
|
+
# Test non-JSON content types
|
|
99
|
+
for content_type in non_json_content_types:
|
|
100
|
+
request = mock_request(headers={"Content-Type": content_type})
|
|
101
|
+
assert wants_json(request) is False
|
|
102
|
+
|
|
103
|
+
# Test missing content type
|
|
104
|
+
request = mock_request()
|
|
105
|
+
assert wants_json(request) is False
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def test_wants_json_with_path(mock_request):
|
|
109
|
+
"""Test wants_json with .json path."""
|
|
110
|
+
# Test .json suffix
|
|
111
|
+
request = mock_request(path="/api/data.json")
|
|
112
|
+
assert wants_json(request) is True
|
|
113
|
+
|
|
114
|
+
# Test non-.json path
|
|
115
|
+
request = mock_request(path="/api/data")
|
|
116
|
+
assert wants_json(request) is False
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_looks_like_a_search(mock_request, search_paths):
|
|
120
|
+
"""Test looks_like_a_search with different paths."""
|
|
121
|
+
# Test search paths
|
|
122
|
+
for path in search_paths:
|
|
123
|
+
request = mock_request(path=path)
|
|
124
|
+
assert looks_like_a_search(request) is True
|
|
125
|
+
|
|
126
|
+
# Test non-search path
|
|
127
|
+
request = mock_request(path="/api/data")
|
|
128
|
+
assert looks_like_a_search(request) is False
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def test_looks_like_a_command(mock_request, command_paths):
|
|
132
|
+
"""Test looks_like_a_command with different paths."""
|
|
133
|
+
# Test command paths
|
|
134
|
+
for path in command_paths:
|
|
135
|
+
request = mock_request(path=path)
|
|
136
|
+
assert looks_like_a_command(request) is True
|
|
137
|
+
|
|
138
|
+
# Test non-command path
|
|
139
|
+
request = mock_request(path="/api/data")
|
|
140
|
+
assert looks_like_a_command(request) is False
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def test_looks_like_a_create(mock_request, create_paths, search_paths, command_paths):
|
|
144
|
+
"""Test looks_like_a_create with different scenarios."""
|
|
145
|
+
# Test create paths with POST method
|
|
146
|
+
for path in create_paths:
|
|
147
|
+
request = mock_request(method="POST", path=path)
|
|
148
|
+
assert looks_like_a_create(request) is True
|
|
149
|
+
|
|
150
|
+
# Test POST with search paths (should be False)
|
|
151
|
+
for path in search_paths:
|
|
152
|
+
request = mock_request(method="POST", path=path)
|
|
153
|
+
assert looks_like_a_create(request) is False
|
|
154
|
+
|
|
155
|
+
# Test POST with command paths (should be False)
|
|
156
|
+
for path in command_paths:
|
|
157
|
+
request = mock_request(method="POST", path=path)
|
|
158
|
+
assert looks_like_a_create(request) is False
|
|
159
|
+
|
|
160
|
+
# Test non-POST method
|
|
161
|
+
request = mock_request(method="GET", path="/api/data")
|
|
162
|
+
assert looks_like_a_create(request) is False
|
|
@@ -68,6 +68,7 @@ mockstack/tests/__init__.py
|
|
|
68
68
|
mockstack/tests/conftest.py
|
|
69
69
|
mockstack/tests/test_display.py
|
|
70
70
|
mockstack/tests/test_identifiers.py
|
|
71
|
+
mockstack/tests/test_intent.py
|
|
71
72
|
mockstack/tests/test_middleware.py
|
|
72
73
|
mockstack/tests/test_telemetry.py
|
|
73
74
|
mockstack/tests/test_templating.py
|
|
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.9.0 → mockstack-0.9.1}/examples/llm/templates/ollama-openai-v1-chat-completions.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
|
|
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
|