Files
bookhoard/cmd/server/tests/search_unified_test.go
T
john-okeefe a6700f73e0 fix(tests): handle all Close() and Decode() errors across integration tests
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.
2026-04-21 20:33:05 -04:00

107 lines
3.8 KiB
Go

package main
import (
"bytes"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestUnifiedSearch(t *testing.T) {
setup := setupDeviceTest(t)
defer setup.Server.Close()
libraryID := setup.CreateLibrary(t, "Test Search Library", "ebooks")
_ = setup.CreateDevice(t, "Test Search Device", "koreader", "search-test-123")
client := &http.Client{}
// Add folder to library (required before adding media items)
folderReq := map[string]interface{}{
"folder_path": "/app/uploads",
}
folderBody, _ := json.Marshal(folderReq)
folderHTTP, _ := http.NewRequest("POST", setup.Server.URL+"/api/libraries/"+libraryID+"/folders", bytes.NewBuffer(folderBody))
folderHTTP.Header.Set("Content-Type", "application/json")
folderHTTP.Header.Set("Authorization", "Bearer "+setup.UserToken)
folderResp, err := client.Do(folderHTTP)
require.NoError(t, err)
_ = folderResp.Body.Close()
require.Equal(t, http.StatusCreated, folderResp.StatusCode)
// Helper to create book with fields
createBook := func(title, author, genre string, year int, hasCover bool) {
bookReq := map[string]interface{}{
"library_id": libraryID,
"title": title,
"author": author,
"genre": genre,
"copyright_year": year,
"file_path": "/tmp/test.epub",
"file_size": 1024,
"mime_type": "application/epub+zip",
}
if hasCover {
bookReq["cover_image_path"] = "/tmp/cover.jpg"
}
body, _ := json.Marshal(bookReq)
req, _ := http.NewRequest("POST", setup.Server.URL+"/api/media-items", bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+setup.UserToken)
resp, err := client.Do(req)
require.NoError(t, err)
defer func(Body io.ReadCloser) {
_ = Body.Close()
}(resp.Body)
require.Equal(t, http.StatusCreated, resp.StatusCode)
}
// Create test books with various fields for filtering
createBook("Foundation and Empire", "asimov", "scifi", 1951, true)
createBook("The Martian", "weir", "scifi", 2010, true)
createBook("I, Robot", "asimov", "fiction", 1950, false)
t.Run("Fuzzy author filter", func(t *testing.T) {
req := httptest.NewRequest("GET", "/api/media-items/search?library_id="+libraryID+"&q=%22Foundation%20and%20Empire%22", nil)
req.Header.Set("Authorization", "Bearer "+setup.UserToken)
rec := httptest.NewRecorder()
setup.Server.Config.Handler.ServeHTTP(rec, req)
assert.Equal(t, http.StatusOK, rec.Code, "Should exact match quoted query")
})
t.Run("Combined search + filters", func(t *testing.T) {
req := httptest.NewRequest("GET", "/api/media-items/search?library_id="+libraryID+"&q=foundation&author_filter=asimov", nil)
req.Header.Set("Authorization", "Bearer "+setup.UserToken)
rec := httptest.NewRecorder()
setup.Server.Config.Handler.ServeHTTP(rec, req)
assert.Equal(t, http.StatusOK, rec.Code, "Should combine search and filters")
})
t.Run("Boolean filter (exact)", func(t *testing.T) {
req := httptest.NewRequest("GET", "/api/media-items/search?library_id="+libraryID+"&has_cover=true", nil)
req.Header.Set("Authorization", "Bearer "+setup.UserToken)
rec := httptest.NewRecorder()
setup.Server.Config.Handler.ServeHTTP(rec, req)
assert.Equal(t, http.StatusOK, rec.Code, "Should filter by has_cover")
})
t.Run("Missing library_id", func(t *testing.T) {
req := httptest.NewRequest("GET", "/api/media-items/search?q=test", nil)
req.Header.Set("Authorization", "Bearer "+setup.UserToken)
rec := httptest.NewRecorder()
setup.Server.Config.Handler.ServeHTTP(rec, req)
// library_id is now optional - searches all libraries when omitted
// Returns 404 when no results match the search query
assert.Equal(t, http.StatusNotFound, rec.Code, "Should return 404 when no results found")
})
}