- Update ListMediaItems calls to include required Limit and Offset parameters - Change Enqueue() to EnqueueJob() to match updated worker API - Add error assertions for job enqueue operations with descriptive messages - Ensure all database queries use proper pagination parameters This ensures tests properly validate error conditions and use the latest worker service API.
319 lines
8.9 KiB
Go
319 lines
8.9 KiB
Go
package main
|
|
|
|
import (
|
|
"bookhoard/internal/database"
|
|
"bookhoard/internal/services"
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestWorker_DirectoryScanJob(t *testing.T) {
|
|
setup := setupTestServer(t)
|
|
defer setup.Close()
|
|
|
|
token := setup.Token
|
|
|
|
// Create library
|
|
createLibReq := map[string]interface{}{
|
|
"name": "Worker Test Library",
|
|
"description": "Test library for worker",
|
|
"type": "ebooks",
|
|
}
|
|
createLibURL := setup.Server.URL + "/api/libraries"
|
|
createLibReqHTTP, _ := http.NewRequest("POST", createLibURL, bytes.NewBuffer(jsonMarshal(createLibReq)))
|
|
createLibReqHTTP.Header.Set("Content-Type", "application/json")
|
|
createLibReqHTTP.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
createLibResp, err := client.Do(createLibReqHTTP)
|
|
require.NoError(t, err)
|
|
require.Equal(t, http.StatusCreated, createLibResp.StatusCode)
|
|
|
|
var createLibResponse map[string]interface{}
|
|
json.NewDecoder(createLibResp.Body).Decode(&createLibResponse)
|
|
createLibResp.Body.Close()
|
|
|
|
libraryID, ok := createLibResponse["id"].(string)
|
|
require.True(t, ok)
|
|
require.NotEmpty(t, libraryID)
|
|
|
|
// Create a temporary directory for testing
|
|
tmpDir := t.TempDir()
|
|
|
|
// Add folder to library
|
|
folderURL := fmt.Sprintf("%s/api/libraries/%s/folders", setup.Server.URL, libraryID)
|
|
folderReq := map[string]interface{}{
|
|
"folder_path": tmpDir,
|
|
}
|
|
req, _ := http.NewRequest("POST", folderURL, bytes.NewBuffer(jsonMarshal(folderReq)))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
resp.Body.Close()
|
|
require.Equal(t, http.StatusCreated, resp.StatusCode)
|
|
|
|
// Create test files in the directory
|
|
for i := 0; i < 3; i++ {
|
|
filePath := filepath.Join(tmpDir, fmt.Sprintf("book%d.epub", i))
|
|
err := os.WriteFile(filePath, []byte(fmt.Sprintf("test content %d", i)), 0644)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// Submit directory scan job through WorkerInstance
|
|
job := &services.Job{
|
|
ID: uuid.New().String(),
|
|
Type: services.JobTypeDirectoryScan,
|
|
Params: map[string]interface{}{
|
|
"directory": tmpDir,
|
|
"db": setup.DB,
|
|
},
|
|
Status: services.JobStatusPending,
|
|
}
|
|
|
|
// Use EnqueueJob which returns errors
|
|
err = services.WorkerInstance.EnqueueJob(job)
|
|
require.NoError(t, err, "Failed to enqueue job")
|
|
// Poll for job completion
|
|
timeout := time.Now().Add(10 * time.Second)
|
|
for time.Now().Before(timeout) {
|
|
if status, exists := services.WorkerInstance.GetJobStatus(job.ID); exists {
|
|
if status.Status == services.JobStatusCompleted || status.Status == services.JobStatusFailed {
|
|
break
|
|
}
|
|
}
|
|
time.Sleep(100 * time.Millisecond)
|
|
}
|
|
|
|
// Debug: Check job status after polling
|
|
if finalStatus, exists := services.WorkerInstance.GetJobStatus(job.ID); exists {
|
|
t.Logf("Job %s final status: %s, error: %s", job.ID, finalStatus.Status, finalStatus.Error)
|
|
} else {
|
|
t.Logf("Job %s not found in results", job.ID)
|
|
}
|
|
|
|
// Check that items were created in database
|
|
ctx := context.Background()
|
|
items, err := setup.DB.ListMediaItems(ctx, database.ListMediaItemsParams{
|
|
Limit: 1000,
|
|
Offset: 0,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Should have at least 3 items (our test files)
|
|
greaterOrEqual := func(a, b int) bool {
|
|
return a >= b
|
|
}
|
|
assert.True(t, greaterOrEqual(len(items), 3), fmt.Sprintf("Expected at least 3 items, got %d", len(items)))
|
|
}
|
|
|
|
func TestWorker_SetFoldersJob(t *testing.T) {
|
|
setup := setupTestServer(t)
|
|
defer setup.Close()
|
|
|
|
token := setup.Token
|
|
|
|
// Create library
|
|
createLibReq := map[string]interface{}{
|
|
"name": "Set Folders Test Library",
|
|
"description": "Test library for set folders",
|
|
"type": "ebooks",
|
|
}
|
|
createLibURL := setup.Server.URL + "/api/libraries"
|
|
createLibReqHTTP, _ := http.NewRequest("POST", createLibURL, bytes.NewBuffer(jsonMarshal(createLibReq)))
|
|
createLibReqHTTP.Header.Set("Content-Type", "application/json")
|
|
createLibReqHTTP.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
client := &http.Client{}
|
|
createLibResp, err := client.Do(createLibReqHTTP)
|
|
require.NoError(t, err)
|
|
require.Equal(t, http.StatusCreated, createLibResp.StatusCode)
|
|
|
|
var createLibResponse map[string]interface{}
|
|
json.NewDecoder(createLibResp.Body).Decode(&createLibResponse)
|
|
createLibResp.Body.Close()
|
|
|
|
libraryID, ok := createLibResponse["id"].(string)
|
|
require.True(t, ok)
|
|
require.NotEmpty(t, libraryID)
|
|
|
|
// Create temporary directory
|
|
tmpDir := t.TempDir()
|
|
|
|
// Submit set folders job through WorkerInstance
|
|
job := &services.Job{
|
|
ID: uuid.New().String(),
|
|
Type: services.JobTypeSetFolders,
|
|
Params: map[string]interface{}{
|
|
"folders": []string{tmpDir},
|
|
"db": setup.DB,
|
|
},
|
|
Status: services.JobStatusPending,
|
|
}
|
|
|
|
err = services.WorkerInstance.EnqueueJob(job)
|
|
require.NoError(t, err, "Failed to enqueue set folders job")
|
|
|
|
// Wait for job to process
|
|
time.Sleep(1 * time.Second)
|
|
|
|
// Verify folder was added to library
|
|
ctx := context.Background()
|
|
folders, err := setup.DB.GetLibraryFolders(ctx, pgtype.UUID{Bytes: [16]byte(uuid.MustParse(libraryID)), Valid: true})
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, folders, "Library should have folders")
|
|
|
|
// Find our folder
|
|
found := false
|
|
for _, folder := range folders {
|
|
if folder.FolderPath == tmpDir {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
assert.True(t, found, "Folder should be in library")
|
|
}
|
|
|
|
func TestWorker_ConcurrentJobs(t *testing.T) {
|
|
setup := setupTestServer(t)
|
|
defer setup.Close()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Create a library and get admin user
|
|
adminID := getTestUserID(t, setup.DB)
|
|
|
|
libraryType, err := setup.DB.GetLibraryTypeByName(ctx, "ebooks")
|
|
require.NoError(t, err)
|
|
|
|
library, err := setup.DB.CreateLibrary(ctx, database.CreateLibraryParams{
|
|
Name: "Concurrent Job Test Library",
|
|
Description: pgtype.Text{String: "Test library", Valid: true},
|
|
LibraryTypeID: libraryType.ID,
|
|
CreatedByAdminID: pgtype.UUID{Bytes: [16]byte(adminID), Valid: true},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Create multiple temporary directories
|
|
var tmpDirs []string
|
|
for i := 0; i < 3; i++ {
|
|
tmpDir := t.TempDir()
|
|
tmpDirs = append(tmpDirs, tmpDir)
|
|
|
|
// Add folder to library
|
|
_, err = setup.DB.AddLibraryFolder(ctx, database.AddLibraryFolderParams{
|
|
LibraryID: library.ID,
|
|
FolderPath: tmpDir,
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// Submit multiple concurrent jobs
|
|
for _, tmpDir := range tmpDirs {
|
|
job := &services.Job{
|
|
ID: uuid.New().String(),
|
|
Type: services.JobTypeDirectoryScan,
|
|
Params: map[string]interface{}{
|
|
"directory": tmpDir,
|
|
"db": setup.DB,
|
|
},
|
|
Status: services.JobStatusPending,
|
|
}
|
|
err = services.WorkerInstance.EnqueueJob(job)
|
|
require.NoError(t, err, "Failed to enqueue set folders job")
|
|
}
|
|
|
|
// Wait for all jobs to process
|
|
time.Sleep(3 * time.Second)
|
|
|
|
// Verify all directories were processed
|
|
allItems, err := setup.DB.ListMediaItems(ctx, database.ListMediaItemsParams{
|
|
Limit: 1000,
|
|
Offset: 0,
|
|
})
|
|
require.NoError(t, err)
|
|
assert.NotEmpty(t, allItems, "Should have media items from concurrent jobs")
|
|
}
|
|
|
|
func TestWorker_JobStatusTracking(t *testing.T) {
|
|
setup := setupTestServer(t)
|
|
defer setup.Close()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Create test library
|
|
adminID := getTestUserID(t, setup.DB)
|
|
libraryType, err := setup.DB.GetLibraryTypeByName(ctx, "ebooks")
|
|
require.NoError(t, err)
|
|
|
|
library, err := setup.DB.CreateLibrary(ctx, database.CreateLibraryParams{
|
|
Name: "Job Status Test Library",
|
|
Description: pgtype.Text{String: "Test library", Valid: true},
|
|
LibraryTypeID: libraryType.ID,
|
|
CreatedByAdminID: pgtype.UUID{Bytes: [16]byte(adminID), Valid: true},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
tmpDir := t.TempDir()
|
|
_, err = setup.DB.AddLibraryFolder(ctx, database.AddLibraryFolderParams{
|
|
LibraryID: library.ID,
|
|
FolderPath: tmpDir,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Submit job and track status
|
|
jobID := uuid.New().String()
|
|
job := &services.Job{
|
|
ID: jobID,
|
|
Type: services.JobTypeDirectoryScan,
|
|
Params: map[string]interface{}{
|
|
"directory": tmpDir,
|
|
"db": setup.DB,
|
|
},
|
|
Status: services.JobStatusPending,
|
|
}
|
|
|
|
err = services.WorkerInstance.EnqueueJob(job)
|
|
require.NoError(t, err, "Failed to enqueue set folders job")
|
|
|
|
// Poll job status
|
|
var finalStatus string
|
|
for i := 0; i < 10; i++ {
|
|
time.Sleep(500 * time.Millisecond)
|
|
|
|
result, exists := services.WorkerInstance.GetJobStatus(jobID)
|
|
if exists {
|
|
finalStatus = string(result.Status)
|
|
if result.Status == services.JobStatusCompleted || result.Status == services.JobStatusFailed {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// Job should complete (success or failure)
|
|
assert.True(t, finalStatus == "completed" || finalStatus == "failed",
|
|
fmt.Sprintf("Job should complete, got status: %s", finalStatus))
|
|
}
|
|
|
|
// Helper function to marshal JSON
|
|
func jsonMarshal(v interface{}) []byte {
|
|
b, err := json.Marshal(v)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return b
|
|
}
|