Per orchestrator's SSO-dep plan + the refactor in 41ede13, DEFERRED.md entry #5 (lasuite-docs
OIDC parity ports + create-a-doc) closes by execution.
- tests/lasuite-docs/functional/test_oidc_login.py: parity port of recipe-maintainer
oidc_login.py. Anonymous GET /api/v1.0/users/me/ → 302 to keycloak realm OR 401/403;
password-grant token → 200 with user.email matching the provisioned test user.
- tests/lasuite-docs/functional/test_create_doc.py: plan §4.3 prescribed create-an-object +
read-it-back. POST /api/v1.0/documents/ with OIDC Bearer → captured id; GET
/api/v1.0/documents/<id>/ → asserts id+title round-trip.
Both marked \@pytest.mark.requires_deps; skipped with 'deps-not-ready' if setup_custom_tests
fails (failure isolation per plan-sso-dep-testing.md §4).
Cold-verifiable: ssh cc-ci 'RECIPE=lasuite-docs STAGES=install,custom cc-ci-run runner/run_recipe_ci.py'
install: 2 PASS; custom: 5 PASS incl. test_oidc_login_via_keycloak +
test_create_doc_and_read_back; deploy-count=2 (recipe + keycloak dep).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
75 lines
3.0 KiB
Python
75 lines
3.0 KiB
Python
"""lasuite-docs — Phase-2 P3 §4.3 prescribed create-a-doc + read-back test.
|
|
|
|
Plan §4.3 explicitly names this test for lasuite-docs: "create a doc, edit via the API, confirm
|
|
persistence". This is the canonical create-an-object + read-it-back for lasuite-docs.
|
|
|
|
Flow (uses an OIDC token from the dep keycloak):
|
|
1. Obtain a JWT via OIDC password grant against the dep keycloak (the test user is provisioned
|
|
by the orchestrator's setup_custom_tests step).
|
|
2. POST `/api/v1.0/documents/` with `Authorization: Bearer <jwt>` to create a new doc with a
|
|
unique title; capture the returned `id`.
|
|
3. GET `/api/v1.0/documents/<id>/` with the same Bearer token; assert the returned title and
|
|
id match.
|
|
|
|
Non-vacuous: a misconfigured OIDC, broken backend, or missing endpoint fails at the layer it's
|
|
broken. The marker-in-the-title + id round-trip proves the doc actually persisted in lasuite-
|
|
docs's database after going through the recipe's nginx → backend → postgres path.
|
|
|
|
Marked @pytest.mark.requires_deps — skips with `deps-not-ready` if setup_custom_tests failed.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import sys
|
|
import uuid
|
|
|
|
import pytest
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "..", "runner"))
|
|
from harness import http as harness_http, sso # noqa: E402
|
|
|
|
|
|
@pytest.mark.requires_deps
|
|
def test_create_doc_and_read_back(live_app, deps_creds):
|
|
"""Create a doc via the authenticated API; fetch it back; assert round-trip."""
|
|
kc = deps_creds["keycloak"]
|
|
|
|
# Obtain a JWT via OIDC password grant
|
|
access_token = sso.oidc_password_grant({
|
|
"client_id": kc["client_id"],
|
|
"client_secret": kc["client_secret"],
|
|
"user": kc["user"],
|
|
"password": kc["password"],
|
|
"token_url": kc["token_url"],
|
|
})
|
|
auth = {"Authorization": f"Bearer {access_token}"}
|
|
|
|
# Create a doc with a unique title
|
|
title = f"ccci-doc-{uuid.uuid4().hex[:8]}"
|
|
s, body = harness_http.http_post(
|
|
f"https://{live_app}/api/v1.0/documents/",
|
|
data={"title": title},
|
|
headers=auth,
|
|
)
|
|
assert s in (200, 201), f"POST /api/v1.0/documents/ HTTP {s}: {body!r}"
|
|
assert isinstance(body, dict), f"unexpected response shape: {body!r}"
|
|
doc_id = body.get("id")
|
|
assert doc_id, f"created doc has no id: {body!r}"
|
|
assert body.get("title") == title, (
|
|
f"created doc title mismatch: created={title!r}, response={body.get('title')!r}"
|
|
)
|
|
|
|
# Fetch it back via the dedicated GET endpoint
|
|
s, fetched = harness_http.http_get(
|
|
f"https://{live_app}/api/v1.0/documents/{doc_id}/", headers=auth
|
|
)
|
|
assert s == 200, f"GET /api/v1.0/documents/{doc_id}/ HTTP {s}: {fetched!r}"
|
|
assert isinstance(fetched, dict), f"unexpected GET response: {fetched!r}"
|
|
assert fetched.get("id") in (doc_id, str(doc_id)), (
|
|
f"fetched id mismatch: created={doc_id!r}, fetched={fetched.get('id')!r}"
|
|
)
|
|
assert fetched.get("title") == title, (
|
|
f"fetched title mismatch: created={title!r}, fetched={fetched.get('title')!r}"
|
|
)
|