2026-05-11 19:26:52 +02:00
|
|
|
|
# =============================================================
|
|
|
|
|
|
# OxiCloud – Recent items API end-to-end scenario
|
|
|
|
|
|
# =============================================================
|
|
|
|
|
|
# Depends on files-folders.hurl having run first:
|
|
|
|
|
|
# - home folder exists with test1 and test2-renamed
|
|
|
|
|
|
# - test2-renamed contains hello-renamed.txt
|
|
|
|
|
|
#
|
|
|
|
|
|
# Run:
|
|
|
|
|
|
# hurl --variables-file tests/api/test.env --test tests/api/recent.hurl
|
|
|
|
|
|
# =============================================================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
# Step 1 – Login and capture the JWT token
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
POST {{base_url}}/api/auth/login
|
|
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
{
|
|
|
|
|
|
"username": "{{username}}",
|
|
|
|
|
|
"password": "{{password}}"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HTTP 200
|
|
|
|
|
|
[Captures]
|
|
|
|
|
|
token: jsonpath "$.access_token"
|
|
|
|
|
|
[Asserts]
|
|
|
|
|
|
jsonpath "$.access_token" isString
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
# Step 2 – Discover the file ID of hello-renamed.txt
|
|
|
|
|
|
# Folders are ORDER BY name: test1 ($[0]), test2-renamed ($[1])
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
GET {{base_url}}/api/folders
|
|
|
|
|
|
Authorization: Bearer {{token}}
|
|
|
|
|
|
|
|
|
|
|
|
HTTP 200
|
|
|
|
|
|
[Captures]
|
|
|
|
|
|
home_folder_id: jsonpath "$[0].id"
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-31 20:21:33 +02:00
|
|
|
|
GET {{base_url}}/api/folders/{{home_folder_id}}/resources?resource_types=folder
|
2026-05-11 19:26:52 +02:00
|
|
|
|
Authorization: Bearer {{token}}
|
|
|
|
|
|
|
|
|
|
|
|
HTTP 200
|
|
|
|
|
|
[Captures]
|
2026-05-31 20:21:33 +02:00
|
|
|
|
test2_id: jsonpath "$.items[1].resource.id"
|
2026-05-11 19:26:52 +02:00
|
|
|
|
[Asserts]
|
2026-05-31 20:21:33 +02:00
|
|
|
|
jsonpath "$.items[1].resource.name" == "test2-renamed"
|
2026-05-11 19:26:52 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GET {{base_url}}/api/files?folder_id={{test2_id}}
|
|
|
|
|
|
Authorization: Bearer {{token}}
|
|
|
|
|
|
|
|
|
|
|
|
HTTP 200
|
|
|
|
|
|
[Captures]
|
|
|
|
|
|
file_id: jsonpath "$[0].id"
|
|
|
|
|
|
[Asserts]
|
|
|
|
|
|
jsonpath "$[0].name" == "hello-renamed.txt"
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-06-26 01:01:44 +02:00
|
|
|
|
# Defensive clear before the explicit-POST assertions: earlier
|
|
|
|
|
|
# scenarios in the runner (files-folders.hurl) auto-record every
|
|
|
|
|
|
# file they upload / GET through the service-layer
|
|
|
|
|
|
# `ResourceAccessHook`, so Recent already has rows by the time we
|
|
|
|
|
|
# arrive here. Clearing first lets step 4 assert `count == 1`
|
|
|
|
|
|
# against a known-empty baseline.
|
|
|
|
|
|
DELETE {{base_url}}/api/recent/clear
|
|
|
|
|
|
Authorization: Bearer {{token}}
|
|
|
|
|
|
|
|
|
|
|
|
HTTP 200
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-11 19:26:52 +02:00
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
# Step 3 – Record access to hello-renamed.txt
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
POST {{base_url}}/api/recent/file/{{file_id}}
|
|
|
|
|
|
Authorization: Bearer {{token}}
|
|
|
|
|
|
|
|
|
|
|
|
HTTP 200
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
# Step 4 – Recent list contains hello-renamed.txt
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
2026-05-29 12:55:26 +02:00
|
|
|
|
GET {{base_url}}/api/recent/resources
|
2026-05-11 19:26:52 +02:00
|
|
|
|
Authorization: Bearer {{token}}
|
|
|
|
|
|
|
|
|
|
|
|
HTTP 200
|
|
|
|
|
|
[Asserts]
|
2026-05-29 12:55:26 +02:00
|
|
|
|
jsonpath "$.items" count == 1
|
|
|
|
|
|
jsonpath "$.items[0].resource_type" == "file"
|
|
|
|
|
|
jsonpath "$.items[0].resource.name" == "hello-renamed.txt"
|
2026-05-11 19:26:52 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
# Step 5 – Clear all recent items
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
DELETE {{base_url}}/api/recent/clear
|
|
|
|
|
|
Authorization: Bearer {{token}}
|
|
|
|
|
|
|
|
|
|
|
|
HTTP 200
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
# Step 6 – Recent list is empty after clear
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
2026-05-29 12:55:26 +02:00
|
|
|
|
GET {{base_url}}/api/recent/resources
|
2026-05-11 19:26:52 +02:00
|
|
|
|
Authorization: Bearer {{token}}
|
|
|
|
|
|
|
|
|
|
|
|
HTTP 200
|
|
|
|
|
|
[Asserts]
|
2026-05-29 12:55:26 +02:00
|
|
|
|
jsonpath "$.items" isCollection
|
|
|
|
|
|
jsonpath "$.items" count == 0
|
2026-06-26 01:01:44 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
# Step 7 – Auto-recording on upload
|
|
|
|
|
|
# The backend `ResourceAccessHook` fires on a successful
|
|
|
|
|
|
# authorised upload, so the new file lands in Recent
|
|
|
|
|
|
# without the client POSTing /api/recent/file/{id}.
|
|
|
|
|
|
# This is the SvelteKit-era contract: the legacy
|
|
|
|
|
|
# vanilla-JS frontend did the POST itself; the new shell
|
|
|
|
|
|
# relies on the service-layer hook instead.
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
POST {{base_url}}/api/files/upload
|
|
|
|
|
|
Authorization: Bearer {{token}}
|
|
|
|
|
|
[MultipartFormData]
|
|
|
|
|
|
folder_id: {{home_folder_id}}
|
|
|
|
|
|
file: file,fixtures/hello.txt; text/plain
|
|
|
|
|
|
|
|
|
|
|
|
HTTP 201
|
|
|
|
|
|
[Captures]
|
|
|
|
|
|
auto_uploaded_id: jsonpath "$.id"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GET {{base_url}}/api/recent/resources
|
|
|
|
|
|
Authorization: Bearer {{token}}
|
|
|
|
|
|
|
|
|
|
|
|
HTTP 200
|
|
|
|
|
|
[Asserts]
|
|
|
|
|
|
jsonpath "$.items" count == 1
|
|
|
|
|
|
jsonpath "$.items[0].resource.id" == "{{auto_uploaded_id}}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
# Step 8 – Auto-recording on GET (file download)
|
|
|
|
|
|
# Clear first, then download the file content and
|
|
|
|
|
|
# assert it reappears in Recent. The per-(user, file)
|
|
|
|
|
|
# 60 s throttle inside the recording hook means the
|
|
|
|
|
|
# cleared row may re-record on the very next GET only
|
|
|
|
|
|
# because we just emptied the table — moka stores the
|
|
|
|
|
|
# throttle entry independently of the DB row, but the
|
|
|
|
|
|
# upsert is idempotent and harmless either way.
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
DELETE {{base_url}}/api/recent/clear
|
|
|
|
|
|
Authorization: Bearer {{token}}
|
|
|
|
|
|
|
|
|
|
|
|
HTTP 200
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GET {{base_url}}/api/files/{{auto_uploaded_id}}
|
|
|
|
|
|
Authorization: Bearer {{token}}
|
|
|
|
|
|
|
|
|
|
|
|
HTTP 200
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GET {{base_url}}/api/recent/resources
|
|
|
|
|
|
Authorization: Bearer {{token}}
|
|
|
|
|
|
|
|
|
|
|
|
HTTP 200
|
|
|
|
|
|
[Asserts]
|
|
|
|
|
|
jsonpath "$.items" count == 1
|
|
|
|
|
|
jsonpath "$.items[0].resource.id" == "{{auto_uploaded_id}}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
# Step 9 – Cleanup so the test is idempotent across runs.
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
DELETE {{base_url}}/api/files/{{auto_uploaded_id}}
|
|
|
|
|
|
Authorization: Bearer {{token}}
|
|
|
|
|
|
|
|
|
|
|
|
HTTP 204
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DELETE {{base_url}}/api/recent/clear
|
|
|
|
|
|
Authorization: Bearer {{token}}
|
|
|
|
|
|
|
|
|
|
|
|
HTTP 200
|