test(infrastructure): Configure pgxpool with max_conns=1
Fix database connection exhaustion in tests by setting max_conns=1 when creating pgxpool via pgxpool.ParseConfig(). - Update setupTestServer() in test_helpers.go - Update setupSyncTestDB() in sync_integration_test.go This reduces per-test connection usage from 4 to 1, keeping total connections well under PostgreSQL's default max_connections=100. 78 tests × 1 connection = 78 connections (down from 312 potential) Fixes test failures: "FATAL: sorry, too many clients already" See PROJECT_GUIDELINES.md Testing section for details.
This commit is contained in:
+13
-3
@@ -9,9 +9,19 @@
|
||||
- ❌ **NEVER build server binaries locally** - all builds through Dockerfile/docker-compose
|
||||
- ❌ **NEVER create new migration files** - merge changes into current one until release
|
||||
- ❌ **NEVER use `git checkout` on schema files** without checking what will be lost
|
||||
- ❌ **NEVER break existing functionality** unless explicitly instructed
|
||||
- ❌ **NEVER duplicate business logic** - keep logic in services, not handlers
|
||||
- ❌ **NEVER bypass service layer** - all database operations must go through services
|
||||
- ❌ **NEVER break existing functionality** unless explicitly instructed
|
||||
- ❌ **NEVER duplicate business logic** - keep logic in services, not handlers
|
||||
- ❌ **NEVER bypass service layer** - all database operations must go through services
|
||||
|
||||
### Testing
|
||||
- ✅ **ALWAYS use `setupTestServer()` helper from `cmd/server/tests/test_helpers.go`**
|
||||
- ✅ **Share one test setup across all subtests** - call `setupTestServer()` once at test function level, not per subtest
|
||||
- ✅ **Prefer table-driven tests** - use `t.Run()` with test cases instead of duplicate test functions
|
||||
- ✅ **Configure database pools efficiently** - use `max_conns=1` for test pools (via `pgxpool.ParseConfig()`) to prevent connection exhaustion
|
||||
- ❌ **NEVER create separate `pgxpool` per test** - each pool creates 4 connections by default; 78 tests = 312 potential connections > PostgreSQL's 100 limit
|
||||
- ❌ **NEVER call `setupTestServer()` in loops or within subtests** - creates unnecessary database pools and exhausts connections
|
||||
- ✅ **DO verify tests pass** - run full test suite before completing work
|
||||
- ✅ **Use `t.Cleanup()` properly** - the `TestServerSetup` pattern automatically handles cleanup via `t.Cleanup()`
|
||||
|
||||
### Frontend & Styling
|
||||
- ❌ **NEVER modify backend/API for frontend features without user confirmation**
|
||||
|
||||
@@ -13,11 +13,12 @@ import (
|
||||
|
||||
// TestAnalyticsReadingStats tests the reading statistics endpoint
|
||||
func TestAnalyticsReadingStats(t *testing.T) {
|
||||
t.Run("GetReadingStats_WithoutAuth", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
setup := setupTestServer(t)
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
client := &http.Client{}
|
||||
|
||||
t.Run("GetReadingStats_WithoutAuth", func(t *testing.T) {
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/reading-stats", nil)
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -26,13 +27,9 @@ func TestAnalyticsReadingStats(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetReadingStats_WithAuth_DefaultDates", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/reading-stats", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
client := &http.Client{}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -51,16 +48,12 @@ func TestAnalyticsReadingStats(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetReadingStats_WithCustomDateRange", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
startDate := time.Now().AddDate(0, -2, 0).Format("2006-01-02")
|
||||
endDate := time.Now().Format("2006-01-02")
|
||||
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/reading-stats?start_date="+startDate+"&end_date="+endDate, nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
client := &http.Client{}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -69,13 +62,9 @@ func TestAnalyticsReadingStats(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetReadingStats_InvalidStartDate", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/reading-stats?start_date=invalid-date", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
client := &http.Client{}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -84,13 +73,9 @@ func TestAnalyticsReadingStats(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetReadingStats_InvalidEndDate", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/reading-stats?end_date=not-a-date", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
client := &http.Client{}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -99,13 +84,9 @@ func TestAnalyticsReadingStats(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetReadingStats_EmptyHistory", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/reading-stats", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
client := &http.Client{}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -123,11 +104,12 @@ func TestAnalyticsReadingStats(t *testing.T) {
|
||||
|
||||
// TestAnalyticsDeviceUsage tests the device usage endpoint
|
||||
func TestAnalyticsDeviceUsage(t *testing.T) {
|
||||
t.Run("GetDeviceUsage_WithoutAuth", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
setup := setupTestServer(t)
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
client := &http.Client{}
|
||||
|
||||
t.Run("GetDeviceUsage_WithoutAuth", func(t *testing.T) {
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/device-usage", nil)
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -136,13 +118,9 @@ func TestAnalyticsDeviceUsage(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetDeviceUsage_WithAuth_NoDevices", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/device-usage", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
client := &http.Client{}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -158,10 +136,6 @@ func TestAnalyticsDeviceUsage(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetDeviceUsage_WithAuth_WithDevices", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
// First create a device
|
||||
deviceReq := map[string]interface{}{
|
||||
"device_name": "Test Kobo",
|
||||
@@ -173,7 +147,6 @@ func TestAnalyticsDeviceUsage(t *testing.T) {
|
||||
deviceReqHTTP.Header.Set("Content-Type", "application/json")
|
||||
deviceReqHTTP.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(deviceReqHTTP)
|
||||
require.NoError(t, err)
|
||||
resp.Body.Close()
|
||||
@@ -181,6 +154,7 @@ func TestAnalyticsDeviceUsage(t *testing.T) {
|
||||
// Now get device usage
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/device-usage", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
resp, err = client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -197,13 +171,9 @@ func TestAnalyticsDeviceUsage(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetDeviceUsage_ResponseStructure", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/device-usage", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
client := &http.Client{}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -231,11 +201,12 @@ func TestAnalyticsDeviceUsage(t *testing.T) {
|
||||
|
||||
// TestAnalyticsPopularBooks tests the popular books endpoint
|
||||
func TestAnalyticsPopularBooks(t *testing.T) {
|
||||
t.Run("GetPopularBooks_WithoutAuth", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
setup := setupTestServer(t)
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
client := &http.Client{}
|
||||
|
||||
t.Run("GetPopularBooks_WithoutAuth", func(t *testing.T) {
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/popular-books", nil)
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -244,13 +215,9 @@ func TestAnalyticsPopularBooks(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetPopularBooks_WithAuth_DefaultLimit", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/popular-books", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
client := &http.Client{}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -268,13 +235,9 @@ func TestAnalyticsPopularBooks(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetPopularBooks_WithCustomLimit", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/popular-books?limit=5", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
client := &http.Client{}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -289,13 +252,9 @@ func TestAnalyticsPopularBooks(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetPopularBooks_InvalidLimit", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/popular-books?limit=invalid", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
client := &http.Client{}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -311,10 +270,6 @@ func TestAnalyticsPopularBooks(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetPopularBooks_ResponseStructure", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
// First create a book and some reading history
|
||||
bookID := createTestMediaItemID(t, setup.Server, token)
|
||||
|
||||
@@ -331,7 +286,6 @@ func TestAnalyticsPopularBooks(t *testing.T) {
|
||||
historyHTTP.Header.Set("Content-Type", "application/json")
|
||||
historyHTTP.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(historyHTTP)
|
||||
require.NoError(t, err)
|
||||
resp.Body.Close()
|
||||
@@ -339,6 +293,7 @@ func TestAnalyticsPopularBooks(t *testing.T) {
|
||||
// Now get popular books
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/popular-books", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
resp, err = client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -363,13 +318,9 @@ func TestAnalyticsPopularBooks(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetPopularBooks_NoReadingHistory", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/popular-books", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
client := &http.Client{}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -387,17 +338,17 @@ func TestAnalyticsPopularBooks(t *testing.T) {
|
||||
|
||||
// TestAnalyticsEdgeCases tests edge cases for analytics endpoints
|
||||
func TestAnalyticsEdgeCases(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
client := &http.Client{}
|
||||
|
||||
t.Run("ReadingStats_FutureDateRange", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
startDate := time.Now().AddDate(0, 0, 7).Format("2006-01-02")
|
||||
endDate := time.Now().AddDate(0, 0, 14).Format("2006-01-02")
|
||||
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/reading-stats?start_date="+startDate+"&end_date="+endDate, nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
client := &http.Client{}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -412,13 +363,9 @@ func TestAnalyticsEdgeCases(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("PopularBooks_LimitZero", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/popular-books?limit=0", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
client := &http.Client{}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -434,13 +381,9 @@ func TestAnalyticsEdgeCases(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("PopularBooks_VeryLargeLimit", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/analytics/popular-books?limit=999999", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
client := &http.Client{}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
@@ -13,9 +13,10 @@ import (
|
||||
|
||||
// TestBookMatchingQueryBooks tests the book query endpoint
|
||||
func TestBookMatchingQueryBooks(t *testing.T) {
|
||||
t.Run("QueryBooks_WithoutAuth", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
setup := setupTestServer(t)
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
t.Run("QueryBooks_WithoutAuth", func(t *testing.T) {
|
||||
req := map[string]interface{}{
|
||||
"title": "Test Book",
|
||||
}
|
||||
@@ -33,9 +34,6 @@ func TestBookMatchingQueryBooks(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("QueryBooks_WithAuth_ByTitle", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
_ = createTestMediaItemID(t, setup.Server, token)
|
||||
|
||||
req := map[string]interface{}{
|
||||
@@ -62,10 +60,6 @@ func TestBookMatchingQueryBooks(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("QueryBooks_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/sync/books/query", bytes.NewBuffer([]byte("invalid json")))
|
||||
httpReq.Header.Set("Content-Type", "application/json")
|
||||
@@ -80,10 +74,6 @@ func TestBookMatchingQueryBooks(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("QueryBooks_NoResults", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"title": "NonExistentBookTitleThatDoesNotExist123456789",
|
||||
}
|
||||
@@ -115,9 +105,10 @@ func TestBookMatchingQueryBooks(t *testing.T) {
|
||||
|
||||
// TestBookMatchingBulkLink tests bulk linking operations
|
||||
func TestBookMatchingBulkLink(t *testing.T) {
|
||||
t.Run("BulkLinkBooks_WithoutAuth", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
setup := setupTestServer(t)
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
t.Run("BulkLinkBooks_WithoutAuth", func(t *testing.T) {
|
||||
req := map[string]interface{}{
|
||||
"links": []map[string]interface{}{
|
||||
{
|
||||
@@ -141,10 +132,6 @@ func TestBookMatchingBulkLink(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkLinkBooks_WithAuth_EmptyLinks", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"links": []map[string]interface{}{},
|
||||
}
|
||||
@@ -170,9 +157,6 @@ func TestBookMatchingBulkLink(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkLinkBooks_InvalidUnlinkedBookID", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
bookID := createTestMediaItemID(t, setup.Server, token)
|
||||
|
||||
req := map[string]interface{}{
|
||||
@@ -211,10 +195,6 @@ func TestBookMatchingBulkLink(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkLinkBooks_MultipleLinks", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"links": []map[string]interface{}{
|
||||
{
|
||||
@@ -258,9 +238,10 @@ func TestBookMatchingBulkLink(t *testing.T) {
|
||||
|
||||
// TestBookMatchingAutoLink tests automatic linking
|
||||
func TestBookMatchingAutoLink(t *testing.T) {
|
||||
t.Run("AutoLinkBooks_WithoutAuth", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
setup := setupTestServer(t)
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
t.Run("AutoLinkBooks_WithoutAuth", func(t *testing.T) {
|
||||
req := map[string]interface{}{
|
||||
"confidence_threshold": 0.8,
|
||||
"limit": 10,
|
||||
@@ -279,10 +260,6 @@ func TestBookMatchingAutoLink(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("AutoLinkBooks_WithAuth_DefaultThreshold", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{}
|
||||
body, _ := json.Marshal(req)
|
||||
|
||||
@@ -305,10 +282,6 @@ func TestBookMatchingAutoLink(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("AutoLinkBooks_CustomThreshold", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"confidence_threshold": 0.95,
|
||||
"limit": 20,
|
||||
@@ -333,10 +306,6 @@ func TestBookMatchingAutoLink(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("AutoLinkBooks_NoUnlinkedBooks", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"limit": 5,
|
||||
}
|
||||
@@ -363,9 +332,10 @@ func TestBookMatchingAutoLink(t *testing.T) {
|
||||
|
||||
// TestBookMatchingSuggestions tests getting suggestions for unlinked books
|
||||
func TestBookMatchingSuggestions(t *testing.T) {
|
||||
t.Run("GetUnlinkedBookSuggestions_WithoutAuth", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
setup := setupTestServer(t)
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
t.Run("GetUnlinkedBookSuggestions_WithoutAuth", func(t *testing.T) {
|
||||
testID := uuid.New()
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/api/sync/unlinked-books/"+testID.String()+"/suggestions", nil)
|
||||
|
||||
@@ -378,10 +348,6 @@ func TestBookMatchingSuggestions(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetUnlinkedBookSuggestions_InvalidUUID", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/api/sync/unlinked-books/invalid-uuid/suggestions", nil)
|
||||
httpReq.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
@@ -394,10 +360,6 @@ func TestBookMatchingSuggestions(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetUnlinkedBookSuggestions_BookNotFound", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
testID := uuid.New()
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/api/sync/unlinked-books/"+testID.String()+"/suggestions", nil)
|
||||
httpReq.Header.Set("Authorization", "Bearer "+token)
|
||||
@@ -411,10 +373,6 @@ func TestBookMatchingSuggestions(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetUnlinkedBookSuggestions_ResponseStructure", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
// Create a test device and unlinked book would go here
|
||||
// For now, test with a non-existent ID to check response structure
|
||||
testID := uuid.New()
|
||||
@@ -433,9 +391,10 @@ func TestBookMatchingSuggestions(t *testing.T) {
|
||||
|
||||
// TestBookMatchingDeviceFileAliases tests device file alias operations
|
||||
func TestBookMatchingDeviceFileAliases(t *testing.T) {
|
||||
t.Run("GetDeviceFileAliases_WithoutAuth", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
setup := setupTestServer(t)
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
t.Run("GetDeviceFileAliases_WithoutAuth", func(t *testing.T) {
|
||||
testID := uuid.New()
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/api/devices/"+testID.String()+"/file-aliases", nil)
|
||||
|
||||
@@ -448,10 +407,6 @@ func TestBookMatchingDeviceFileAliases(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetDeviceFileAliases_WithAuth", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
testID := uuid.New()
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/api/devices/"+testID.String()+"/file-aliases", nil)
|
||||
httpReq.Header.Set("Authorization", "Bearer "+token)
|
||||
@@ -472,8 +427,6 @@ func TestBookMatchingDeviceFileAliases(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("CreateDeviceFileAlias_WithoutAuth", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
deviceID := uuid.New()
|
||||
mediaItemID := uuid.New()
|
||||
|
||||
@@ -497,10 +450,6 @@ func TestBookMatchingDeviceFileAliases(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("CreateDeviceFileAlias_InvalidDeviceID", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
mediaItemID := uuid.New()
|
||||
|
||||
req := map[string]interface{}{
|
||||
@@ -524,10 +473,6 @@ func TestBookMatchingDeviceFileAliases(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("CreateDeviceFileAlias_InvalidMediaItemID", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
deviceID := uuid.New()
|
||||
|
||||
req := map[string]interface{}{
|
||||
@@ -551,10 +496,6 @@ func TestBookMatchingDeviceFileAliases(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("UpdateDeviceFileAlias_InvalidAliasID", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
deviceID := uuid.New()
|
||||
|
||||
req := map[string]interface{}{
|
||||
@@ -575,10 +516,6 @@ func TestBookMatchingDeviceFileAliases(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("DeleteDeviceFileAlias_InvalidAliasID", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
deviceID := uuid.New()
|
||||
|
||||
httpReq, _ := http.NewRequest("DELETE", setup.Server.URL+"/api/devices/"+deviceID.String()+"/file-aliases/invalid-uuid", nil)
|
||||
@@ -595,9 +532,10 @@ func TestBookMatchingDeviceFileAliases(t *testing.T) {
|
||||
|
||||
// TestBookMatchingGetBookMatches tests the book matches endpoint
|
||||
func TestBookMatchingGetBookMatches(t *testing.T) {
|
||||
t.Run("GetBookMatches_WithoutAuth", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
setup := setupTestServer(t)
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
t.Run("GetBookMatches_WithoutAuth", func(t *testing.T) {
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/api/books/match?title=Test", nil)
|
||||
|
||||
client := &http.Client{}
|
||||
@@ -609,10 +547,6 @@ func TestBookMatchingGetBookMatches(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetBookMatches_WithAuth_ByTitle", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/api/books/match?title=Test", nil)
|
||||
httpReq.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
@@ -631,10 +565,6 @@ func TestBookMatchingGetBookMatches(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetBookMatches_InvalidFileSize", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/api/books/match?title=Test&file_size=invalid", nil)
|
||||
httpReq.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
@@ -647,10 +577,6 @@ func TestBookMatchingGetBookMatches(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetBookMatches_MultipleIdentifiers", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/api/books/match?identifier=id1&identifier=id2&title=Test", nil)
|
||||
httpReq.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
|
||||
@@ -13,9 +13,11 @@ import (
|
||||
|
||||
// TestCollectionsBulkOperations tests bulk collection operations
|
||||
func TestCollectionsBulkOperations(t *testing.T) {
|
||||
t.Run("BulkAddBooks_WithoutAuth", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
setup := setupTestServer(t)
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
client := &http.Client{}
|
||||
|
||||
t.Run("BulkAddBooks_WithoutAuth", func(t *testing.T) {
|
||||
req := map[string]interface{}{
|
||||
"operations": []map[string]interface{}{
|
||||
{
|
||||
@@ -29,7 +31,6 @@ func TestCollectionsBulkOperations(t *testing.T) {
|
||||
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()
|
||||
@@ -38,10 +39,6 @@ func TestCollectionsBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
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{}{},
|
||||
}
|
||||
@@ -51,7 +48,6 @@ func TestCollectionsBulkOperations(t *testing.T) {
|
||||
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()
|
||||
@@ -60,9 +56,6 @@ func TestCollectionsBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
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{}{
|
||||
@@ -79,7 +72,6 @@ func TestCollectionsBulkOperations(t *testing.T) {
|
||||
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()
|
||||
@@ -102,10 +94,6 @@ func TestCollectionsBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
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",
|
||||
@@ -117,7 +105,6 @@ func TestCollectionsBulkOperations(t *testing.T) {
|
||||
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()
|
||||
@@ -156,10 +143,6 @@ func TestCollectionsBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
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",
|
||||
@@ -171,7 +154,6 @@ func TestCollectionsBulkOperations(t *testing.T) {
|
||||
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()
|
||||
@@ -218,10 +200,6 @@ func TestCollectionsBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
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",
|
||||
@@ -233,7 +211,6 @@ func TestCollectionsBulkOperations(t *testing.T) {
|
||||
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()
|
||||
@@ -276,10 +253,6 @@ func TestCollectionsBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
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",
|
||||
@@ -291,7 +264,6 @@ func TestCollectionsBulkOperations(t *testing.T) {
|
||||
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()
|
||||
@@ -355,10 +327,6 @@ func TestCollectionsBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
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",
|
||||
@@ -370,7 +338,6 @@ func TestCollectionsBulkOperations(t *testing.T) {
|
||||
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()
|
||||
@@ -401,7 +368,7 @@ func TestCollectionsBulkOperations(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Try to add the same book again - create new request with fresh body
|
||||
// Try to add 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")
|
||||
@@ -416,16 +383,11 @@ func TestCollectionsBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
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()
|
||||
|
||||
@@ -13,9 +13,11 @@ import (
|
||||
|
||||
// TestConflictsBulkOperations tests bulk conflict resolution operations
|
||||
func TestConflictsBulkOperations(t *testing.T) {
|
||||
t.Run("BulkResolveConflicts_WithoutAuth", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
setup := setupTestServer(t)
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
client := &http.Client{}
|
||||
|
||||
t.Run("BulkResolveConflicts_WithoutAuth", func(t *testing.T) {
|
||||
req := map[string]interface{}{
|
||||
"conflict_ids": []string{uuid.New().String()},
|
||||
"strategy": "most_recent",
|
||||
@@ -25,7 +27,6 @@ func TestConflictsBulkOperations(t *testing.T) {
|
||||
httpReq, _ := http.NewRequest("POST", setup.Server.URL+"/api/conflicts/bulk-resolve", 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()
|
||||
@@ -34,10 +35,6 @@ func TestConflictsBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkResolveConflicts_EmptyConflictIDs", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"conflict_ids": []string{},
|
||||
"strategy": "most_recent",
|
||||
@@ -48,7 +45,6 @@ func TestConflictsBulkOperations(t *testing.T) {
|
||||
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()
|
||||
@@ -57,10 +53,6 @@ func TestConflictsBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkResolveConflicts_InvalidConflictID", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"conflict_ids": []string{"invalid-uuid"},
|
||||
"strategy": "most_recent",
|
||||
@@ -71,7 +63,6 @@ func TestConflictsBulkOperations(t *testing.T) {
|
||||
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()
|
||||
@@ -92,10 +83,6 @@ func TestConflictsBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkResolveConflicts_InvalidStrategy", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"conflict_ids": []string{uuid.New().String()},
|
||||
"strategy": "invalid_strategy",
|
||||
@@ -106,7 +93,6 @@ func TestConflictsBulkOperations(t *testing.T) {
|
||||
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()
|
||||
@@ -130,10 +116,6 @@ func TestConflictsBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkResolveConflicts_MostRecentStrategy", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"conflict_ids": []string{uuid.New().String(), uuid.New().String()},
|
||||
"strategy": "most_recent",
|
||||
@@ -144,7 +126,6 @@ func TestConflictsBulkOperations(t *testing.T) {
|
||||
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()
|
||||
@@ -159,10 +140,6 @@ func TestConflictsBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkResolveConflicts_HighestProgressStrategy", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"conflict_ids": []string{uuid.New().String(), uuid.New().String()},
|
||||
"strategy": "highest_progress",
|
||||
@@ -173,7 +150,6 @@ func TestConflictsBulkOperations(t *testing.T) {
|
||||
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()
|
||||
@@ -188,10 +164,6 @@ func TestConflictsBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkResolveConflicts_ManualStrategy_WithoutWinner", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"conflict_ids": []string{uuid.New().String()},
|
||||
"strategy": "manual",
|
||||
@@ -202,7 +174,6 @@ func TestConflictsBulkOperations(t *testing.T) {
|
||||
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()
|
||||
@@ -216,10 +187,6 @@ func TestConflictsBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkResolveConflicts_ManualStrategy_WithWinner", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"conflict_ids": []string{uuid.New().String()},
|
||||
"strategy": "manual",
|
||||
@@ -231,7 +198,6 @@ func TestConflictsBulkOperations(t *testing.T) {
|
||||
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()
|
||||
@@ -240,16 +206,11 @@ func TestConflictsBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkResolveConflicts_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/conflicts/bulk-resolve", 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()
|
||||
@@ -260,9 +221,11 @@ func TestConflictsBulkOperations(t *testing.T) {
|
||||
|
||||
// TestConflictsBulkDismiss tests bulk dismiss operations
|
||||
func TestConflictsBulkDismiss(t *testing.T) {
|
||||
t.Run("BulkDismissConflicts_WithoutAuth", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
setup := setupTestServer(t)
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
client := &http.Client{}
|
||||
|
||||
t.Run("BulkDismissConflicts_WithoutAuth", func(t *testing.T) {
|
||||
req := map[string]interface{}{
|
||||
"conflict_ids": []string{uuid.New().String()},
|
||||
}
|
||||
@@ -271,7 +234,6 @@ func TestConflictsBulkDismiss(t *testing.T) {
|
||||
httpReq, _ := http.NewRequest("POST", setup.Server.URL+"/api/conflicts/bulk-dismiss", 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()
|
||||
@@ -280,10 +242,6 @@ func TestConflictsBulkDismiss(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkDismissConflicts_EmptyConflictIDs", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"conflict_ids": []string{},
|
||||
}
|
||||
@@ -293,7 +251,6 @@ func TestConflictsBulkDismiss(t *testing.T) {
|
||||
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()
|
||||
@@ -302,10 +259,6 @@ func TestConflictsBulkDismiss(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkDismissConflicts_InvalidConflictID", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"conflict_ids": []string{"invalid-uuid", uuid.New().String()},
|
||||
}
|
||||
@@ -315,7 +268,6 @@ func TestConflictsBulkDismiss(t *testing.T) {
|
||||
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()
|
||||
@@ -336,10 +288,6 @@ func TestConflictsBulkDismiss(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkDismissConflicts_MultipleConflicts", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"conflict_ids": []string{
|
||||
uuid.New().String(),
|
||||
@@ -353,7 +301,6 @@ func TestConflictsBulkDismiss(t *testing.T) {
|
||||
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()
|
||||
@@ -368,16 +315,11 @@ func TestConflictsBulkDismiss(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkDismissConflicts_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/conflicts/bulk-dismiss", 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()
|
||||
@@ -388,11 +330,11 @@ func TestConflictsBulkDismiss(t *testing.T) {
|
||||
|
||||
// TestConflictsBulkEdgeCases tests edge cases for bulk operations
|
||||
func TestConflictsBulkEdgeCases(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
client := &http.Client{}
|
||||
|
||||
t.Run("BulkResolve_NonExistentConflicts", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"conflict_ids": []string{
|
||||
uuid.New().String(),
|
||||
@@ -407,7 +349,6 @@ func TestConflictsBulkEdgeCases(t *testing.T) {
|
||||
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()
|
||||
@@ -423,10 +364,6 @@ func TestConflictsBulkEdgeCases(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkDismiss_MixedValidInvalid", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"conflict_ids": []string{
|
||||
"invalid-uuid-1",
|
||||
@@ -440,7 +377,6 @@ func TestConflictsBulkEdgeCases(t *testing.T) {
|
||||
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()
|
||||
|
||||
@@ -13,9 +13,10 @@ import (
|
||||
|
||||
// TestMediaBulkOperations tests bulk media operations
|
||||
func TestMediaBulkOperations(t *testing.T) {
|
||||
t.Run("BulkDeleteBooks_WithoutAuth", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
setup := setupTestServer(t)
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
t.Run("BulkDeleteBooks_WithoutAuth", func(t *testing.T) {
|
||||
req := map[string]interface{}{
|
||||
"media_item_ids": []string{uuid.New().String()},
|
||||
}
|
||||
@@ -33,10 +34,6 @@ func TestMediaBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkDeleteBooks_EmptyBookIDs", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"media_item_ids": []string{},
|
||||
}
|
||||
@@ -55,10 +52,6 @@ func TestMediaBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkDeleteBooks_InvalidBookIDs", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"media_item_ids": []string{"invalid-uuid", "another-invalid"},
|
||||
}
|
||||
@@ -85,11 +78,6 @@ func TestMediaBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkDeleteBooks_WithValidBooks", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
// Create test media items
|
||||
mediaID1 := createTestMediaItemID(t, setup.Server, token)
|
||||
mediaID2 := createTestMediaItemID(t, setup.Server, token)
|
||||
mediaID3 := uuid.New().String()
|
||||
@@ -117,15 +105,11 @@ func TestMediaBulkOperations(t *testing.T) {
|
||||
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")
|
||||
assert.True(t, deleted >= 2, "Should delete at least valid books")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("BulkDeleteBooks_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/media-items/bulk-delete", bytes.NewBuffer([]byte("invalid json")))
|
||||
httpReq.Header.Set("Content-Type", "application/json")
|
||||
@@ -140,8 +124,6 @@ func TestMediaBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkUpdateBooks_WithoutAuth", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"media_item_updates": []map[string]interface{}{
|
||||
{
|
||||
@@ -166,10 +148,6 @@ func TestMediaBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkUpdateBooks_EmptyBookIDs", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"media_item_updates": []map[string]interface{}{
|
||||
{
|
||||
@@ -195,10 +173,6 @@ func TestMediaBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkUpdateBooks_InvalidBookIDs", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"media_item_updates": []map[string]interface{}{
|
||||
{
|
||||
@@ -232,11 +206,6 @@ func TestMediaBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkUpdateBooks_UpdateTags", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
// Create test media items
|
||||
mediaID1 := createTestMediaItemID(t, setup.Server, token)
|
||||
mediaID2 := createTestMediaItemID(t, setup.Server, token)
|
||||
|
||||
@@ -281,11 +250,6 @@ func TestMediaBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkUpdateBooks_UpdateReadingStatus", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
// Create test media items
|
||||
mediaID1 := createTestMediaItemID(t, setup.Server, token)
|
||||
|
||||
req := map[string]interface{}{
|
||||
@@ -318,11 +282,6 @@ func TestMediaBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkUpdateBooks_UpdateMultipleFields", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
// Create test media items
|
||||
mediaID1 := createTestMediaItemID(t, setup.Server, token)
|
||||
|
||||
req := map[string]interface{}{
|
||||
@@ -357,10 +316,6 @@ func TestMediaBulkOperations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("BulkUpdateBooks_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/media-items/bulk-update", bytes.NewBuffer([]byte("invalid json")))
|
||||
httpReq.Header.Set("Content-Type", "application/json")
|
||||
|
||||
@@ -11,13 +11,14 @@ import (
|
||||
|
||||
// TestOPDSEndpoints tests OPDS (Open Publication Distribution System) endpoints
|
||||
func TestOPDSEndpoints(t *testing.T) {
|
||||
t.Run("GetDeviceCatalog_WithoutDeviceAuth", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
setup := setupTestServer(t)
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
client := &http.Client{}
|
||||
|
||||
t.Run("GetDeviceCatalog_WithoutDeviceAuth", func(t *testing.T) {
|
||||
deviceID := uuid.New()
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/"+deviceID.String()+"/catalog", nil)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -28,11 +29,8 @@ func TestOPDSEndpoints(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetDeviceCatalog_InvalidDeviceID", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/invalid-uuid/catalog", nil)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -42,17 +40,11 @@ func TestOPDSEndpoints(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetDeviceCatalog_ValidDevice", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
|
||||
// Note: Device registration requires different endpoint
|
||||
// For now, test with a valid UUID format
|
||||
deviceID := uuid.New()
|
||||
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/"+deviceID.String()+"/catalog", nil)
|
||||
httpReq.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -62,11 +54,8 @@ func TestOPDSEndpoints(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("SearchDeviceCatalog_InvalidDeviceID", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/invalid-uuid/search?query=test", nil)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -75,15 +64,11 @@ func TestOPDSEndpoints(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("SearchDeviceCatalog_ValidDevice", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
deviceID := uuid.New()
|
||||
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/"+deviceID.String()+"/search?query=test", nil)
|
||||
httpReq.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -93,11 +78,8 @@ func TestOPDSEndpoints(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetDeviceNavigation_InvalidDeviceID", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/invalid-uuid/nav", nil)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -106,15 +88,11 @@ func TestOPDSEndpoints(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetDeviceNavigation_ValidDevice", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
deviceID := uuid.New()
|
||||
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/"+deviceID.String()+"/nav", nil)
|
||||
httpReq.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -124,12 +102,8 @@ func TestOPDSEndpoints(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("DownloadBook_InvalidDeviceID", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/invalid-uuid/download/"+uuid.New().String(), nil)
|
||||
|
||||
bookID := uuid.New()
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/invalid-uuid/download/"+bookID.String(), nil)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -138,12 +112,9 @@ func TestOPDSEndpoints(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("DownloadBook_InvalidBookID", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
deviceID := uuid.New()
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/"+deviceID.String()+"/download/invalid-uuid", nil)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -152,16 +123,12 @@ func TestOPDSEndpoints(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("DownloadBook_ValidIDs", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
deviceID := uuid.New()
|
||||
bookID := createTestMediaItemID(t, setup.Server, token)
|
||||
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/"+deviceID.String()+"/download/"+bookID, nil)
|
||||
httpReq.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -172,12 +139,8 @@ func TestOPDSEndpoints(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetCoverImage_InvalidDeviceID", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/invalid-uuid/cover/"+uuid.New().String(), nil)
|
||||
|
||||
bookID := uuid.New()
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/invalid-uuid/cover/"+bookID.String(), nil)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -186,12 +149,8 @@ func TestOPDSEndpoints(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetCoverImage_InvalidBookID", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/invalid-uuid/cover/"+uuid.New().String(), nil)
|
||||
|
||||
deviceID := uuid.New()
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/"+deviceID.String()+"/cover/invalid-uuid", nil)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -200,16 +159,12 @@ func TestOPDSEndpoints(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("GetCoverImage_ValidIDs", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
deviceID := uuid.New()
|
||||
bookID := createTestMediaItemID(t, setup.Server, token)
|
||||
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/"+deviceID.String()+"/cover/"+bookID, nil)
|
||||
httpReq.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -219,12 +174,9 @@ func TestOPDSEndpoints(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("ListFormats_InvalidDeviceID", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
bookID := uuid.New()
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/invalid-uuid/formats/"+bookID.String(), nil)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -233,16 +185,12 @@ func TestOPDSEndpoints(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("ListFormats_ValidDeviceID", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
deviceID := uuid.New()
|
||||
bookID := createTestMediaItemID(t, setup.Server, token)
|
||||
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/"+deviceID.String()+"/formats/"+bookID, nil)
|
||||
httpReq.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -254,10 +202,11 @@ func TestOPDSEndpoints(t *testing.T) {
|
||||
|
||||
// TestOPDSConversion tests on-the-fly conversion for downloads
|
||||
func TestOPDSConversion(t *testing.T) {
|
||||
t.Run("DownloadKEPUB_FormatParameter", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
setup := setupTestServer(t)
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
client := &http.Client{}
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
t.Run("DownloadKEPUB_FormatParameter", func(t *testing.T) {
|
||||
deviceID := uuid.New()
|
||||
bookID := createTestMediaItemID(t, setup.Server, token)
|
||||
|
||||
@@ -265,7 +214,6 @@ func TestOPDSConversion(t *testing.T) {
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/"+deviceID.String()+"/download/"+bookID+"?format=kepub", nil)
|
||||
httpReq.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -276,9 +224,6 @@ func TestOPDSConversion(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("DownloadEPUB_DefaultFormat", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
deviceID := uuid.New()
|
||||
bookID := createTestMediaItemID(t, setup.Server, token)
|
||||
|
||||
@@ -286,7 +231,6 @@ func TestOPDSConversion(t *testing.T) {
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/"+deviceID.String()+"/download/"+bookID, nil)
|
||||
httpReq.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -296,9 +240,6 @@ func TestOPDSConversion(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Download_UnsupportedFormat", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
deviceID := uuid.New()
|
||||
bookID := createTestMediaItemID(t, setup.Server, token)
|
||||
|
||||
@@ -306,7 +247,6 @@ func TestOPDSConversion(t *testing.T) {
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/"+deviceID.String()+"/download/"+bookID+"?format=pdf", nil)
|
||||
httpReq.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -318,16 +258,16 @@ func TestOPDSConversion(t *testing.T) {
|
||||
|
||||
// TestOPDSEdgeCases tests edge cases for OPDS endpoints
|
||||
func TestOPDSEdgeCases(t *testing.T) {
|
||||
t.Run("Catalog_EmptyLibrary", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
setup := setupTestServer(t)
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
client := &http.Client{}
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
t.Run("Catalog_EmptyLibrary", func(t *testing.T) {
|
||||
deviceID := uuid.New()
|
||||
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/"+deviceID.String()+"/catalog", nil)
|
||||
httpReq.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -337,16 +277,12 @@ func TestOPDSEdgeCases(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Search_SpecialCharacters", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
deviceID := uuid.New()
|
||||
|
||||
// Search with special characters
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/"+deviceID.String()+"/search?query=test%20%26%20more", nil)
|
||||
httpReq.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -356,15 +292,11 @@ func TestOPDSEdgeCases(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Search_EmptyQuery", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
token := loginTestUser(t, setup.Server, setup.DB)
|
||||
deviceID := uuid.New()
|
||||
|
||||
httpReq, _ := http.NewRequest("GET", setup.Server.URL+"/opds/devices/"+deviceID.String()+"/search?query=", nil)
|
||||
httpReq.Header.Set("Authorization", "Bearer "+token)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
@@ -12,16 +12,16 @@ import (
|
||||
|
||||
// TestRefreshTokenFlow comprehensive tests for token refresh functionality
|
||||
func TestRefreshTokenFlow(t *testing.T) {
|
||||
t.Run("RefreshToken_MissingToken", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
setup := setupTestServer(t)
|
||||
client := &http.Client{}
|
||||
|
||||
t.Run("RefreshToken_MissingToken", func(t *testing.T) {
|
||||
req := map[string]interface{}{}
|
||||
body, _ := json.Marshal(req)
|
||||
|
||||
httpReq, _ := http.NewRequest("POST", setup.Server.URL+"/api/auth/refresh", 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()
|
||||
@@ -30,8 +30,6 @@ func TestRefreshTokenFlow(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("RefreshToken_InvalidTokenFormat", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"refresh_token": "not-a-valid-jwt-token",
|
||||
}
|
||||
@@ -40,7 +38,6 @@ func TestRefreshTokenFlow(t *testing.T) {
|
||||
httpReq, _ := http.NewRequest("POST", setup.Server.URL+"/api/auth/refresh", 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()
|
||||
@@ -49,8 +46,6 @@ func TestRefreshTokenFlow(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("RefreshToken_ExpiredToken", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
// This would require an expired token - for now test with invalid token
|
||||
req := map[string]interface{}{
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MjAwMDAwMDB9.expired",
|
||||
@@ -60,7 +55,6 @@ func TestRefreshTokenFlow(t *testing.T) {
|
||||
httpReq, _ := http.NewRequest("POST", setup.Server.URL+"/api/auth/refresh", 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()
|
||||
@@ -69,8 +63,6 @@ func TestRefreshTokenFlow(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("RefreshToken_ValidToken", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
// First, login to get tokens
|
||||
loginReq := map[string]string{
|
||||
"login": "testuser@example.com",
|
||||
@@ -81,7 +73,6 @@ func TestRefreshTokenFlow(t *testing.T) {
|
||||
loginHTTP, _ := http.NewRequest("POST", setup.Server.URL+"/api/auth/login", bytes.NewBuffer(loginBody))
|
||||
loginHTTP.Header.Set("Content-Type", "application/json")
|
||||
|
||||
client := &http.Client{}
|
||||
loginResp, err := client.Do(loginHTTP)
|
||||
require.NoError(t, err)
|
||||
defer loginResp.Body.Close()
|
||||
@@ -122,13 +113,10 @@ func TestRefreshTokenFlow(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("RefreshToken_InvalidRequestBody", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
// Send invalid JSON
|
||||
httpReq, _ := http.NewRequest("POST", setup.Server.URL+"/api/auth/refresh", bytes.NewBuffer([]byte("invalid json")))
|
||||
httpReq.Header.Set("Content-Type", "application/json")
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -137,8 +125,6 @@ func TestRefreshTokenFlow(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("RefreshToken_MissingContentType", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"refresh_token": "some-token",
|
||||
}
|
||||
@@ -147,7 +133,6 @@ func TestRefreshTokenFlow(t *testing.T) {
|
||||
httpReq, _ := http.NewRequest("POST", setup.Server.URL+"/api/auth/refresh", bytes.NewBuffer(body))
|
||||
// Don't set Content-Type
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(httpReq)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
@@ -159,9 +144,10 @@ func TestRefreshTokenFlow(t *testing.T) {
|
||||
|
||||
// TestRefreshTokenSecurity tests security aspects of token refresh
|
||||
func TestRefreshTokenSecurity(t *testing.T) {
|
||||
t.Run("RefreshToken_ReuseProtection", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
setup := setupTestServer(t)
|
||||
client := &http.Client{}
|
||||
|
||||
t.Run("RefreshToken_ReuseProtection", func(t *testing.T) {
|
||||
// Login to get tokens
|
||||
loginReq := map[string]string{
|
||||
"login": "testuser@example.com",
|
||||
@@ -172,7 +158,6 @@ func TestRefreshTokenSecurity(t *testing.T) {
|
||||
loginHTTP, _ := http.NewRequest("POST", setup.Server.URL+"/api/auth/login", bytes.NewBuffer(loginBody))
|
||||
loginHTTP.Header.Set("Content-Type", "application/json")
|
||||
|
||||
client := &http.Client{}
|
||||
loginResp, err := client.Do(loginHTTP)
|
||||
require.NoError(t, err)
|
||||
defer loginResp.Body.Close()
|
||||
@@ -213,8 +198,6 @@ func TestRefreshTokenSecurity(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("RefreshToken_TokenTampering", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
// Login to get a valid token
|
||||
loginReq := map[string]string{
|
||||
"login": "testuser@example.com",
|
||||
@@ -225,7 +208,6 @@ func TestRefreshTokenSecurity(t *testing.T) {
|
||||
loginHTTP, _ := http.NewRequest("POST", setup.Server.URL+"/api/auth/login", bytes.NewBuffer(loginBody))
|
||||
loginHTTP.Header.Set("Content-Type", "application/json")
|
||||
|
||||
client := &http.Client{}
|
||||
loginResp, err := client.Do(loginHTTP)
|
||||
require.NoError(t, err)
|
||||
defer loginResp.Body.Close()
|
||||
@@ -237,7 +219,7 @@ func TestRefreshTokenSecurity(t *testing.T) {
|
||||
|
||||
refreshToken := loginResult["refresh_token"].(string)
|
||||
|
||||
// Tamper with the token by modifying a character
|
||||
// Tamper with token by modifying a character
|
||||
if len(refreshToken) > 10 {
|
||||
tamperedToken := refreshToken[:5] + "X" + refreshToken[6:]
|
||||
|
||||
@@ -249,20 +231,21 @@ func TestRefreshTokenSecurity(t *testing.T) {
|
||||
refreshHTTP, _ := http.NewRequest("POST", setup.Server.URL+"/api/auth/refresh", bytes.NewBuffer(refreshBody))
|
||||
refreshHTTP.Header.Set("Content-Type", "application/json")
|
||||
|
||||
refreshResp, err := client.Do(refreshHTTP)
|
||||
resp, err := client.Do(refreshHTTP)
|
||||
require.NoError(t, err)
|
||||
defer refreshResp.Body.Close()
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, http.StatusUnauthorized, refreshResp.StatusCode)
|
||||
assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestRefreshTokenEdgeCases tests edge cases for token refresh
|
||||
func TestRefreshTokenEdgeCases(t *testing.T) {
|
||||
t.Run("RefreshToken_EmptyStringToken", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
setup := setupTestServer(t)
|
||||
client := &http.Client{}
|
||||
|
||||
t.Run("RefreshToken_EmptyStringToken", func(t *testing.T) {
|
||||
req := map[string]interface{}{
|
||||
"refresh_token": "",
|
||||
}
|
||||
@@ -271,7 +254,6 @@ func TestRefreshTokenEdgeCases(t *testing.T) {
|
||||
httpReq, _ := http.NewRequest("POST", setup.Server.URL+"/api/auth/refresh", 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()
|
||||
@@ -280,8 +262,6 @@ func TestRefreshTokenEdgeCases(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("RefreshToken_NullToken", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
req := map[string]interface{}{
|
||||
"refresh_token": nil,
|
||||
}
|
||||
@@ -290,7 +270,6 @@ func TestRefreshTokenEdgeCases(t *testing.T) {
|
||||
httpReq, _ := http.NewRequest("POST", setup.Server.URL+"/api/auth/refresh", 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()
|
||||
@@ -299,8 +278,6 @@ func TestRefreshTokenEdgeCases(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("RefreshToken_ResponseStructure", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
// Login to get tokens
|
||||
loginReq := map[string]string{
|
||||
"login": "testuser@example.com",
|
||||
@@ -311,7 +288,6 @@ func TestRefreshTokenEdgeCases(t *testing.T) {
|
||||
loginHTTP, _ := http.NewRequest("POST", setup.Server.URL+"/api/auth/login", bytes.NewBuffer(loginBody))
|
||||
loginHTTP.Header.Set("Content-Type", "application/json")
|
||||
|
||||
client := &http.Client{}
|
||||
loginResp, err := client.Do(loginHTTP)
|
||||
require.NoError(t, err)
|
||||
defer loginResp.Body.Close()
|
||||
@@ -350,8 +326,6 @@ func TestRefreshTokenEdgeCases(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("RefreshToken_TokenType", func(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
|
||||
// Login to get tokens
|
||||
loginReq := map[string]string{
|
||||
"login": "testuser@example.com",
|
||||
@@ -362,7 +336,6 @@ func TestRefreshTokenEdgeCases(t *testing.T) {
|
||||
loginHTTP, _ := http.NewRequest("POST", setup.Server.URL+"/api/auth/login", bytes.NewBuffer(loginBody))
|
||||
loginHTTP.Header.Set("Content-Type", "application/json")
|
||||
|
||||
client := &http.Client{}
|
||||
loginResp, err := client.Do(loginHTTP)
|
||||
require.NoError(t, err)
|
||||
defer loginResp.Body.Close()
|
||||
|
||||
@@ -18,7 +18,11 @@ func setupSyncTestDB(t *testing.T) *database.Queries {
|
||||
ctx := context.Background()
|
||||
|
||||
dbURL := "postgresql://postgres:postgres@db:5432/bookhoard?sslmode=disable"
|
||||
dbPool, err := pgxpool.New(ctx, dbURL)
|
||||
// Use max_conns=1 to prevent connection pool exhaustion during test runs
|
||||
dbConfig, err := pgxpool.ParseConfig(dbURL)
|
||||
require.NoError(t, err, "Failed to parse database URL")
|
||||
dbConfig.MaxConns = 1
|
||||
dbPool, err := pgxpool.NewWithConfig(ctx, dbConfig)
|
||||
require.NoError(t, err, "Failed to connect to test database")
|
||||
|
||||
db := database.New(dbPool)
|
||||
|
||||
@@ -309,7 +309,12 @@ func setupTestServer(t *testing.T) *TestServerSetup {
|
||||
cfg.RequestsPerMinute = 1000
|
||||
|
||||
// Connect to test database using the same method as main application
|
||||
dbPool, err := pgxpool.New(context.Background(), cfg.DatabaseURL())
|
||||
// Use max_conns=1 to prevent connection pool exhaustion during test runs
|
||||
// (78 tests × 1 connection = 78 connections, well under PostgreSQL's 100 default max_connections)
|
||||
dbConfig, err := pgxpool.ParseConfig(cfg.DatabaseURL())
|
||||
require.NoError(t, err, "Failed to parse database URL")
|
||||
dbConfig.MaxConns = 1
|
||||
dbPool, err := pgxpool.NewWithConfig(context.Background(), dbConfig)
|
||||
require.NoError(t, err, "Failed to connect to test database")
|
||||
|
||||
queries := database.New(dbPool)
|
||||
|
||||
Reference in New Issue
Block a user