Files
Oxicloud/tests/api/trash_resources.hurl
T
2026-06-23 22:04:20 +02:00

280 lines
11 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# =============================================================
# OxiCloud – Cursor-paginated trash listing (GET /api/trash/resources)
# =============================================================
# Depends on files-folders.hurl having run first (home folder exists).
# Runs after trash.hurl, which leaves an empty trash.
#
# Verifies:
# - Empty trash returns items:[] and no next_cursor
# - 401 without auth
# - Default order_by = deletion_date (soonest-expiring first)
# - order_by=name groups folders before files
# - order_by=size: folders cluster via -1 sentinel
# - resource_types=file / =folder filters narrow the result set
# - Pagination: limit=1 + cursor walks the whole set
# - Cursor is opaque (returned next_cursor is a non-empty string)
#
# Run:
# hurl --variables-file tests/api/test.env --test tests/api/trash_resources.hurl
# =============================================================
# ─────────────────────────────────────────────────────────────
# Step 1 – Login + capture token
# ─────────────────────────────────────────────────────────────
POST {{base_url}}/api/auth/login
Content-Type: application/json
{
"username": "{{username}}",
"password": "{{password}}"
}
HTTP 200
[Captures]
token: jsonpath "$.access_token"
# ─────────────────────────────────────────────────────────────
# Step 2 – Trash starts empty (trash.hurl left it that way)
# ─────────────────────────────────────────────────────────────
GET {{base_url}}/api/trash/resources
Authorization: Bearer {{token}}
HTTP 200
[Asserts]
jsonpath "$.items" isCollection
jsonpath "$.items" count == 0
jsonpath "$.next_cursor" not exists
# ─────────────────────────────────────────────────────────────
# Step 4 – Capture the home folder ID
# ─────────────────────────────────────────────────────────────
GET {{base_url}}/api/folders
Authorization: Bearer {{token}}
HTTP 200
[Captures]
home_folder_id: jsonpath "$[0].id"
# ─────────────────────────────────────────────────────────────
# Step 5 – Create three folders + two files to trash
# folders: trash-res-A, trash-res-B
# files: alpha.txt (in home), beta.txt (in home)
# ─────────────────────────────────────────────────────────────
POST {{base_url}}/api/folders
Authorization: Bearer {{token}}
Content-Type: application/json
{
"name": "trash-res-A",
"parent_id": "{{home_folder_id}}"
}
HTTP 201
[Captures]
folder_a_id: jsonpath "$.id"
POST {{base_url}}/api/folders
Authorization: Bearer {{token}}
Content-Type: application/json
{
"name": "trash-res-B",
"parent_id": "{{home_folder_id}}"
}
HTTP 201
[Captures]
folder_b_id: jsonpath "$.id"
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]
file_alpha_id: jsonpath "$.id"
# Rename uploaded file to alpha.txt so order_by=name has a predictable result
PUT {{base_url}}/api/files/{{file_alpha_id}}/rename
Authorization: Bearer {{token}}
Content-Type: application/json
{
"name": "alpha.txt"
}
HTTP 200
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]
file_beta_id: jsonpath "$.id"
PUT {{base_url}}/api/files/{{file_beta_id}}/rename
Authorization: Bearer {{token}}
Content-Type: application/json
{
"name": "beta.txt"
}
HTTP 200
# ─────────────────────────────────────────────────────────────
# Step 6 – Move all four items to trash
# ─────────────────────────────────────────────────────────────
DELETE {{base_url}}/api/trash/files/{{file_alpha_id}}
Authorization: Bearer {{token}}
HTTP 200
DELETE {{base_url}}/api/trash/files/{{file_beta_id}}
Authorization: Bearer {{token}}
HTTP 200
DELETE {{base_url}}/api/trash/folders/{{folder_a_id}}
Authorization: Bearer {{token}}
HTTP 200
DELETE {{base_url}}/api/trash/folders/{{folder_b_id}}
Authorization: Bearer {{token}}
HTTP 200
# ─────────────────────────────────────────────────────────────
# Step 7 – Default listing: 4 items, all carry trashed_at + deletion_date
# + drive_id (D2b — enables per-drive grouping in the UI).
# The listing is also drive-membership scoped (D2b stage 2): the
# admin sees their own personal drive's trashed items, just as
# before, because a personal drive Owner has all roles needed.
# ─────────────────────────────────────────────────────────────
GET {{base_url}}/api/trash/resources
Authorization: Bearer {{token}}
HTTP 200
[Asserts]
jsonpath "$.items" count == 4
jsonpath "$.items[0].trashed_at" isString
jsonpath "$.items[0].deletion_date" isString
# D2b: drive_id is non-null on every trashed item.
jsonpath "$.items[0].drive_id" isString
jsonpath "$.items[1].drive_id" isString
jsonpath "$.items[2].drive_id" isString
jsonpath "$.items[3].drive_id" isString
jsonpath "$.items[0].resource_type" matches "^(file|folder)$"
jsonpath "$.items[*].resource.id" contains {{folder_a_id}}
jsonpath "$.items[*].resource.id" contains {{folder_b_id}}
jsonpath "$.items[*].resource.id" contains {{file_alpha_id}}
jsonpath "$.items[*].resource.id" contains {{file_beta_id}}
# ─────────────────────────────────────────────────────────────
# Step 8 – order_by=name: folders sort before files (folder_first axis),
# then alphabetic. Expected order:
# [trash-res-A, trash-res-B, alpha.txt, beta.txt]
# ─────────────────────────────────────────────────────────────
GET {{base_url}}/api/trash/resources?order_by=name
Authorization: Bearer {{token}}
HTTP 200
[Asserts]
jsonpath "$.items[0].resource.name" == "trash-res-A"
jsonpath "$.items[1].resource.name" == "trash-res-B"
jsonpath "$.items[2].resource.name" == "alpha.txt"
jsonpath "$.items[3].resource.name" == "beta.txt"
# ─────────────────────────────────────────────────────────────
# Step 9 – order_by=size: folders use sentinel -1 so they cluster
# together (before files with size >= 0).
# ─────────────────────────────────────────────────────────────
GET {{base_url}}/api/trash/resources?order_by=size
Authorization: Bearer {{token}}
HTTP 200
[Asserts]
jsonpath "$.items" count == 4
jsonpath "$.items[0].resource_type" == "folder"
jsonpath "$.items[1].resource_type" == "folder"
jsonpath "$.items[2].resource_type" == "file"
jsonpath "$.items[3].resource_type" == "file"
# ─────────────────────────────────────────────────────────────
# Step 10 – resource_types=file → only files (2)
# ─────────────────────────────────────────────────────────────
GET {{base_url}}/api/trash/resources?resource_types=file
Authorization: Bearer {{token}}
HTTP 200
[Asserts]
jsonpath "$.items" count == 2
jsonpath "$.items[0].resource_type" == "file"
jsonpath "$.items[1].resource_type" == "file"
# ─────────────────────────────────────────────────────────────
# Step 11 – resource_types=folder → only folders (2)
# ─────────────────────────────────────────────────────────────
GET {{base_url}}/api/trash/resources?resource_types=folder
Authorization: Bearer {{token}}
HTTP 200
[Asserts]
jsonpath "$.items" count == 2
jsonpath "$.items[0].resource_type" == "folder"
jsonpath "$.items[1].resource_type" == "folder"
# ─────────────────────────────────────────────────────────────
# Step 12 – Pagination: limit=1 returns 1 item + a next_cursor
# ─────────────────────────────────────────────────────────────
GET {{base_url}}/api/trash/resources?order_by=name&limit=1
Authorization: Bearer {{token}}
HTTP 200
[Captures]
page1_cursor: jsonpath "$.next_cursor"
[Asserts]
jsonpath "$.items" count == 1
jsonpath "$.items[0].resource.name" == "trash-res-A"
jsonpath "$.next_cursor" isString
# Step 13 – Walk to page 2 with the captured cursor
GET {{base_url}}/api/trash/resources?order_by=name&limit=1&cursor={{page1_cursor}}
Authorization: Bearer {{token}}
HTTP 200
[Asserts]
jsonpath "$.items" count == 1
jsonpath "$.items[0].resource.name" == "trash-res-B"
jsonpath "$.next_cursor" isString
# ─────────────────────────────────────────────────────────────
# Step 14 – Cleanup: empty trash so subsequent tests see a clean slate
# ─────────────────────────────────────────────────────────────
DELETE {{base_url}}/api/trash/empty
Authorization: Bearer {{token}}
HTTP 200
GET {{base_url}}/api/trash/resources
Authorization: Bearer {{token}}
HTTP 200
[Asserts]
jsonpath "$.items" count == 0