Files
Oxicloud/tests/api/trash_resources.hurl
T

271 lines
11 KiB
Plaintext
Raw Normal View History

# =============================================================
# 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
# ─────────────────────────────────────────────────────────────
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
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