Files
bookhoard/cmd/server/tests/collections_bulk_test.go
T
john-okeefe 778d611cab test: update collections bulk tests for 'added' field rename
Update test assertions in TestCollectionsBulkOperations to expect
'added' instead of 'success' in the response, matching the handler
change made in the bulk operations rename.

Fixes:
- BulkAddBooks_InvalidCollectionID: assert 'added' field exists
- BulkAddBooks_SingleOperation: assert 'added' field exists
2026-02-10 20:51:29 -05:00

436 lines
13 KiB
Go

package main
import (
"bytes"
"encoding/json"
"net/http"
"testing"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// TestCollectionsBulkOperations tests bulk collection operations
func TestCollectionsBulkOperations(t *testing.T) {
t.Run("BulkAddBooks_WithoutAuth", func(t *testing.T) {
setup := setupTestServer(t)
req := map[string]interface{}{
"operations": []map[string]interface{}{
{
"collection_id": uuid.New().String(),
"book_ids": []string{uuid.New().String()},
},
},
}
body, _ := json.Marshal(req)
httpReq, _ := http.NewRequest("POST", setup.Server.URL+"/api/collections/bulk-add-books", bytes.NewBuffer(body))
httpReq.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(httpReq)
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
})
t.Run("BulkAddBooks_EmptyOperations", func(t *testing.T) {
setup := setupTestServer(t)
token := loginTestUser(t, setup.Server, setup.DB)
req := map[string]interface{}{
"operations": []map[string]interface{}{},
}
body, _ := json.Marshal(req)
httpReq, _ := http.NewRequest("POST", setup.Server.URL+"/api/collections/bulk-add-books", bytes.NewBuffer(body))
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("Authorization", "Bearer "+token)
client := &http.Client{}
resp, err := client.Do(httpReq)
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
})
t.Run("BulkAddBooks_InvalidCollectionID", func(t *testing.T) {
setup := setupTestServer(t)
token := loginTestUser(t, setup.Server, setup.DB)
bookID := createTestMediaItemID(t, setup.Server, token)
req := map[string]interface{}{
"operations": []map[string]interface{}{
{
"collection_id": "invalid-uuid",
"book_ids": []string{bookID},
},
},
}
body, _ := json.Marshal(req)
httpReq, _ := http.NewRequest("POST", setup.Server.URL+"/api/collections/bulk-add-books", bytes.NewBuffer(body))
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("Authorization", "Bearer "+token)
client := &http.Client{}
resp, err := client.Do(httpReq)
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusOK, resp.StatusCode)
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
assert.Contains(t, result, "results")
assert.Contains(t, result, "total")
assert.Contains(t, result, "added")
assert.Contains(t, result, "failed")
results := result["results"].([]interface{})
assert.True(t, len(results) > 0)
firstResult := results[0].(map[string]interface{})
assert.Equal(t, "error", firstResult["status"])
})
t.Run("BulkAddBooks_InvalidBookID", func(t *testing.T) {
setup := setupTestServer(t)
token := loginTestUser(t, setup.Server, setup.DB)
// Create a collection first
collectionReq := map[string]interface{}{
"name": "Test Collection",
"description": "A test collection",
}
collectionBody, _ := json.Marshal(collectionReq)
collectionHTTP, _ := http.NewRequest("POST", setup.Server.URL+"/api/collections", bytes.NewBuffer(collectionBody))
collectionHTTP.Header.Set("Content-Type", "application/json")
collectionHTTP.Header.Set("Authorization", "Bearer "+token)
client := &http.Client{}
resp, err := client.Do(collectionHTTP)
require.NoError(t, err)
defer resp.Body.Close()
var collectionResult map[string]interface{}
json.NewDecoder(resp.Body).Decode(&collectionResult)
collectionID := collectionResult["id"].(string)
// Now try to add invalid book IDs
addReq := map[string]interface{}{
"operations": []map[string]interface{}{
{
"collection_id": collectionID,
"book_ids": []string{"invalid-uuid"},
},
},
}
addBody, _ := json.Marshal(addReq)
addHTTP, _ := http.NewRequest("POST", setup.Server.URL+"/api/collections/bulk-add-books", bytes.NewBuffer(addBody))
addHTTP.Header.Set("Content-Type", "application/json")
addHTTP.Header.Set("Authorization", "Bearer "+token)
resp, err = client.Do(addHTTP)
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusOK, resp.StatusCode)
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
results := result["results"].([]interface{})
firstResult := results[0].(map[string]interface{})
assert.Equal(t, "error", firstResult["status"])
})
t.Run("BulkAddBooks_SingleOperation", func(t *testing.T) {
setup := setupTestServer(t)
token := loginTestUser(t, setup.Server, setup.DB)
// Create a collection
collectionReq := map[string]interface{}{
"name": "Test Collection",
"description": "A test collection",
}
collectionBody, _ := json.Marshal(collectionReq)
collectionHTTP, _ := http.NewRequest("POST", setup.Server.URL+"/api/collections", bytes.NewBuffer(collectionBody))
collectionHTTP.Header.Set("Content-Type", "application/json")
collectionHTTP.Header.Set("Authorization", "Bearer "+token)
client := &http.Client{}
resp, err := client.Do(collectionHTTP)
require.NoError(t, err)
defer resp.Body.Close()
var collectionResult map[string]interface{}
json.NewDecoder(resp.Body).Decode(&collectionResult)
collectionID := collectionResult["id"].(string)
// Create a book
bookID := createTestMediaItemID(t, setup.Server, token)
// Add book to collection
addReq := map[string]interface{}{
"operations": []map[string]interface{}{
{
"collection_id": collectionID,
"book_ids": []string{bookID},
},
},
}
addBody, _ := json.Marshal(addReq)
addHTTP, _ := http.NewRequest("POST", setup.Server.URL+"/api/collections/bulk-add-books", bytes.NewBuffer(addBody))
addHTTP.Header.Set("Content-Type", "application/json")
addHTTP.Header.Set("Authorization", "Bearer "+token)
resp, err = client.Do(addHTTP)
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusOK, resp.StatusCode)
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
assert.Contains(t, result, "results")
assert.Contains(t, result, "total")
assert.Contains(t, result, "added")
assert.Contains(t, result, "failed")
results := result["results"].([]interface{})
firstResult := results[0].(map[string]interface{})
assert.Equal(t, "success", firstResult["status"])
})
t.Run("BulkAddBooks_MultipleBooksSingleCollection", func(t *testing.T) {
setup := setupTestServer(t)
token := loginTestUser(t, setup.Server, setup.DB)
// Create a collection
collectionReq := map[string]interface{}{
"name": "Test Collection",
"description": "A test collection",
}
collectionBody, _ := json.Marshal(collectionReq)
collectionHTTP, _ := http.NewRequest("POST", setup.Server.URL+"/api/collections", bytes.NewBuffer(collectionBody))
collectionHTTP.Header.Set("Content-Type", "application/json")
collectionHTTP.Header.Set("Authorization", "Bearer "+token)
client := &http.Client{}
resp, err := client.Do(collectionHTTP)
require.NoError(t, err)
defer resp.Body.Close()
var collectionResult map[string]interface{}
json.NewDecoder(resp.Body).Decode(&collectionResult)
collectionID := collectionResult["id"].(string)
// Create multiple books
bookID1 := createTestMediaItemID(t, setup.Server, token)
bookID2 := createTestMediaItemID(t, setup.Server, token)
bookID3 := createTestMediaItemID(t, setup.Server, token)
// Add all books to collection
addReq := map[string]interface{}{
"operations": []map[string]interface{}{
{
"collection_id": collectionID,
"book_ids": []string{bookID1, bookID2, bookID3},
},
},
}
addBody, _ := json.Marshal(addReq)
addHTTP, _ := http.NewRequest("POST", setup.Server.URL+"/api/collections/bulk-add-books", bytes.NewBuffer(addBody))
addHTTP.Header.Set("Content-Type", "application/json")
addHTTP.Header.Set("Authorization", "Bearer "+token)
resp, err = client.Do(addHTTP)
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusOK, resp.StatusCode)
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
assert.Equal(t, 3.0, result["total"])
assert.True(t, result["added"].(float64) > 0)
})
t.Run("BulkAddBooks_MultipleCollections", func(t *testing.T) {
setup := setupTestServer(t)
token := loginTestUser(t, setup.Server, setup.DB)
// Create multiple collections
collectionReq := map[string]interface{}{
"name": "Test Collection 1",
"description": "First test collection",
}
collectionBody, _ := json.Marshal(collectionReq)
collectionHTTP, _ := http.NewRequest("POST", setup.Server.URL+"/api/collections", bytes.NewBuffer(collectionBody))
collectionHTTP.Header.Set("Content-Type", "application/json")
collectionHTTP.Header.Set("Authorization", "Bearer "+token)
client := &http.Client{}
resp, err := client.Do(collectionHTTP)
require.NoError(t, err)
defer resp.Body.Close()
var collectionResult1 map[string]interface{}
json.NewDecoder(resp.Body).Decode(&collectionResult1)
collectionID1 := collectionResult1["id"].(string)
collectionReq2 := map[string]interface{}{
"name": "Test Collection 2",
"description": "Second test collection",
}
collectionBody2, _ := json.Marshal(collectionReq2)
collectionHTTP2, _ := http.NewRequest("POST", setup.Server.URL+"/api/collections", bytes.NewBuffer(collectionBody2))
collectionHTTP2.Header.Set("Content-Type", "application/json")
collectionHTTP2.Header.Set("Authorization", "Bearer "+token)
resp, err = client.Do(collectionHTTP2)
require.NoError(t, err)
defer resp.Body.Close()
var collectionResult2 map[string]interface{}
json.NewDecoder(resp.Body).Decode(&collectionResult2)
collectionID2 := collectionResult2["id"].(string)
// Create books
bookID1 := createTestMediaItemID(t, setup.Server, token)
bookID2 := createTestMediaItemID(t, setup.Server, token)
// Add books to multiple collections
addReq := map[string]interface{}{
"operations": []map[string]interface{}{
{
"collection_id": collectionID1,
"book_ids": []string{bookID1},
},
{
"collection_id": collectionID2,
"book_ids": []string{bookID1, bookID2},
},
},
}
addBody, _ := json.Marshal(addReq)
addHTTP, _ := http.NewRequest("POST", setup.Server.URL+"/api/collections/bulk-add-books", bytes.NewBuffer(addBody))
addHTTP.Header.Set("Content-Type", "application/json")
addHTTP.Header.Set("Authorization", "Bearer "+token)
resp, err = client.Do(addHTTP)
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusOK, resp.StatusCode)
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
assert.Contains(t, result, "results")
assert.Equal(t, 3.0, result["total"])
})
t.Run("BulkAddBooks_DuplicateBooks", func(t *testing.T) {
setup := setupTestServer(t)
token := loginTestUser(t, setup.Server, setup.DB)
// Create a collection
collectionReq := map[string]interface{}{
"name": "Test Collection",
"description": "A test collection",
}
collectionBody, _ := json.Marshal(collectionReq)
collectionHTTP, _ := http.NewRequest("POST", setup.Server.URL+"/api/collections", bytes.NewBuffer(collectionBody))
collectionHTTP.Header.Set("Content-Type", "application/json")
collectionHTTP.Header.Set("Authorization", "Bearer "+token)
client := &http.Client{}
resp, err := client.Do(collectionHTTP)
require.NoError(t, err)
defer resp.Body.Close()
var collectionResult map[string]interface{}
json.NewDecoder(resp.Body).Decode(&collectionResult)
collectionID := collectionResult["id"].(string)
// Create a book
bookID := createTestMediaItemID(t, setup.Server, token)
// Add book to collection
addReq := map[string]interface{}{
"operations": []map[string]interface{}{
{
"collection_id": collectionID,
"book_ids": []string{bookID},
},
},
}
addBody, _ := json.Marshal(addReq)
addHTTP, _ := http.NewRequest("POST", setup.Server.URL+"/api/collections/bulk-add-books", bytes.NewBuffer(addBody))
addHTTP.Header.Set("Content-Type", "application/json")
addHTTP.Header.Set("Authorization", "Bearer "+token)
resp, err = client.Do(addHTTP)
require.NoError(t, err)
defer resp.Body.Close()
// Try to add the same book again - create new request with fresh body
addBody2, _ := json.Marshal(addReq)
addHTTP2, _ := http.NewRequest("POST", setup.Server.URL+"/api/collections/bulk-add-books", bytes.NewBuffer(addBody2))
addHTTP2.Header.Set("Content-Type", "application/json")
addHTTP2.Header.Set("Authorization", "Bearer "+token)
resp2, err := client.Do(addHTTP2)
require.NoError(t, err)
defer resp2.Body.Close()
// Should handle duplicate gracefully (either succeed or return error)
assert.Equal(t, http.StatusOK, resp2.StatusCode)
})
t.Run("BulkAddBooks_InvalidRequestBody", func(t *testing.T) {
setup := setupTestServer(t)
token := loginTestUser(t, setup.Server, setup.DB)
// Send invalid JSON
httpReq, _ := http.NewRequest("POST", setup.Server.URL+"/api/collections/bulk-add-books", bytes.NewBuffer([]byte("invalid json")))
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("Authorization", "Bearer "+token)
client := &http.Client{}
resp, err := client.Do(httpReq)
require.NoError(t, err)
defer resp.Body.Close()
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
})
}