Replace all unhandled resp.Body.Close() calls throughout the test suite:
- Deferred calls: replace 'defer VAR.Body.Close()' with a closure that explicitly
discards the error via 'defer func(Body io.ReadCloser) { _ = Body.Close() }(VAR.Body)'
- Immediate calls: replace 'VAR.Body.Close()' with '_ = VAR.Body.Close()'
Replace all unhandled json.NewDecoder(VAR.Body).Decode(&x) calls with error capture
and require.NoError assertion. Files using httptest.ResponseRecorder (collections_preview,
processing_issues) use 'err :=' declaration; suite-style tests (scanner_integration,
dashboard_integration) use s.T() instead of t.
129 lines
4.4 KiB
Go
129 lines
4.4 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestFSNotify_BulkFileDetection(t *testing.T) {
|
|
setup := setupTestServer(t)
|
|
t.Run("Detects multiple files added simultaneously", func(t *testing.T) {
|
|
token := setup.Token
|
|
tmpDir := t.TempDir()
|
|
// Create library
|
|
createLibReq := map[string]interface{}{
|
|
"name": "bulk-test-library",
|
|
"type": "ebooks",
|
|
}
|
|
libBody, _ := json.Marshal(createLibReq)
|
|
libReq, _ := http.NewRequest("POST", setup.Server.URL+"/api/libraries", bytes.NewBuffer(libBody))
|
|
libReq.Header.Set("Content-Type", "application/json")
|
|
libReq.Header.Set("Authorization", "Bearer "+token)
|
|
client := &http.Client{}
|
|
libResp, err := client.Do(libReq)
|
|
require.NoError(t, err)
|
|
defer func(Body io.ReadCloser) {
|
|
_ = Body.Close()
|
|
}(libResp.Body)
|
|
require.Equal(t, http.StatusCreated, libResp.StatusCode)
|
|
var libResult map[string]interface{}
|
|
err = json.NewDecoder(libResp.Body).Decode(&libResult)
|
|
require.NoError(t, err)
|
|
libraryID := libResult["id"].(string)
|
|
// Add folder to library
|
|
folderURL := fmt.Sprintf("%s/api/libraries/%s/folders", setup.Server.URL, libraryID)
|
|
folderReq := map[string]interface{}{
|
|
"folder_path": tmpDir,
|
|
}
|
|
folderBody, _ := json.Marshal(folderReq)
|
|
folderHTTPReq, _ := http.NewRequest("POST", folderURL, bytes.NewBuffer(folderBody))
|
|
folderHTTPReq.Header.Set("Content-Type", "application/json")
|
|
folderHTTPReq.Header.Set("Authorization", "Bearer "+token)
|
|
folderResp, err := client.Do(folderHTTPReq)
|
|
require.NoError(t, err)
|
|
defer func(Body io.ReadCloser) {
|
|
_ = Body.Close()
|
|
}(folderResp.Body)
|
|
require.Equal(t, http.StatusCreated, folderResp.StatusCode, "Folder should be added to library")
|
|
// Create 20 test files simultaneously
|
|
for i := 0; i < 20; i++ {
|
|
fileName := filepath.Join(tmpDir, fmt.Sprintf("book%d.epub", i))
|
|
err := os.WriteFile(fileName, []byte(fmt.Sprintf("test %d", i)), 0644)
|
|
require.NoError(t, err)
|
|
}
|
|
// Trigger library scan
|
|
scanURL := fmt.Sprintf("%s/api/libraries/%s/scan", setup.Server.URL, libraryID)
|
|
scanHTTPReq, _ := http.NewRequest("POST", scanURL, nil)
|
|
scanHTTPReq.Header.Set("Authorization", "Bearer "+token)
|
|
scanResp, err := client.Do(scanHTTPReq)
|
|
require.NoError(t, err)
|
|
defer func(Body io.ReadCloser) {
|
|
_ = Body.Close()
|
|
}(scanResp.Body)
|
|
require.Equal(t, http.StatusAccepted, scanResp.StatusCode, "Scan should be accepted")
|
|
var scanResponse map[string]interface{}
|
|
err = json.NewDecoder(scanResp.Body).Decode(&scanResponse)
|
|
require.NoError(t, err)
|
|
jobID, ok := scanResponse["job_id"].(string)
|
|
require.True(t, ok, "job_id should be string")
|
|
require.NotEmpty(t, jobID, "job_id should not be empty")
|
|
// Wait for scan job to complete
|
|
time.Sleep(3 * time.Second)
|
|
for i := 0; i < 30; i++ {
|
|
if i > 0 {
|
|
time.Sleep(1 * time.Second)
|
|
}
|
|
statusURL := fmt.Sprintf("%s/api/scanner/status/%s", setup.Server.URL, jobID)
|
|
statusReq, _ := http.NewRequest("GET", statusURL, nil)
|
|
statusReq.Header.Set("Authorization", "Bearer "+token)
|
|
statusResp, err := client.Do(statusReq)
|
|
require.NoError(t, err)
|
|
|
|
if statusResp.StatusCode == http.StatusNotFound {
|
|
_ = statusResp.Body.Close()
|
|
break // Job completed
|
|
}
|
|
|
|
var status map[string]interface{}
|
|
err = json.NewDecoder(statusResp.Body).Decode(&status)
|
|
require.NoError(t, err)
|
|
_ = statusResp.Body.Close()
|
|
|
|
if status["status"] == "completed" || status["status"] == "failed" {
|
|
_ = statusResp.Body.Close()
|
|
break
|
|
}
|
|
}
|
|
// Check items
|
|
req, _ := http.NewRequest("GET", setup.Server.URL+"/api/libraries/"+libraryID+"/media-items", nil)
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
itemsResp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
defer func(Body io.ReadCloser) {
|
|
_ = Body.Close()
|
|
}(itemsResp.Body)
|
|
var itemsResult map[string]interface{}
|
|
err = json.NewDecoder(itemsResp.Body).Decode(&itemsResult)
|
|
require.NoError(t, err)
|
|
items, ok := itemsResult["data"].([]interface{})
|
|
if !ok || items == nil {
|
|
items = []interface{}{} // Handle nil or wrong type
|
|
}
|
|
assert.GreaterOrEqual(t, len(items), 20, "Should detect all 20 files")
|
|
// Cleanup
|
|
deleteReq, _ := http.NewRequest("DELETE", setup.Server.URL+"/api/libraries/"+libraryID, nil)
|
|
deleteReq.Header.Set("Authorization", "Bearer "+token)
|
|
client.Do(deleteReq)
|
|
})
|
|
}
|