Files
bookhoard/cmd/server/tests/media_bulk_test.go
T
john-okeefe 98f2913eb5 refactor(tests): remove getJSONInt helper, use float64 for JSON numeric values
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.
2026-02-07 21:55:48 -05:00

359 lines
9.9 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"
)
// TestMediaBulkOperations tests bulk media operations
func TestMediaBulkOperations(t *testing.T) {
t.Run("BulkDeleteBooks_WithoutAuth", func(t *testing.T) {
ts, _, _ := setupTestServer(t)
defer ts.Close()
req := map[string]interface{}{
"book_ids": []string{uuid.New().String()},
}
body, _ := json.Marshal(req)
httpReq, _ := http.NewRequest("POST", ts.URL+"/api/books/bulk-delete", 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("BulkDeleteBooks_EmptyBookIDs", func(t *testing.T) {
ts, db, _ := setupTestServer(t)
defer ts.Close()
token := loginTestUser(t, ts, db)
req := map[string]interface{}{
"book_ids": []string{},
}
body, _ := json.Marshal(req)
httpReq, _ := http.NewRequest("POST", ts.URL+"/api/books/bulk-delete", 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("BulkDeleteBooks_InvalidBookIDs", func(t *testing.T) {
ts, db, _ := setupTestServer(t)
defer ts.Close()
token := loginTestUser(t, ts, db)
req := map[string]interface{}{
"book_ids": []string{"invalid-uuid", "another-invalid"},
}
body, _ := json.Marshal(req)
httpReq, _ := http.NewRequest("POST", ts.URL+"/api/books/bulk-delete", 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, "deleted")
assert.Contains(t, result, "failed")
})
t.Run("BulkDeleteBooks_WithValidBooks", func(t *testing.T) {
ts, db, _ := setupTestServer(t)
defer ts.Close()
token := loginTestUser(t, ts, db)
// Create test books
bookID1 := createTestEbookID(t, ts, token)
bookID2 := createTestEbookID(t, ts, token)
bookID3 := uuid.New().String()
req := map[string]interface{}{
"book_ids": []string{bookID1, bookID2, bookID3},
}
body, _ := json.Marshal(req)
httpReq, _ := http.NewRequest("POST", ts.URL+"/api/books/bulk-delete", 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.Equal(t, 3.0, result["total"])
// Check that deleted field exists and has at least 2 (the valid books)
if deleted, ok := result["deleted"].(float64); ok {
assert.True(t, deleted >= 2, "Should delete at least the valid books")
}
})
t.Run("BulkDeleteBooks_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/books/bulk-delete", 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)
})
t.Run("BulkUpdateBooks_WithoutAuth", func(t *testing.T) {
ts, _, _ := setupTestServer(t)
defer ts.Close()
req := map[string]interface{}{
"book_ids": []string{uuid.New().String()},
"updates": map[string]interface{}{
"tags": []string{"test"},
},
}
body, _ := json.Marshal(req)
httpReq, _ := http.NewRequest("POST", ts.URL+"/api/books/bulk-update", 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("BulkUpdateBooks_EmptyBookIDs", func(t *testing.T) {
ts, db, _ := setupTestServer(t)
defer ts.Close()
token := loginTestUser(t, ts, db)
req := map[string]interface{}{
"book_ids": []string{},
"updates": map[string]interface{}{
"tags": []string{"test"},
},
}
body, _ := json.Marshal(req)
httpReq, _ := http.NewRequest("POST", ts.URL+"/api/books/bulk-update", 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("BulkUpdateBooks_InvalidBookIDs", func(t *testing.T) {
ts, db, _ := setupTestServer(t)
defer ts.Close()
token := loginTestUser(t, ts, db)
req := map[string]interface{}{
"book_ids": []string{"invalid-uuid"},
"updates": map[string]interface{}{
"tags": []string{"fiction", "test"},
},
}
body, _ := json.Marshal(req)
httpReq, _ := http.NewRequest("POST", ts.URL+"/api/books/bulk-update", 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, "updated")
assert.Contains(t, result, "failed")
})
t.Run("BulkUpdateBooks_UpdateTags", func(t *testing.T) {
ts, db, _ := setupTestServer(t)
defer ts.Close()
token := loginTestUser(t, ts, db)
// Create test books
bookID1 := createTestEbookID(t, ts, token)
bookID2 := createTestEbookID(t, ts, token)
req := map[string]interface{}{
"book_ids": []string{bookID1, bookID2},
"updates": map[string]interface{}{
"tags": []string{"fiction", "science-fiction", "test"},
},
}
body, _ := json.Marshal(req)
httpReq, _ := http.NewRequest("POST", ts.URL+"/api/books/bulk-update", 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.Equal(t, 2.0, result["total"])
// Check that updated field exists and has at least 1
if updated, ok := result["updated"].(float64); ok {
assert.True(t, updated > 0, "Should update at least one book")
}
})
t.Run("BulkUpdateBooks_UpdateReadingStatus", func(t *testing.T) {
ts, db, _ := setupTestServer(t)
defer ts.Close()
token := loginTestUser(t, ts, db)
// Create test books
bookID1 := createTestEbookID(t, ts, token)
req := map[string]interface{}{
"book_ids": []string{bookID1},
"updates": map[string]interface{}{
"reading_status": "reading",
},
}
body, _ := json.Marshal(req)
httpReq, _ := http.NewRequest("POST", ts.URL+"/api/books/bulk-update", 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")
})
t.Run("BulkUpdateBooks_UpdateMultipleFields", func(t *testing.T) {
ts, db, _ := setupTestServer(t)
defer ts.Close()
token := loginTestUser(t, ts, db)
// Create test books
bookID1 := createTestEbookID(t, ts, token)
req := map[string]interface{}{
"book_ids": []string{bookID1},
"updates": map[string]interface{}{
"tags": []string{"test", "bulk-update"},
"reading_status": "to-read",
"rating": 4,
},
}
body, _ := json.Marshal(req)
httpReq, _ := http.NewRequest("POST", ts.URL+"/api/books/bulk-update", 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")
})
t.Run("BulkUpdateBooks_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/books/bulk-update", 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)
})
}