Remove the getJSONInt helper function and update all test assertions to expect float64 instead of int for JSON numeric fields, as Go's JSON decoder unmarshals all numbers to float64 by default. This simplifies the codebase by removing an unnecessary conversion helper and makes tests more accurate to the actual JSON format. Changes: - Remove getJSONInt function from book_matching_test.go - Update 5 assertions in book_matching_test.go to use float64 - Update 2 assertions in collections_bulk_test.go to use float64 - Update 2 assertions in media_bulk_test.go to use float64 - Add nil checks for optional numeric fields to prevent panics Affected tests: - TestBookMatchingBulkLink - TestBookMatchingAutoLink - TestCollectionsBulkOperations - TestMediaBulkOperations Note: Some test failures remain (API returning 400 instead of 200) but these are legitimate test issues unrelated to type assertions.
445 lines
13 KiB
Go
445 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) {
|
|
ts, _, _ := setupTestServer(t)
|
|
defer ts.Close()
|
|
|
|
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", ts.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) {
|
|
ts, db, _ := setupTestServer(t)
|
|
defer ts.Close()
|
|
|
|
token := loginTestUser(t, ts, db)
|
|
|
|
req := map[string]interface{}{
|
|
"operations": []map[string]interface{}{},
|
|
}
|
|
body, _ := json.Marshal(req)
|
|
|
|
httpReq, _ := http.NewRequest("POST", ts.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) {
|
|
ts, db, _ := setupTestServer(t)
|
|
defer ts.Close()
|
|
|
|
token := loginTestUser(t, ts, db)
|
|
bookID := createTestEbookID(t, ts, 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", ts.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, "success")
|
|
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) {
|
|
ts, db, _ := setupTestServer(t)
|
|
defer ts.Close()
|
|
|
|
token := loginTestUser(t, ts, db)
|
|
|
|
// Create a collection first
|
|
collectionReq := map[string]interface{}{
|
|
"name": "Test Collection",
|
|
"description": "A test collection",
|
|
}
|
|
collectionBody, _ := json.Marshal(collectionReq)
|
|
|
|
collectionHTTP, _ := http.NewRequest("POST", ts.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", ts.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) {
|
|
ts, db, _ := setupTestServer(t)
|
|
defer ts.Close()
|
|
|
|
token := loginTestUser(t, ts, db)
|
|
|
|
// Create a collection
|
|
collectionReq := map[string]interface{}{
|
|
"name": "Test Collection",
|
|
"description": "A test collection",
|
|
}
|
|
collectionBody, _ := json.Marshal(collectionReq)
|
|
|
|
collectionHTTP, _ := http.NewRequest("POST", ts.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 := createTestEbookID(t, ts, 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", ts.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, "success")
|
|
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) {
|
|
ts, db, _ := setupTestServer(t)
|
|
defer ts.Close()
|
|
|
|
token := loginTestUser(t, ts, db)
|
|
|
|
// Create a collection
|
|
collectionReq := map[string]interface{}{
|
|
"name": "Test Collection",
|
|
"description": "A test collection",
|
|
}
|
|
collectionBody, _ := json.Marshal(collectionReq)
|
|
|
|
collectionHTTP, _ := http.NewRequest("POST", ts.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 := createTestEbookID(t, ts, token)
|
|
bookID2 := createTestEbookID(t, ts, token)
|
|
bookID3 := createTestEbookID(t, ts, 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", ts.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["success"].(float64) > 0)
|
|
})
|
|
|
|
t.Run("BulkAddBooks_MultipleCollections", func(t *testing.T) {
|
|
ts, db, _ := setupTestServer(t)
|
|
defer ts.Close()
|
|
|
|
token := loginTestUser(t, ts, db)
|
|
|
|
// Create multiple collections
|
|
collectionReq := map[string]interface{}{
|
|
"name": "Test Collection 1",
|
|
"description": "First test collection",
|
|
}
|
|
collectionBody, _ := json.Marshal(collectionReq)
|
|
|
|
collectionHTTP, _ := http.NewRequest("POST", ts.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", ts.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 := createTestEbookID(t, ts, token)
|
|
bookID2 := createTestEbookID(t, ts, 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", ts.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) {
|
|
ts, db, _ := setupTestServer(t)
|
|
defer ts.Close()
|
|
|
|
token := loginTestUser(t, ts, db)
|
|
|
|
// Create a collection
|
|
collectionReq := map[string]interface{}{
|
|
"name": "Test Collection",
|
|
"description": "A test collection",
|
|
}
|
|
collectionBody, _ := json.Marshal(collectionReq)
|
|
|
|
collectionHTTP, _ := http.NewRequest("POST", ts.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 := createTestEbookID(t, ts, 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", ts.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", ts.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) {
|
|
ts, db, _ := setupTestServer(t)
|
|
defer ts.Close()
|
|
|
|
token := loginTestUser(t, ts, db)
|
|
|
|
// Send invalid JSON
|
|
httpReq, _ := http.NewRequest("POST", ts.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)
|
|
})
|
|
}
|