Closes the remaining integration-suite failures (handoff open bug 3),
line by line:
- Fixture family (the upsert equivalence): tags_filter_test
("Science Fiction" found 1 of 3; "Fantasy" 404'd on zero results),
media_item_isbn_test (normalization read back the first case's ISBN
everywhere; edge cases saw a nil ISBN; pagination collapsed 5
creates onto 1 row), search_unified_test (its 3 books were actually
1 row + two no-op creates) — all POSTed a constant file_path into
one library while CreateMediaItem upserts ON CONFLICT
(library_id, file_path). Every fixture now uses unique per-item
paths, the suite's universal convention elsewhere. TestTagsFilter
confirmed same-family: counts came right with no second bug.
- New TestMediaItemCreateDuplicatePath pins the honest-create
contract from da13898: 201 for the first create; 200 + duplicate
flag + the EXISTING row (never a 201 lie), second payload not
overwritten.
- library_browse_test: the admin subtest browsed the container's
/tmp and required it non-empty — env-coupled (empty /tmp → "was
[]"). Now browses a self-created t.TempDir with two subdirs and a
decoy file, asserting ONLY directories are listed.
- series_integration_test: three stale assertions re-anchored to the
shipped contracts, each with a ground-truth comment: /dashboard/
sections key identity on the collection NAME (BuildSections ID =
CollectionName; the web/app reorder + hidden prefs persist those
strings) — the kebab query_type is the storage key and is not
exposed; /api/series/books is name-ONLY (the app client and the
web SSR page both send name only; library_id is ignored, never
validated); /api/series is optional-scope BY DESIGN (GetDistinct-
Series: narg IS NULL OR library_id = narg aggregates across
libraries when omitted). The former 400-on-missing-library_id
expectations asserted validation that never shipped.
- gofmt rider on three untouched-in-this-arc test files
(dashboard_integration, search, test_helpers).
Full suite with -parallel=1: 217 groups pass, zero failures.
597 lines
18 KiB
Go
597 lines
18 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// createTestLibrary creates a test library and returns its ID
|
|
func createTestLibrary(t *testing.T, ts *httptest.Server, token, name string) string {
|
|
t.Helper()
|
|
|
|
payload := map[string]interface{}{
|
|
"name": name,
|
|
"description": "Test library for ISBN tests",
|
|
"type": "ebooks",
|
|
}
|
|
|
|
body, _ := json.Marshal(payload)
|
|
req, _ := http.NewRequest("POST", ts.URL+"/api/libraries", bytes.NewBuffer(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
defer func(Body io.ReadCloser) {
|
|
_ = Body.Close()
|
|
}(resp.Body)
|
|
|
|
require.Equal(t, http.StatusCreated, resp.StatusCode)
|
|
|
|
var result map[string]interface{}
|
|
err = json.NewDecoder(resp.Body).Decode(&result)
|
|
require.NoError(t, err)
|
|
|
|
return result["id"].(string)
|
|
}
|
|
|
|
// TestMediaItemISBNNormalization tests ISBN normalization with media-items endpoint
|
|
func TestMediaItemISBNNormalization(t *testing.T) {
|
|
setup := setupTestServer(t)
|
|
|
|
// Create an ebook library first
|
|
token := setup.Token
|
|
libID := createTestLibrary(t, setup.Server, token, "test-isbn-lib")
|
|
|
|
// Add a folder to the library (required before adding media items)
|
|
addFolderToLibrary(t, setup, libID, "/app/uploads")
|
|
|
|
// Test ISBN normalization cases
|
|
testCases := []struct {
|
|
name string
|
|
input string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "ISBN-13 with hyphens (978-0-12345-678-9)",
|
|
input: "978-0-12345-678-9",
|
|
expected: "9780123456789",
|
|
},
|
|
{
|
|
name: "ISBN-13 with single hyphen (978-0123456789)",
|
|
input: "978-0123456789",
|
|
expected: "9780123456789",
|
|
},
|
|
{
|
|
name: "ISBN-13 without hyphens",
|
|
input: "9780123456789",
|
|
expected: "9780123456789",
|
|
},
|
|
{
|
|
name: "ISBN-13 with spaces",
|
|
input: "978 0123456789",
|
|
expected: "9780123456789",
|
|
},
|
|
{
|
|
name: "ISBN-13 with mixed hyphens and spaces",
|
|
input: "978-0 1234-56789",
|
|
expected: "9780123456789",
|
|
},
|
|
{
|
|
name: "ISBN-10 with hyphens",
|
|
input: "0-12345-678-9",
|
|
expected: "9780123456786",
|
|
},
|
|
{
|
|
name: "ISBN-10 without hyphens",
|
|
input: "0123456789",
|
|
expected: "9780123456786",
|
|
},
|
|
{
|
|
name: "ISBN-10 with X",
|
|
input: "0-12345-678-X",
|
|
expected: "9780123456786",
|
|
},
|
|
{
|
|
name: "ISBN-10 converts to ISBN-13",
|
|
input: "0-306-40615-2",
|
|
expected: "9780306406157",
|
|
},
|
|
{
|
|
name: "ISBN-13 with trailing hyphen",
|
|
input: "978030640615-7-",
|
|
expected: "9780306406157",
|
|
},
|
|
{
|
|
name: "ISBN-10 with trailing hyphen",
|
|
input: "0306406152-",
|
|
expected: "9780306406157",
|
|
},
|
|
{
|
|
name: "only hyphens converts to empty string",
|
|
input: "---",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "only spaces converts to empty string",
|
|
input: " ",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "ISBN-10 with X converts to ISBN-13",
|
|
input: "0-596-00965-X",
|
|
expected: "9780596009656",
|
|
},
|
|
{
|
|
name: "ISBN-13 with leading/trailing hyphens",
|
|
input: "-978-0-306-40615-7-",
|
|
expected: "9780306406157",
|
|
},
|
|
{
|
|
name: "ISBN-13 preserves case",
|
|
input: "978-0-306-40615-7",
|
|
expected: "9780306406157",
|
|
},
|
|
{
|
|
name: "ISBN-13 lowercase preserved",
|
|
input: "978-0-306-40615-7",
|
|
expected: "9780306406157",
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
// Unique file_path per case: CreateMediaItem upserts ON
|
|
// CONFLICT (library_id, file_path), so a constant path would
|
|
// return the FIRST row's ISBN for every later case.
|
|
slug := strings.ReplaceAll(strings.ToLower(tc.name), " ", "-")
|
|
payload := map[string]interface{}{
|
|
"title": fmt.Sprintf("Test Book %s", tc.name),
|
|
"isbn": tc.input,
|
|
"library_id": libID,
|
|
"file_path": "/test/" + slug + ".epub",
|
|
"file_size": 1024,
|
|
"mime_type": "application/epub+zip",
|
|
}
|
|
|
|
body, _ := json.Marshal(payload)
|
|
req, _ := http.NewRequest("POST", setup.Server.URL+"/api/media-items", bytes.NewBuffer(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
defer func(Body io.ReadCloser) {
|
|
_ = Body.Close()
|
|
}(resp.Body)
|
|
|
|
// Check if this is an invalid ISBN case that should return 422
|
|
if tc.expected == "" && (tc.input == "---" || tc.input == " ") {
|
|
assert.Equal(t, http.StatusUnprocessableEntity, resp.StatusCode)
|
|
} else {
|
|
assert.Equal(t, http.StatusCreated, resp.StatusCode)
|
|
}
|
|
|
|
var response map[string]interface{}
|
|
err = json.NewDecoder(resp.Body).Decode(&response)
|
|
require.NoError(t, err)
|
|
|
|
// For valid ISBN responses, verify normalization worked correctly
|
|
if resp.StatusCode == http.StatusCreated {
|
|
assert.Equal(t, tc.expected, response["isbn"])
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestMediaItemISBNEdgeCases tests ISBN edge cases
|
|
func TestMediaItemISBNEdgeCases(t *testing.T) {
|
|
setup := setupTestServer(t)
|
|
|
|
token := setup.Token
|
|
libID := createTestLibrary(t, setup.Server, token, "test-isbn-edge-lib")
|
|
addFolderToLibrary(t, setup, libID, "/app/uploads")
|
|
|
|
t.Run("Empty ISBN should be accepted", func(t *testing.T) {
|
|
payload := map[string]interface{}{
|
|
"title": "Book without ISBN",
|
|
"library_id": libID,
|
|
"file_path": "/test/book-without-isbn.epub",
|
|
"file_size": 1024,
|
|
"mime_type": "application/epub+zip",
|
|
}
|
|
|
|
body, _ := json.Marshal(payload)
|
|
req, _ := http.NewRequest("POST", setup.Server.URL+"/api/media-items", bytes.NewBuffer(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
defer func(Body io.ReadCloser) {
|
|
_ = Body.Close()
|
|
}(resp.Body)
|
|
|
|
assert.Equal(t, http.StatusCreated, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("ISBN with multiple hyphens", func(t *testing.T) {
|
|
payload := map[string]interface{}{
|
|
"title": "Multi-Hyphen ISBN",
|
|
"isbn": "978-0-306-40615-7",
|
|
"library_id": libID,
|
|
"file_path": "/test/multi-hyphen-isbn.epub",
|
|
"file_size": 1024,
|
|
"mime_type": "application/epub+zip",
|
|
}
|
|
|
|
body, _ := json.Marshal(payload)
|
|
req, _ := http.NewRequest("POST", setup.Server.URL+"/api/media-items", bytes.NewBuffer(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
defer func(Body io.ReadCloser) {
|
|
_ = Body.Close()
|
|
}(resp.Body)
|
|
|
|
var response map[string]interface{}
|
|
err = json.NewDecoder(resp.Body).Decode(&response)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, http.StatusCreated, resp.StatusCode)
|
|
assert.Equal(t, "9780306406157", response["isbn"])
|
|
})
|
|
|
|
t.Run("ISBN with trailing hyphen", func(t *testing.T) {
|
|
payload := map[string]interface{}{
|
|
"title": "Trailing Hyphen ISBN",
|
|
"isbn": "978-0-596-00965-2",
|
|
"library_id": libID,
|
|
"file_path": "/test/trailing-hyphen-isbn.epub",
|
|
"file_size": 1024,
|
|
"mime_type": "application/epub+zip",
|
|
}
|
|
|
|
body, _ := json.Marshal(payload)
|
|
req, _ := http.NewRequest("POST", setup.Server.URL+"/api/media-items", bytes.NewBuffer(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
defer func(Body io.ReadCloser) {
|
|
_ = Body.Close()
|
|
}(resp.Body)
|
|
|
|
var response map[string]interface{}
|
|
err = json.NewDecoder(resp.Body).Decode(&response)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, http.StatusCreated, resp.StatusCode)
|
|
assert.Equal(t, "9780596009652", response["isbn"])
|
|
})
|
|
}
|
|
|
|
// TestMediaItemsPagination tests pagination with media-items endpoint
|
|
func TestMediaItemsPagination(t *testing.T) {
|
|
setup := setupTestServer(t)
|
|
|
|
token := setup.Token
|
|
libID := createTestLibrary(t, setup.Server, token, "test-pagination-lib")
|
|
addFolderToLibrary(t, setup, libID, "/app/uploads")
|
|
|
|
// Create some test media items. Unique file_path per item: the create
|
|
// endpoint upserts ON CONFLICT (library_id, file_path), so a constant
|
|
// path would collapse all five creates onto one row.
|
|
for i := 1; i <= 5; i++ {
|
|
payload := map[string]interface{}{
|
|
"title": fmt.Sprintf("Book %d", i),
|
|
"isbn": fmt.Sprintf("978030640615%d", i),
|
|
"library_id": libID,
|
|
"file_path": fmt.Sprintf("/test/book-%d.epub", i),
|
|
"file_size": 1024,
|
|
"mime_type": "application/epub+zip",
|
|
}
|
|
|
|
body, _ := json.Marshal(payload)
|
|
req, _ := http.NewRequest("POST", setup.Server.URL+"/api/media-items", bytes.NewBuffer(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
_ = resp.Body.Close()
|
|
}
|
|
|
|
// Small delay to allow database to commit before pagination queries
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
t.Run("Valid pagination parameters", func(t *testing.T) {
|
|
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/media-items?library_id="+libID+"&limit=2&offset=0", nil)
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
defer func(Body io.ReadCloser) {
|
|
_ = Body.Close()
|
|
}(resp.Body)
|
|
|
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
|
|
|
var response map[string]interface{}
|
|
err = json.NewDecoder(resp.Body).Decode(&response)
|
|
require.NoError(t, err)
|
|
data := response["data"].([]interface{})
|
|
|
|
// Should get 2 items
|
|
assert.Equal(t, 2, len(data))
|
|
})
|
|
|
|
t.Run("Pagination with offset", func(t *testing.T) {
|
|
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/media-items?library_id="+libID+"&limit=2&offset=2", nil)
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
defer func(Body io.ReadCloser) {
|
|
_ = Body.Close()
|
|
}(resp.Body)
|
|
|
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
|
|
|
var response map[string]interface{}
|
|
err = json.NewDecoder(resp.Body).Decode(&response)
|
|
require.NoError(t, err)
|
|
data := response["data"].([]interface{})
|
|
|
|
// Should get 2 items starting from offset 2
|
|
assert.Equal(t, 2, len(data))
|
|
})
|
|
|
|
t.Run("Negative limit should fail", func(t *testing.T) {
|
|
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/media-items?library_id="+libID+"&limit=-10&offset=0", nil)
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
defer func(Body io.ReadCloser) {
|
|
_ = Body.Close()
|
|
}(resp.Body)
|
|
|
|
// Should return 400 Bad Request or handle it gracefully
|
|
assert.NotEqual(t, http.StatusOK, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("Negative offset should fail", func(t *testing.T) {
|
|
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/media-items?library_id="+libID+"&limit=10&offset=-5", nil)
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
defer func(Body io.ReadCloser) {
|
|
_ = Body.Close()
|
|
}(resp.Body)
|
|
|
|
// Should return 400 Bad Request or handle it gracefully
|
|
assert.NotEqual(t, http.StatusOK, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("Limit exceeds maximum", func(t *testing.T) {
|
|
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/media-items?library_id="+libID+"&limit=10000&offset=0", nil)
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
defer func(Body io.ReadCloser) {
|
|
_ = Body.Close()
|
|
}(resp.Body)
|
|
|
|
// Should be capped at maximum or return error
|
|
// The application uses maxPaginationLimit = 1000
|
|
assert.NotEqual(t, http.StatusInternalServerError, resp.StatusCode)
|
|
})
|
|
}
|
|
|
|
// TestMediaItemCreateDuplicatePath pins the create endpoint's duplicate
|
|
// behavior: a POST with a (library_id, file_path) that already exists
|
|
// answers 200 OK with the EXISTING item and duplicate=true — never a
|
|
// 201 with the old row pretending to be new, and nothing overwritten.
|
|
func TestMediaItemCreateDuplicatePath(t *testing.T) {
|
|
setup := setupTestServer(t)
|
|
|
|
token := setup.Token
|
|
libID := createTestLibrary(t, setup.Server, token, "test-dup-create-lib")
|
|
addFolderToLibrary(t, setup, libID, "/app/uploads")
|
|
|
|
createPayload := func(title string) []byte {
|
|
body, _ := json.Marshal(map[string]interface{}{
|
|
"title": title,
|
|
"author": "First Author",
|
|
"isbn": "9780306406157",
|
|
"library_id": libID,
|
|
"file_path": "/test/dup-target.epub",
|
|
"file_size": 1024,
|
|
"mime_type": "application/epub+zip",
|
|
})
|
|
return body
|
|
}
|
|
|
|
post := func(body []byte) (*http.Response, []byte) {
|
|
req, _ := http.NewRequest("POST", setup.Server.URL+"/api/media-items", bytes.NewBuffer(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
resp, err := (&http.Client{}).Do(req)
|
|
require.NoError(t, err)
|
|
defer func(Body io.ReadCloser) {
|
|
_ = Body.Close()
|
|
}(resp.Body)
|
|
raw, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
return resp, raw
|
|
}
|
|
|
|
resp, raw := post(createPayload("Original Title"))
|
|
require.Equal(t, http.StatusCreated, resp.StatusCode, "first create should be 201")
|
|
var created map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(raw, &created))
|
|
originalID := created["id"].(string)
|
|
|
|
resp, raw = post(createPayload("Different Title"))
|
|
require.Equal(t, http.StatusOK, resp.StatusCode, "duplicate create should be 200, not a 201 lie")
|
|
|
|
var dup map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(raw, &dup))
|
|
assert.Equal(t, true, dup["duplicate"], "response must flag the duplicate")
|
|
assert.Equal(t, originalID, dup["item"].(map[string]interface{})["id"].(string),
|
|
"duplicate response carries the existing item")
|
|
assert.Equal(t, "Original Title", dup["item"].(map[string]interface{})["title"],
|
|
"the second create's payload must NOT overwrite the existing row")
|
|
}
|
|
|
|
// TestMediaItemLibraryRequirement tests that media items require a library
|
|
func TestMediaItemLibraryRequirement(t *testing.T) {
|
|
setup := setupTestServer(t)
|
|
|
|
token := setup.Token
|
|
|
|
t.Run("Create media-item without library should fail gracefully", func(t *testing.T) {
|
|
payload := map[string]interface{}{
|
|
"title": "Orphan Book",
|
|
"isbn": "9780123456789",
|
|
"file_path": "/test/path.epub",
|
|
"file_size": 1024,
|
|
"mime_type": "application/epub+zip",
|
|
}
|
|
|
|
body, _ := json.Marshal(payload)
|
|
req, _ := http.NewRequest("POST", setup.Server.URL+"/api/media-items", bytes.NewBuffer(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
defer func(Body io.ReadCloser) {
|
|
_ = Body.Close()
|
|
}(resp.Body)
|
|
|
|
// Should fail - library_id is required
|
|
assert.NotEqual(t, http.StatusCreated, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("Create media-item with existing library should succeed", func(t *testing.T) {
|
|
libID := createTestLibrary(t, setup.Server, token, "test-req-lib")
|
|
addFolderToLibrary(t, setup, libID, "/app/uploads")
|
|
|
|
payload := map[string]interface{}{
|
|
"title": "Valid Book",
|
|
"isbn": "978-0-306-40615-7",
|
|
"library_id": libID,
|
|
"file_path": "/test/path.epub",
|
|
"file_size": 1024,
|
|
"mime_type": "application/epub+zip",
|
|
}
|
|
|
|
body, _ := json.Marshal(payload)
|
|
req, _ := http.NewRequest("POST", setup.Server.URL+"/api/media-items", bytes.NewBuffer(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
defer func(Body io.ReadCloser) {
|
|
_ = Body.Close()
|
|
}(resp.Body)
|
|
|
|
assert.Equal(t, http.StatusCreated, resp.StatusCode)
|
|
|
|
var response map[string]interface{}
|
|
err = json.NewDecoder(resp.Body).Decode(&response)
|
|
require.NoError(t, err)
|
|
|
|
// VerifyISBN was normalized
|
|
assert.Equal(t, "9780306406157", response["isbn"])
|
|
assert.Equal(t, libID, response["library_id"])
|
|
})
|
|
}
|
|
|
|
// TestUpdateMediaItemISBN tests updating media-item ISBN
|
|
func TestUpdateMediaItemISBN(t *testing.T) {
|
|
setup := setupTestServer(t)
|
|
|
|
token := setup.Token
|
|
libID := createTestLibrary(t, setup.Server, token, "test-update-lib")
|
|
addFolderToLibrary(t, setup, libID, "/app/uploads")
|
|
|
|
// First create a media item
|
|
createPayload := map[string]interface{}{
|
|
"title": "Original Title",
|
|
"isbn": "978-0-596-00965-2",
|
|
"library_id": libID,
|
|
"file_path": "/test/path.epub",
|
|
"file_size": 1024,
|
|
"mime_type": "application/epub+zip",
|
|
}
|
|
|
|
body, _ := json.Marshal(createPayload)
|
|
req, _ := http.NewRequest("POST", setup.Server.URL+"/api/media-items", bytes.NewBuffer(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
|
|
var createResponse map[string]interface{}
|
|
err = json.NewDecoder(resp.Body).Decode(&createResponse)
|
|
require.NoError(t, err)
|
|
_ = resp.Body.Close()
|
|
|
|
mediaItemID := createResponse["id"].(string)
|
|
|
|
// Now update with new ISBN
|
|
t.Run("Update with invalid ISBN rejects", func(t *testing.T) {
|
|
updatePayload := map[string]interface{}{
|
|
"title": "Updated Title",
|
|
"isbn": "978-9876543210-9",
|
|
}
|
|
|
|
body, _ := json.Marshal(updatePayload)
|
|
req, _ := http.NewRequest("PUT", setup.Server.URL+"/api/media-items/"+mediaItemID, bytes.NewBuffer(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
defer func(Body io.ReadCloser) {
|
|
_ = Body.Close()
|
|
}(resp.Body)
|
|
|
|
assert.Equal(t, http.StatusUnprocessableEntity, resp.StatusCode)
|
|
})
|
|
}
|