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:
2026-02-11 10:37:38 -05:00
parent 61115bc8cd
commit 891209b4bd
10 changed files with 124 additions and 478 deletions
+16 -84
View File
@@ -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()