158 lines
7.5 KiB
Markdown
158 lines
7.5 KiB
Markdown
# API functional tests
|
||
|
||
Tests are written using [Hurl](https://hurl.dev) — a plain-text, CLI-first HTTP testing tool.
|
||
|
||
## Prerequisites
|
||
|
||
- [Hurl](https://hurl.dev/docs/installation.html) ≥ 4.0
|
||
Install: `cargo install hurl` or via your package manager
|
||
|
||
## Configuration
|
||
|
||
Edit `test.env` to match your local instance. This file is the single source of
|
||
truth: `run.sh` sources it for shell variables and passes it to Hurl as
|
||
`--variables-file`.
|
||
|
||
```
|
||
base_url=http://localhost:8087
|
||
username=admin
|
||
email=admin@example.com
|
||
password=TestPassword1!
|
||
```
|
||
|
||
## Running the tests
|
||
|
||
```bash
|
||
# First-time setup (run once on a fresh instance)
|
||
hurl --variables-file tests/api/test.env --test tests/api/setup.hurl
|
||
|
||
# Contacts CRUD scenario
|
||
hurl --variables-file tests/api/test.env --test tests/api/contacts.hurl
|
||
|
||
# All scenarios at once
|
||
hurl --variables-file tests/api/test.env --test tests/api/setup.hurl tests/api/contacts.hurl
|
||
|
||
# With full request/response output
|
||
hurl --variables-file tests/api/test.env --test --verbose tests/api/contacts.hurl
|
||
|
||
# Generate an HTML report
|
||
hurl --variables-file tests/api/test.env --test --report-html /tmp/hurl-report tests/api/contacts.hurl
|
||
```
|
||
|
||
## Test files
|
||
|
||
| File | Description |
|
||
|---|---|
|
||
| `setup.hurl` | One-time admin account creation; also asserts the endpoint is locked afterwards |
|
||
| `files-folders.hurl` | Files & folders CRUD scenario (22 steps, see below) |
|
||
| `favorites.hurl` | Favorites add/list/remove scenario (11 steps); depends on `files-folders.hurl` state |
|
||
| `trash.hurl` | Trash move/restore/purge scenario (16 steps); depends on `files-folders.hurl` state |
|
||
| `recent.hurl` | Recent items record/list/clear scenario (6 steps); depends on `files-folders.hurl` state |
|
||
| `contacts.hurl` | Full contacts CRUD scenario (14 steps, see below) |
|
||
| `test.env` | Variables: `base_url`, `username`, `email`, `password` — used by both Hurl and `run.sh` |
|
||
|
||
## Scenario: `files-folders.hurl`
|
||
|
||
| Step | Description |
|
||
|---|---|
|
||
| 1 | Login – capture JWT token |
|
||
| 2 | List root folders – assert exactly 1 (home folder), capture `home_folder_id`, assert `parent_id` is null |
|
||
| 3 | Browse home folder sub-folders – assert empty |
|
||
| 4 | Browse home folder files – assert empty |
|
||
| 5 | Create folder named `"/"` – assert HTTP 400, `error_type == "Invalid Input"` |
|
||
| 6 | Create `test1` inside home folder – capture `test1_id`, assert `parent_id` == `home_folder_id` |
|
||
| 7 | Create `test2` inside `test1` – capture `test2_id`, assert `parent_id` == `test1_id` |
|
||
| 8 | Browse home folder – assert exactly 1 sub-folder (`test1`) |
|
||
| 9 | Browse `test1` – assert exactly 1 sub-folder (`test2`), assert `parent_id` |
|
||
| 10 | Upload `fixtures/hello.txt` into `test2` – capture `file_id`, assert name/size/mime_type/folder_id |
|
||
| 11 | List files in `test2` – assert count=1, `mime_type == text/plain`, `icon_class == fas fa-file-alt` |
|
||
| 12 | Move `test2` from `test1` into home folder – assert `parent_id` == `home_folder_id` |
|
||
| 13 | Browse `test1` – assert empty (no more children) |
|
||
| 14 | Browse home folder – assert 2 sub-folders (`test1` and `test2`) |
|
||
| 15 | Rename `test2` → `test2-renamed` – assert new name, `parent_id` unchanged |
|
||
| 16 | Rename `hello.txt` → `hello-renamed.txt` – assert new name, `folder_id` unchanged |
|
||
| 17 | Rename `hello-renamed.txt` to `"."` – assert HTTP 400, `error_type == "Invalid Input"` |
|
||
| 18 | Upload `fixtures/oxicloud-logo.jpg` into home folder – capture `logo_id`, assert `mime_type == image/jpeg` |
|
||
| 19 | List files in home folder – assert count=1, `icon_class == fas fa-file-image` |
|
||
| 20 | `GET /api/files/{logo_id}/thumbnail/icon` → HTTP 200 |
|
||
| 21 | `GET /api/files/{logo_id}/thumbnail/preview` → HTTP 200 |
|
||
| 22 | `GET /api/files/{logo_id}/thumbnail/large` → HTTP 200 |
|
||
|
||
## Scenario: `favorites.hurl`
|
||
|
||
Depends on `files-folders.hurl` having run first (test1, test2-renamed/hello-renamed.txt must exist).
|
||
|
||
| Step | Description |
|
||
|---|---|
|
||
| 1 | Login – capture JWT token |
|
||
| 2 | Assert no favorites yet |
|
||
| 3 | Discover item IDs: home folder → contents (test1=$[0], test2-renamed=$[1]) → files in test2-renamed |
|
||
| 4 | `POST /api/favorites/file/{file_id}` – add hello-renamed.txt → HTTP 201 |
|
||
| 5 | List favorites – assert count=1, item_type=file, item_name=hello-renamed.txt |
|
||
| 6 | `POST /api/favorites/folder/{test1_id}` – add test1 → HTTP 201 |
|
||
| 7 | List favorites – assert count=2, both IDs present (order-independent) |
|
||
| 8 | `DELETE /api/favorites/file/{file_id}` – remove hello-renamed.txt → HTTP 200 |
|
||
| 9 | List favorites – assert count=1, item_type=folder, item_name=test1 |
|
||
| 10 | Cleanup: `DELETE /api/favorites/folder/{test1_id}` → HTTP 200 |
|
||
| 11 | List favorites – assert count=0 |
|
||
|
||
## Scenario: `trash.hurl`
|
||
|
||
Depends on `files-folders.hurl` having run first (home folder must exist).
|
||
|
||
| Step | Description |
|
||
|---|---|
|
||
| 1 | Login – capture JWT token |
|
||
| 2 | Assert trash is empty |
|
||
| 3 | Capture home folder ID |
|
||
| 4 | Create `to-delete` folder in home folder – capture `to_delete_id` |
|
||
| 5 | Upload `hello.txt` into `to-delete` |
|
||
| 6 | `DELETE /api/folders/{to_delete_id}` – moves folder to trash → HTTP 204 |
|
||
| 7 | List trash – assert count=1, item_type=folder, name=to-delete, original_id matches; capture `trash_id` |
|
||
| 8 | List home folder contents – assert `to-delete` is not present |
|
||
| 9 | `POST /api/trash/{trash_id}/restore` → HTTP 200, `success == true` |
|
||
| 10 | List home folder contents – assert `to-delete` is present |
|
||
| 11 | List files in `to-delete` – assert count=1, name=hello.txt |
|
||
| 12 | List trash – assert empty (restore removed the entry) |
|
||
| 13 | `DELETE /api/folders/{to_delete_id}` – move restored folder to trash again → HTTP 204 |
|
||
| 14 | `DELETE /api/trash/empty` – purge trash → HTTP 200, `success == true` |
|
||
| 15 | List trash – assert empty after purge |
|
||
| 16 | List home folder contents – assert `to-delete` is not present (permanently gone) |
|
||
|
||
## Scenario: `recent.hurl`
|
||
|
||
Depends on `files-folders.hurl` having run first (test2-renamed/hello-renamed.txt must exist).
|
||
Recent items are not auto-recorded on upload — step 3 explicitly registers the access.
|
||
|
||
| Step | Description |
|
||
|---|---|
|
||
| 1 | Login – capture JWT token |
|
||
| 2 | Discover `file_id` of hello-renamed.txt via home folder → test2-renamed contents |
|
||
| 3 | `POST /api/recent/file/{file_id}` – record access → HTTP 200 |
|
||
| 4 | `GET /api/recent` – assert count=1, item_type=file, item_name=hello-renamed.txt |
|
||
| 5 | `DELETE /api/recent/clear` – clear all recent items → HTTP 200 |
|
||
| 6 | `GET /api/recent` – assert count=0 |
|
||
|
||
## Scenario: `contacts.hurl`
|
||
|
||
| Step | Description |
|
||
|---|---|
|
||
| 1 | Login – capture JWT token |
|
||
| 2 | List address books – assert system book is present and read-only |
|
||
| 3 | Create personal address book – capture `book_id` |
|
||
| 4 | List contacts in new book – assert empty |
|
||
| 5 | Create contact John Doe – capture `contact_id` |
|
||
| 6 | List contacts – assert exactly 1 result with John Doe's id |
|
||
| 7 | Get John Doe – assert all fields, capture `ETag` |
|
||
| 8 | Update John Doe (nickname, org, notes) with `If-Match` – assert new values, capture refreshed `ETag` |
|
||
| 9 | Delete John Doe with `If-Match` |
|
||
| 10 | List contacts – assert empty again |
|
||
| 11 | Delete personal address book |
|
||
| 12 | List address books – assert `book_id` no longer present |
|
||
| 13 | List system address book – assert non-empty collection of OxiCloud users |
|
||
|
||
## Legacy bash tests
|
||
|
||
`test.sh` and `common.sh` are the original curl/bash scripts kept for reference.
|
||
Run them with `bash tests/api/test.sh` from the repo root (requires `jq`).
|