From 75f067acf5d305fcc5b882e8a6425c6cdbf574b0 Mon Sep 17 00:00:00 2001 From: Edouard Vanbelle Date: Wed, 8 Jul 2026 00:33:16 +0200 Subject: [PATCH] test(contact+calendar): cover grants tests --- tests/api/calendar.hurl | 42 ++++++++++++++++++++++++++++++++++++----- tests/api/contacts.hurl | 37 +++++++++++++++++++++++++++++++----- 2 files changed, 69 insertions(+), 10 deletions(-) diff --git a/tests/api/calendar.hurl b/tests/api/calendar.hurl index cb505d19..d10c8344 100644 --- a/tests/api/calendar.hurl +++ b/tests/api/calendar.hurl @@ -41,6 +41,7 @@ Content-Type: application/json HTTP 200 [Captures] alice_token: jsonpath "$.access_token" +alice_user_id: jsonpath "$.user.id" # ───────────────────────────────────────────────────────────── @@ -109,7 +110,7 @@ Content-Type: application/json HTTP 200 [Captures] -bob_token: jsonpath "$.access_token" +bob_token: jsonpath "$.access_token" bob_user_id: jsonpath "$.user.id" @@ -154,7 +155,7 @@ Content-Type: application/xml HTTP * [Asserts] status >= 400 -status < 500 +status < 500 # ───────────────────────────────────────────────────────────── @@ -175,9 +176,9 @@ HTTP 201 [Captures] share_grant_id: jsonpath "$.grants[0].id" [Asserts] -jsonpath "$.grants[0].role" == "viewer" +jsonpath "$.grants[0].role" == "viewer" jsonpath "$.grants[0].resource.type" == "calendar" -jsonpath "$.grants[0].resource.id" == "{{calendar_id}}" +jsonpath "$.grants[0].resource.id" == "{{calendar_id}}" # ───────────────────────────────────────────────────────────── @@ -202,6 +203,37 @@ HTTP 207 body contains "{{calendar_id}}" +# ───────────────────────────────────────────────────────────── +# Step 8b – Unified list-on-resource: Alice queries +# `GET /api/grants?resource_type=calendar&resource_id=…`. The +# handler requires `Share` on the resource (Alice's Owner grant +# satisfies it) and returns the raw `role_grants` rows including +# the Owner self-grant. Confirms `ResourceTypeDto::Calendar` is +# admitted at the query-string boundary. +# ───────────────────────────────────────────────────────────── +GET {{base_url}}/api/grants?resource_type=calendar&resource_id={{calendar_id}} +Authorization: Bearer {{alice_token}} + +HTTP 200 +[Asserts] +jsonpath "$[*].subject.id" contains "{{bob_user_id}}" +jsonpath "$[*].subject.id" contains "{{alice_user_id}}" +jsonpath "$[?(@.subject.id == '{{bob_user_id}}')].role" == "viewer" +jsonpath "$[?(@.subject.id == '{{alice_user_id}}')].role" == "owner" +jsonpath "$[?(@.subject.id == '{{bob_user_id}}')].resource.type" == "calendar" + + +# ───────────────────────────────────────────────────────────── +# Step 8c – Viewer Bob is denied on the unified list endpoint — +# `Share` is required, Viewer's bundle excludes it → 404 +# anti-enum shape (same treatment as any other resource type). +# ───────────────────────────────────────────────────────────── +GET {{base_url}}/api/grants?resource_type=calendar&resource_id={{calendar_id}} +Authorization: Bearer {{bob_token}} + +HTTP 404 + + # ───────────────────────────────────────────────────────────── # Step 9 – Alice revokes the grant. `DELETE /api/grants/{id}` # maps to a single `role_grants` row delete. @@ -247,4 +279,4 @@ Authorization: Bearer {{alice_token}} HTTP * [Asserts] status >= 200 -status < 300 +status < 300 diff --git a/tests/api/contacts.hurl b/tests/api/contacts.hurl index 4a199da2..075a8e14 100644 --- a/tests/api/contacts.hurl +++ b/tests/api/contacts.hurl @@ -24,6 +24,7 @@ Content-Type: application/json HTTP 200 [Captures] token: jsonpath "$.access_token" +admin_user_id: jsonpath "$.user.id" [Asserts] jsonpath "$.access_token" isString jsonpath "$.token_type" == "Bearer" @@ -342,7 +343,7 @@ Content-Type: application/json HTTP 200 [Captures] -bob_token: jsonpath "$.access_token" +bob_token: jsonpath "$.access_token" bob_user_id: jsonpath "$.user.id" @@ -396,9 +397,9 @@ HTTP 201 [Captures] share_grant_id: jsonpath "$.grants[0].id" [Asserts] -jsonpath "$.grants[0].role" == "viewer" -jsonpath "$.grants[0].resource.type" == "address_book" -jsonpath "$.grants[0].resource.id" == "{{share_book_id}}" +jsonpath "$.grants[0].role" == "viewer" +jsonpath "$.grants[0].resource.type" == "address_book" +jsonpath "$.grants[0].resource.id" == "{{share_book_id}}" # Step 20 — Bob's listing now includes the book, marked readonly @@ -425,6 +426,32 @@ Content-Type: application/json HTTP 404 +# Step 21b — Unified list-on-resource: Alice queries +# `GET /api/grants?resource_type=address_book&resource_id=…`. +# `Share` is required (Alice's Owner grant satisfies it) and the +# response includes the Owner self-grant that the per-domain +# UI hides. Confirms `ResourceTypeDto::AddressBook` is admitted +# at the query-string boundary. +GET {{base_url}}/api/grants?resource_type=address_book&resource_id={{share_book_id}} +Authorization: Bearer {{token}} + +HTTP 200 +[Asserts] +jsonpath "$[*].subject.id" contains "{{bob_user_id}}" +jsonpath "$[*].subject.id" contains "{{admin_user_id}}" +jsonpath "$[?(@.subject.id == '{{bob_user_id}}')].role" == "viewer" +jsonpath "$[?(@.subject.id == '{{admin_user_id}}')].role" == "owner" +jsonpath "$[?(@.subject.id == '{{bob_user_id}}')].resource.type" == "address_book" + + +# Step 21c — Viewer Bob is denied on the unified list endpoint — +# `Share` isn't in the Viewer bundle → 404 anti-enum shape. +GET {{base_url}}/api/grants?resource_type=address_book&resource_id={{share_book_id}} +Authorization: Bearer {{bob_token}} + +HTTP 404 + + # Step 22 — Alice revokes the grant. DELETE {{base_url}}/api/grants/{{share_grant_id}} Authorization: Bearer {{token}} @@ -590,4 +617,4 @@ Authorization: Bearer {{token}} HTTP * [Asserts] status >= 200 -status < 300 +status < 300