fixtureqa 0.3.4__tar.gz → 0.3.5__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.
- {fixtureqa-0.3.4/fixtureqa.egg-info → fixtureqa-0.3.5}/PKG-INFO +1 -1
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/api/routers/sessions.py +18 -12
- {fixtureqa-0.3.4 → fixtureqa-0.3.5/fixtureqa.egg-info}/PKG-INFO +1 -1
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/pyproject.toml +1 -1
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_sessions.py +17 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/LICENSE +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/README.md +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/__init__.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/__main__.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/api/__init__.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/api/app.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/api/connection_manager.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/api/deps.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/api/routers/__init__.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/api/routers/admin.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/api/routers/auth.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/api/routers/branding.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/api/routers/custom_tags.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/api/routers/fix_spec.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/api/routers/messages.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/api/routers/perf.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/api/routers/scenarios.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/api/routers/setup.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/api/routers/spec_overlay.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/api/routers/templates.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/api/routers/ws.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/api/schemas.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/config/__init__.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/__init__.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/atomic_io.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/auth.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/config_store.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/custom_tag_store.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/db_migrations.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/events.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/fix_application.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/fix_builder.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/fix_parser.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/fix_spec_parser.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/fix_tags.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/housekeeping.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/inbound.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/message_log.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/message_store.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/models.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/perf_engine.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/perf_models.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/perf_payload.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/perf_stats.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/perf_store.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/perf_writer.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/scenario_runner.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/scenario_store.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/session.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/session_manager.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/spec_overlay_store.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/template_store.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/user_store.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/core/venue_responses.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/fix_specs/FIX42.xml +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/fix_specs/FIX44.xml +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/server.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/static/assets/ag-grid-_QKprVdm.js +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/static/assets/index-BYDmHEr1.js +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/static/assets/index-D9vW5wFo.css +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/static/assets/react-vendor-2eF0YfZT.js +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/static/favicon.svg +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/static/index.html +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixture/ui/__init__.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixtureqa.egg-info/SOURCES.txt +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixtureqa.egg-info/dependency_links.txt +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixtureqa.egg-info/entry_points.txt +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixtureqa.egg-info/requires.txt +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/fixtureqa.egg-info/top_level.txt +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/setup.cfg +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_atomic_io.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_auth.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_connection_manager.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_db_migrations.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_fix_builder.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_health.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_inbound.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_inbound_validation.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_message_store.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_perf_api.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_perf_engine.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_perf_models.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_perf_payload.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_perf_rehydrate.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_scenarios.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_session_lifecycle.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_session_manager_concurrency.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_templates.py +0 -0
- {fixtureqa-0.3.4 → fixtureqa-0.3.5}/tests/test_ws.py +0 -0
|
@@ -71,15 +71,20 @@ def _check_ownership(sm: SessionManager, session_id: str, user: User) -> Session
|
|
|
71
71
|
return cfg
|
|
72
72
|
|
|
73
73
|
|
|
74
|
+
def _owner_store(us: UserStore, user: User) -> Optional[UserStore]:
|
|
75
|
+
"""Only admin responses carry owner_username (the UI owner badge / Mine filter)."""
|
|
76
|
+
return us if user.is_admin else None
|
|
77
|
+
|
|
78
|
+
|
|
74
79
|
@router.get("/", response_model=list[SessionResponse])
|
|
75
80
|
def list_sessions(sm: SM, us: US, user: CurrentUser):
|
|
76
81
|
configs = sm.list_sessions_for_user(user.uid, is_admin=user.is_admin)
|
|
77
|
-
user_store = us
|
|
82
|
+
user_store = _owner_store(us, user)
|
|
78
83
|
return [_session_response(sm, cfg.session_id, user_store) for cfg in configs]
|
|
79
84
|
|
|
80
85
|
|
|
81
86
|
@router.post("/", response_model=SessionResponse, status_code=201)
|
|
82
|
-
async def create_session(body: SessionConfigRequest, sm: SM, user: CurrentUser):
|
|
87
|
+
async def create_session(body: SessionConfigRequest, sm: SM, us: US, user: CurrentUser):
|
|
83
88
|
try:
|
|
84
89
|
ct = ConnectionType(body.connection_type)
|
|
85
90
|
except ValueError:
|
|
@@ -127,11 +132,11 @@ async def create_session(body: SessionConfigRequest, sm: SM, user: CurrentUser):
|
|
|
127
132
|
except Exception as e:
|
|
128
133
|
raise HTTPException(status_code=500, detail=f"Session added but failed to start: {e}")
|
|
129
134
|
|
|
130
|
-
return _session_response(sm, session_id)
|
|
135
|
+
return _session_response(sm, session_id, _owner_store(us, user))
|
|
131
136
|
|
|
132
137
|
|
|
133
138
|
@router.post("/import", response_model=list[SessionResponse], status_code=201)
|
|
134
|
-
def import_sessions(body: list[SessionConfigRequest], sm: SM, user: CurrentUser):
|
|
139
|
+
def import_sessions(body: list[SessionConfigRequest], sm: SM, us: US, user: CurrentUser):
|
|
135
140
|
"""
|
|
136
141
|
Bulk-create sessions from an exported config file.
|
|
137
142
|
Each entry is processed independently; invalid entries are skipped.
|
|
@@ -169,20 +174,20 @@ def import_sessions(body: list[SessionConfigRequest], sm: SM, user: CurrentUser)
|
|
|
169
174
|
owner_uid=user.uid,
|
|
170
175
|
)
|
|
171
176
|
session_id = sm.add_session(cfg)
|
|
172
|
-
created.append(_session_response(sm, session_id))
|
|
177
|
+
created.append(_session_response(sm, session_id, _owner_store(us, user)))
|
|
173
178
|
except Exception:
|
|
174
179
|
pass # skip invalid / conflicting entries
|
|
175
180
|
return created
|
|
176
181
|
|
|
177
182
|
|
|
178
183
|
@router.get("/{session_id}", response_model=SessionResponse)
|
|
179
|
-
def get_session(session_id: str, sm: SM, user: CurrentUser):
|
|
184
|
+
def get_session(session_id: str, sm: SM, us: US, user: CurrentUser):
|
|
180
185
|
_check_ownership(sm, session_id, user)
|
|
181
|
-
return _session_response(sm, session_id)
|
|
186
|
+
return _session_response(sm, session_id, _owner_store(us, user))
|
|
182
187
|
|
|
183
188
|
|
|
184
189
|
@router.patch("/{session_id}", response_model=SessionResponse)
|
|
185
|
-
def update_session(session_id: str, body: UpdateSessionRequest, sm: SM, user: CurrentUser):
|
|
190
|
+
def update_session(session_id: str, body: UpdateSessionRequest, sm: SM, us: US, user: CurrentUser):
|
|
186
191
|
_check_ownership(sm, session_id, user)
|
|
187
192
|
try:
|
|
188
193
|
sm.update_session(session_id, body)
|
|
@@ -190,7 +195,7 @@ def update_session(session_id: str, body: UpdateSessionRequest, sm: SM, user: Cu
|
|
|
190
195
|
raise HTTPException(status_code=409, detail=str(e))
|
|
191
196
|
except (ValueError, KeyError) as e:
|
|
192
197
|
raise HTTPException(status_code=422, detail=str(e))
|
|
193
|
-
return _session_response(sm, session_id)
|
|
198
|
+
return _session_response(sm, session_id, _owner_store(us, user))
|
|
194
199
|
|
|
195
200
|
|
|
196
201
|
@router.delete("/{session_id}", status_code=204)
|
|
@@ -203,25 +208,26 @@ async def remove_session(session_id: str, sm: SM, user: CurrentUser):
|
|
|
203
208
|
|
|
204
209
|
|
|
205
210
|
@router.post("/{session_id}/start", response_model=SessionResponse)
|
|
206
|
-
async def start_session(session_id: str, sm: SM, user: CurrentUser):
|
|
211
|
+
async def start_session(session_id: str, sm: SM, us: US, user: CurrentUser):
|
|
207
212
|
_check_ownership(sm, session_id, user)
|
|
208
213
|
try:
|
|
209
214
|
await sm.start_session(session_id)
|
|
210
215
|
except RuntimeError as e:
|
|
211
216
|
raise HTTPException(status_code=409, detail=str(e))
|
|
212
|
-
return _session_response(sm, session_id)
|
|
217
|
+
return _session_response(sm, session_id, _owner_store(us, user))
|
|
213
218
|
|
|
214
219
|
|
|
215
220
|
@router.post("/{session_id}/stop", response_model=SessionResponse)
|
|
216
221
|
async def stop_session(
|
|
217
222
|
session_id: str,
|
|
218
223
|
sm: SM,
|
|
224
|
+
us: US,
|
|
219
225
|
user: CurrentUser,
|
|
220
226
|
force: bool = Query(default=False),
|
|
221
227
|
):
|
|
222
228
|
_check_ownership(sm, session_id, user)
|
|
223
229
|
await sm.stop_session(session_id, force=force)
|
|
224
|
-
return _session_response(sm, session_id)
|
|
230
|
+
return _session_response(sm, session_id, _owner_store(us, user))
|
|
225
231
|
|
|
226
232
|
|
|
227
233
|
@router.post("/{session_id}/send")
|
|
@@ -53,6 +53,23 @@ def test_create_session(authed):
|
|
|
53
53
|
assert "session_id" in body
|
|
54
54
|
|
|
55
55
|
|
|
56
|
+
def test_mutating_responses_carry_owner_username_for_admin(authed):
|
|
57
|
+
# The admin "Mine" filter matches on owner_username client-side; if any
|
|
58
|
+
# session response omits it, the upserted session vanishes from the list
|
|
59
|
+
# until a full refetch. Every endpoint must enrich it like GET /sessions/.
|
|
60
|
+
client, _ = authed
|
|
61
|
+
created = client.post("/api/sessions/", json=_ini(9876)).json()
|
|
62
|
+
assert created["owner_username"] == "admin"
|
|
63
|
+
sid = created["session_id"]
|
|
64
|
+
assert client.get(f"/api/sessions/{sid}").json()["owner_username"] == "admin"
|
|
65
|
+
patched = client.patch(f"/api/sessions/{sid}", json={"display_name": "renamed"}).json()
|
|
66
|
+
assert patched["owner_username"] == "admin"
|
|
67
|
+
stopped = client.post(f"/api/sessions/{sid}/stop").json()
|
|
68
|
+
assert stopped["owner_username"] == "admin"
|
|
69
|
+
imported = client.post("/api/sessions/import", json=[_ini(9877, "A", "B")]).json()
|
|
70
|
+
assert imported[0]["owner_username"] == "admin"
|
|
71
|
+
|
|
72
|
+
|
|
56
73
|
def test_list_sessions(authed):
|
|
57
74
|
client, _ = authed
|
|
58
75
|
client.post("/api/sessions/", json=_ini(9001, "A", "B"))
|
|
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
|
|
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
|