From e28776c7a6c1fd0b20ec2e48054927a3ffd953d2 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Sun, 1 Feb 2026 13:21:35 -0500 Subject: [PATCH] test(api): add Bruno API tests for devices, media items, and progress --- bruno/devices/Create Device File Alias.bru | 97 ++++++++++++++++++++++ bruno/devices/Get Device File Aliases.bru | 78 +++++++++++++++++ bruno/media-items/Update Media Rating.bru | 95 +++++++++++++++++++++ bruno/progress/Delete Reading Progress.bru | 59 +++++++++++++ 4 files changed, 329 insertions(+) create mode 100644 bruno/devices/Create Device File Alias.bru create mode 100644 bruno/devices/Get Device File Aliases.bru create mode 100644 bruno/media-items/Update Media Rating.bru create mode 100644 bruno/progress/Delete Reading Progress.bru diff --git a/bruno/devices/Create Device File Alias.bru b/bruno/devices/Create Device File Alias.bru new file mode 100644 index 0000000..658d967 --- /dev/null +++ b/bruno/devices/Create Device File Alias.bru @@ -0,0 +1,97 @@ +meta { + name: Create Device File Alias + type: http + seq: 1 +} + +post { + url: {{base_url}}/api/devices/{{device_id}}/file-aliases + body: json + auth: inherit +} + +body:json { + { + "file_path": "/mnt/sd/books/my-book.kepub.epub", + "media_item_id": "{{media_item_id}}" + } +} + +headers { + Content-Type: application/json +} + +tests { + test_create_device_file_alias_success(status, headers, body) { + if (status !== 201 && status !== 200) { + throw new Error("Expected status 201 or 200, got " + status); + } + + const contentType = headers["content-type"]; + if (!contentType || !contentType.includes("application/json")) { + throw new Error("Expected content-type to contain application/json"); + } + + let data; + try { + data = JSON.parse(body); + } catch (e) { + throw new Error("Response body is not valid JSON"); + } + + if (!data.id) { + throw new Error("Response missing id field"); + } + + if (!data.file_path) { + throw new Error("Response missing file_path field"); + } + + return true; + } +} + +vars:pre-request { + deviceId: "8821b703-1234-5678-9123-446655440002" + mediaItemId: "8821b703-1234-5678-9123-446655440001" +} + +settings { + encodeUrl: true + timeout: 0 +} + +docs { + ## Create Device File Alias + + Creates a new file alias for a device. File aliases map device-specific file paths to media items. + + **Method:** POST + + **Endpoint:** /api/devices/:id/file-aliases + + **Authentication:** Required (Bearer token) + + **Path Parameters:** + - `id` (string, required): Device UUID + + **Request Body:** + - `file_path` (string, required): Device-specific file path + - `media_item_id` (string, required): Media item UUID to link to + + **Response:** Created file alias object + - `id` (string): Alias UUID + - `device_id` (string): Device UUID + - `file_path` (string): Device-specific file path + - `media_item_id` (string): Associated media item UUID + - `created_at` (string): Creation timestamp + - `updated_at` (string): Last update timestamp + + **Status Codes:** + - 201: Created + - 200: Success + - 400: Invalid request body + - 401: Unauthorized + - 404: Device not found + - 500: Internal server error +} diff --git a/bruno/devices/Get Device File Aliases.bru b/bruno/devices/Get Device File Aliases.bru new file mode 100644 index 0000000..b0657dd --- /dev/null +++ b/bruno/devices/Get Device File Aliases.bru @@ -0,0 +1,78 @@ +meta { + name: Get Device File Aliases + type: http + seq: 1 +} + +get { + url: {{base_url}}/api/devices/{{device_id}}/file-aliases + auth: inherit +} + +headers { + Content-Type: application/json +} + +tests { + test_get_device_file_aliases_success(status, headers, body) { + if (status !== 200) { + throw new Error("Expected status 200, got " + status); + } + + const contentType = headers["content-type"]; + if (!contentType || !contentType.includes("application/json")) { + throw new Error("Expected content-type to contain application/json"); + } + + let data; + try { + data = JSON.parse(body); + } catch (e) { + throw new Error("Response body is not valid JSON"); + } + + if (!Array.isArray(data)) { + throw new Error("Expected response body to be an array"); + } + + return true; + } +} + +vars:pre-request { + deviceId: "8821b703-1234-5678-9123-446655440002" +} + +settings { + encodeUrl: true + timeout: 0 +} + +docs { + ## Get Device File Aliases + + Retrieves all file aliases for a specific device. File aliases are used to map device-specific file paths to media items. + + **Method:** GET + + **Endpoint:** /api/devices/:id/file-aliases + + **Authentication:** Required (Bearer token) + + **Path Parameters:** + - `id` (string, required): Device UUID + + **Response:** Array of file alias objects + - `id` (string): Alias UUID + - `device_id` (string): Device UUID + - `file_path` (string): Device-specific file path + - `media_item_id` (string): Associated media item UUID + - `created_at` (string): Creation timestamp + - `updated_at` (string): Last update timestamp + + **Status Codes:** + - 200: Success + - 401: Unauthorized + - 404: Device not found + - 500: Internal server error +} diff --git a/bruno/media-items/Update Media Rating.bru b/bruno/media-items/Update Media Rating.bru new file mode 100644 index 0000000..a017676 --- /dev/null +++ b/bruno/media-items/Update Media Rating.bru @@ -0,0 +1,95 @@ +meta { + name: Update Media Rating + type: http + seq: 1 +} + +put { + url: {{base_url}}/api/media-items/{{media_item_id}}/rating + body: json + auth: inherit +} + +body:json { + { + "rating": 4, + "review": "Great book! Very enjoyable read." + } +} + +headers { + Content-Type: application/json +} + +tests { + test_update_media_rating_success(status, headers, body) { + if (status !== 200) { + throw new Error("Expected status 200, got " + status); + } + + const contentType = headers["content-type"]; + if (!contentType || !contentType.includes("application/json")) { + throw new Error("Expected content-type to contain application/json"); + } + + let data; + try { + data = JSON.parse(body); + } catch (e) { + throw new Error("Response body is not valid JSON"); + } + + if (!data.id) { + throw new Error("Response missing id field"); + } + + if (typeof data.rating !== "number") { + throw new Error("Rating should be a number"); + } + + return true; + } +} + +vars:pre-request { + mediaItemId: "8821b703-1234-5678-9123-446655440001" +} + +settings { + encodeUrl: true + timeout: 0 +} + +docs { + ## Update Media Rating + + Updates an existing rating for a media item. + + **Method:** PUT + + **Endpoint:** /api/media-items/:id/rating + + **Authentication:** Required (Bearer token) + + **Path Parameters:** + - `id` (string, required): Media item UUID + + **Request Body:** + - `rating` (number, required): Rating value (typically 1-5) + - `review` (string, optional): Review text + + **Response:** Updated rating object + - `id` (string): Rating ID + - `media_item_id` (string): Media item UUID + - `rating` (number): Rating value + - `review` (string): Review text + - `created_at` (string): Creation timestamp + - `updated_at` (string): Last update timestamp + + **Status Codes:** + - 200: Success + - 400: Invalid request body + - 401: Unauthorized + - 404: Media item or rating not found + - 500: Internal server error +} diff --git a/bruno/progress/Delete Reading Progress.bru b/bruno/progress/Delete Reading Progress.bru new file mode 100644 index 0000000..74d4502 --- /dev/null +++ b/bruno/progress/Delete Reading Progress.bru @@ -0,0 +1,59 @@ +meta { + name: Delete Reading Progress + type: http + seq: 1 +} + +delete { + url: {{base_url}}/api/media-items/{{media_item_id}}/progress + auth: inherit +} + +headers { + Content-Type: application/json +} + +tests { + test_delete_reading_progress_success(status, headers, body) { + if (status !== 200 && status !== 204) { + throw new Error("Expected status 200 or 204, got " + status); + } + + return true; + } +} + +vars:pre-request { + mediaItemId: "8821b703-1234-5678-9123-446655440001" +} + +settings { + encodeUrl: true + timeout: 0 +} + +docs { + ## Delete Reading Progress + + Deletes reading progress for a media item. This is a legacy endpoint - consider using universal progress endpoints instead. + + **Method:** DELETE + + **Endpoint:** /api/media-items/:id/progress + + **Authentication:** Required (Bearer token) + + **Path Parameters:** + - `id` (string, required): Media item UUID + + **Response:** Success message or empty + + **Status Codes:** + - 200: Success + - 204: Success (no content) + - 401: Unauthorized + - 404: Media item not found + - 500: Internal server error + + **Note:** This is a legacy endpoint. Use `/api/progress/:id` endpoints for new implementations. +}