Problem: Tests were calling `defer setup.Close()` which was interfering with the library cleanup added in the previous commit. The execution order was: 1. setupTestServer() registers t.Cleanup() with library deletion code 2. Test calls defer setup.Close() 3. Test finishes: - defer setup.Close() runs FIRST → closes DB pool - t.Cleanup() runs SECOND → tries to delete libraries but DB is closed! This prevented "Job Status Test Library" and other test libraries from being cleaned up, leaving residual data in the database after tests. Root Cause: The setupTestServer() function already handles cleanup via t.Cleanup(), which calls setup.Close() at the end. The explicit defer calls were redundant and caused the database pool to close before library cleanup could execute. Solution: Removed all 17 occurrences of `defer setup.Close()` from test files: - worker_test.go: 4 tests - jobs_test.go: 7 tests - scan_settings_integration_test.go: 3 tests - library_browse_test.go: 1 test - goroutine_leak_test.go: 1 test - fsnotify_integration_test.go: 1 test Now setupTestServer()'s t.Cleanup() function properly: 1. Deletes "test" libraries (while DB is still connected) 2. Then calls setup.Close() to close connections This ensures all test libraries are cleaned up, leaving a clean database after `make test-integration` completes. Files changed: - cmd/server/tests/worker_test.go: Removed 4 defer calls - cmd/server/tests/jobs_test.go: Removed 7 defer calls - cmd/server/tests/scan_settings_integration_test.go: Removed 3 defer calls - cmd/server/tests/library_browse_test.go: Removed 1 defer call - cmd/server/tests/goroutine_leak_test.go: Removed 1 defer call - cmd/server/tests/fsnotify_integration_test.go: Removed 1 defer call
183 lines
5.7 KiB
Go
183 lines
5.7 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestScanSettings_GetSettings(t *testing.T) {
|
|
setup := setupTestServer(t)
|
|
|
|
t.Run("Get settings as admin", func(t *testing.T) {
|
|
token := setup.Token
|
|
|
|
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/libraries/scan-settings", nil)
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
|
|
|
var response map[string]interface{}
|
|
json.NewDecoder(resp.Body).Decode(&response)
|
|
resp.Body.Close()
|
|
|
|
assert.Contains(t, response, "scan_poll_interval_seconds")
|
|
assert.Contains(t, response, "auto_scan_enabled")
|
|
// Validate scan_poll_interval_seconds is present and valid (don't hardcode value)
|
|
interval, ok := response["scan_poll_interval_seconds"].(float64)
|
|
require.True(t, ok, "scan_poll_interval_seconds must be a number")
|
|
assert.Greater(t, interval, float64(0), "scan_poll_interval_seconds must be positive")
|
|
// Validate auto_scan_enabled is present and a boolean
|
|
autoScan, ok := response["auto_scan_enabled"].(bool)
|
|
require.True(t, ok, "auto_scan_enabled must be a boolean")
|
|
assert.NotNil(t, autoScan, "auto_scan_enabled must not be nil")
|
|
})
|
|
}
|
|
|
|
func TestScanSettings_UpdateSettings(t *testing.T) {
|
|
setup := setupTestServer(t)
|
|
|
|
t.Run("Update scan_poll_interval_seconds", func(t *testing.T) {
|
|
token := setup.Token
|
|
|
|
updateReq := map[string]interface{}{
|
|
"scan_poll_interval_seconds": 45,
|
|
"auto_scan_enabled": true,
|
|
}
|
|
body, _ := json.Marshal(updateReq)
|
|
|
|
req, _ := http.NewRequest("PUT", setup.Server.URL+"/api/libraries/scan-settings", bytes.NewBuffer(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
|
|
|
var response map[string]interface{}
|
|
json.NewDecoder(resp.Body).Decode(&response)
|
|
resp.Body.Close()
|
|
|
|
assert.Equal(t, float64(45), response["scan_poll_interval_seconds"])
|
|
assert.Equal(t, true, response["auto_scan_enabled"])
|
|
|
|
getReq, _ := http.NewRequest("GET", setup.Server.URL+"/api/libraries/scan-settings", nil)
|
|
getReq.Header.Set("Authorization", "Bearer "+token)
|
|
getResp, _ := client.Do(getReq)
|
|
|
|
var getResponse map[string]interface{}
|
|
json.NewDecoder(getResp.Body).Decode(&getResponse)
|
|
getResp.Body.Close()
|
|
|
|
assert.Equal(t, float64(45), getResponse["scan_poll_interval_seconds"])
|
|
})
|
|
|
|
t.Run("Update auto_scan_enabled to false", func(t *testing.T) {
|
|
token := setup.Token
|
|
|
|
updateReq := map[string]interface{}{
|
|
"scan_poll_interval_seconds": 30,
|
|
"auto_scan_enabled": false,
|
|
}
|
|
body, _ := json.Marshal(updateReq)
|
|
|
|
req, _ := http.NewRequest("PUT", setup.Server.URL+"/api/libraries/scan-settings", bytes.NewBuffer(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
|
|
|
var response map[string]interface{}
|
|
json.NewDecoder(resp.Body).Decode(&response)
|
|
resp.Body.Close()
|
|
|
|
assert.Equal(t, false, response["auto_scan_enabled"])
|
|
})
|
|
|
|
t.Run("Validation rejects values below minimum", func(t *testing.T) {
|
|
token := setup.Token
|
|
|
|
updateReq := map[string]interface{}{
|
|
"scan_poll_interval_seconds": 0,
|
|
"auto_scan_enabled": true,
|
|
}
|
|
body, _ := json.Marshal(updateReq)
|
|
|
|
req, _ := http.NewRequest("PUT", setup.Server.URL+"/api/libraries/scan-settings", bytes.NewBuffer(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("Validation rejects values above maximum", func(t *testing.T) {
|
|
token := setup.Token
|
|
|
|
updateReq := map[string]interface{}{
|
|
"scan_poll_interval_seconds": 4000,
|
|
"auto_scan_enabled": true,
|
|
}
|
|
body, _ := json.Marshal(updateReq)
|
|
|
|
req, _ := http.NewRequest("PUT", setup.Server.URL+"/api/libraries/scan-settings", bytes.NewBuffer(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
|
})
|
|
}
|
|
|
|
func TestScanSettings_RequireAdmin(t *testing.T) {
|
|
setup := setupTestServer(t)
|
|
|
|
t.Run("Get settings without auth returns 401", func(t *testing.T) {
|
|
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/libraries/scan-settings", nil)
|
|
client := &http.Client{}
|
|
resp, _ := client.Do(req)
|
|
assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("Get settings as non-admin returns 403", func(t *testing.T) {
|
|
token := setup.RegularToken
|
|
|
|
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/libraries/scan-settings", nil)
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
resp, _ := client.Do(req)
|
|
assert.Equal(t, http.StatusForbidden, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("Update settings without auth returns 401", func(t *testing.T) {
|
|
updateReq := map[string]interface{}{
|
|
"scan_poll_interval_seconds": 30,
|
|
"auto_scan_enabled": true,
|
|
}
|
|
body, _ := json.Marshal(updateReq)
|
|
|
|
req, _ := http.NewRequest("PUT", setup.Server.URL+"/api/libraries/scan-settings", bytes.NewBuffer(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
client := &http.Client{}
|
|
resp, _ := client.Do(req)
|
|
assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
|
|
})
|
|
}
|