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
+18 -92
View File
@@ -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)