agnes-the-ai-analyst/tests/test_journey_memory.py
ZdenekSrotyr 7967279181 test: add E2E journey tests (J1-J8) covering full user flows
40 tests across 8 files covering bootstrap/auth, sync+query, hybrid
queries, RBAC+access-requests, Jira webhooks, corporate memory,
analyst uploads, and multi-source orchestration. Adds mock_extract_factory
and admin_user fixtures to conftest, and journey marker to pytest.ini.
2026-04-12 11:13:51 +02:00

138 lines
4.5 KiB
Python

"""J6 — Corporate memory lifecycle journey tests.
Full cycle: upload local-md → create knowledge item → list → vote → admin approve.
"""
import pytest
def _auth(token: str) -> dict:
return {"Authorization": f"Bearer {token}"}
@pytest.mark.journey
class TestMemoryJourney:
def test_create_list_vote_approve(self, seeded_app):
"""Full corporate memory lifecycle from creation to approval."""
c = seeded_app["client"]
admin_h = _auth(seeded_app["admin_token"])
analyst_h = _auth(seeded_app["analyst_token"])
# Step 1: Create knowledge item as analyst
resp = c.post(
"/api/memory",
json={
"title": "DuckDB query best practices",
"content": "Always use parameterised queries to avoid SQL injection.",
"category": "engineering",
"tags": ["duckdb", "security"],
},
headers=analyst_h,
)
assert resp.status_code == 201
item_id = resp.json()["id"]
assert resp.json()["status"] == "pending"
# Step 2: List items — should appear
resp = c.get("/api/memory", headers=analyst_h)
assert resp.status_code == 200
ids = [i["id"] for i in resp.json()["items"]]
assert item_id in ids
# Step 3: Analyst upvotes the item
resp = c.post(
f"/api/memory/{item_id}/vote",
json={"vote": 1},
headers=analyst_h,
)
assert resp.status_code == 200
assert resp.json()["upvotes"] >= 1
# Step 4: Admin approves
resp = c.post(
f"/api/memory/admin/approve?item_id={item_id}",
headers=admin_h,
)
assert resp.status_code == 200
assert resp.json()["status"] == "approved"
# Step 5: Verify status in listing
resp = c.get(f"/api/memory?status_filter=approved", headers=analyst_h)
assert resp.status_code == 200
approved_ids = [i["id"] for i in resp.json()["items"]]
assert item_id in approved_ids
def test_upload_local_md_creates_file(self, seeded_app):
"""Uploading CLAUDE.local.md content is stored correctly."""
c = seeded_app["client"]
analyst_h = _auth(seeded_app["analyst_token"])
content = "# Local knowledge\n\nThis is my personal insight."
resp = c.post(
"/api/upload/local-md",
json={"content": content},
headers=analyst_h,
)
assert resp.status_code == 200
body = resp.json()
assert body["status"] == "ok"
assert body["size"] == len(content)
def test_admin_can_reject_item(self, seeded_app):
"""Admin can reject a pending knowledge item."""
c = seeded_app["client"]
admin_h = _auth(seeded_app["admin_token"])
resp = c.post(
"/api/memory",
json={"title": "Bad info", "content": "Wrong thing", "category": "misc"},
headers=admin_h,
)
assert resp.status_code == 201
item_id = resp.json()["id"]
resp = c.post(
f"/api/memory/admin/reject?item_id={item_id}",
json={"reason": "Inaccurate"},
headers=admin_h,
)
assert resp.status_code == 200
assert resp.json()["status"] == "rejected"
def test_vote_invalid_value_rejected(self, seeded_app):
"""Vote values other than 1 and -1 are rejected."""
c = seeded_app["client"]
analyst_h = _auth(seeded_app["analyst_token"])
resp = c.post(
"/api/memory",
json={"title": "Test item", "content": "Some content", "category": "test"},
headers=analyst_h,
)
item_id = resp.json()["id"]
resp = c.post(
f"/api/memory/{item_id}/vote",
json={"vote": 5},
headers=analyst_h,
)
assert resp.status_code == 400
def test_memory_stats_endpoint(self, seeded_app):
"""Memory stats reflect created items."""
c = seeded_app["client"]
admin_h = _auth(seeded_app["admin_token"])
# Create an item
c.post(
"/api/memory",
json={"title": "Stats test", "content": "Content", "category": "engineering"},
headers=admin_h,
)
resp = c.get("/api/memory/stats", headers=admin_h)
assert resp.status_code == 200
body = resp.json()
assert body["total"] >= 1
assert "by_status" in body
assert "pending" in body["by_status"]