415 lines
11 KiB
Go
415 lines
11 KiB
Go
|
|
package label_test
|
||
|
|
|
||
|
|
import (
|
||
|
|
"testing"
|
||
|
|
|
||
|
|
"queryorchestration/internal/database/repository"
|
||
|
|
"queryorchestration/internal/label"
|
||
|
|
"queryorchestration/internal/serviceconfig"
|
||
|
|
"queryorchestration/internal/test"
|
||
|
|
|
||
|
|
"github.com/google/uuid"
|
||
|
|
"github.com/stretchr/testify/assert"
|
||
|
|
"github.com/stretchr/testify/require"
|
||
|
|
)
|
||
|
|
|
||
|
|
type TestConfig struct {
|
||
|
|
serviceconfig.BaseConfig
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestApplyLabel(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := label.New(cfg)
|
||
|
|
|
||
|
|
// Create test client and document
|
||
|
|
clientID := "test-client-labels"
|
||
|
|
err := cfg.GetDBQueries().CreateClient(ctx, &repository.CreateClientParams{
|
||
|
|
Clientid: clientID,
|
||
|
|
Name: "Test Client Labels",
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
hash := "testhash123"
|
||
|
|
filename := "test.pdf"
|
||
|
|
documentID, err := cfg.GetDBQueries().CreateDocument(ctx, &repository.CreateDocumentParams{
|
||
|
|
Clientid: clientID,
|
||
|
|
Hash: hash,
|
||
|
|
Filename: &filename,
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
t.Run("apply label successfully", func(t *testing.T) {
|
||
|
|
labelName := "Ingested"
|
||
|
|
appliedBy := "user123"
|
||
|
|
|
||
|
|
result, err := svc.ApplyLabel(ctx, documentID, labelName, appliedBy)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.NotNil(t, result)
|
||
|
|
assert.Equal(t, documentID, result.Documentid)
|
||
|
|
assert.Equal(t, labelName, result.Label)
|
||
|
|
assert.Equal(t, appliedBy, result.Appliedby)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("reject empty label", func(t *testing.T) {
|
||
|
|
_, err := svc.ApplyLabel(ctx, documentID, "", "user123")
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.Contains(t, err.Error(), "label cannot be empty")
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("reject empty appliedBy", func(t *testing.T) {
|
||
|
|
_, err := svc.ApplyLabel(ctx, documentID, "Ingested", "")
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.Contains(t, err.Error(), "appliedBy cannot be empty")
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGetDocumentLabels(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := label.New(cfg)
|
||
|
|
|
||
|
|
// Create test client and document
|
||
|
|
clientID := "test-client-get-labels"
|
||
|
|
err := cfg.GetDBQueries().CreateClient(ctx, &repository.CreateClientParams{
|
||
|
|
Clientid: clientID,
|
||
|
|
Name: "Test Client Get Labels",
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
hash := "gethash123"
|
||
|
|
filename := "get.pdf"
|
||
|
|
documentID, err := cfg.GetDBQueries().CreateDocument(ctx, &repository.CreateDocumentParams{
|
||
|
|
Clientid: clientID,
|
||
|
|
Hash: hash,
|
||
|
|
Filename: &filename,
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// Apply multiple labels
|
||
|
|
_, err = svc.ApplyLabel(ctx, documentID, "Dashboard_Ready", "user123")
|
||
|
|
require.NoError(t, err)
|
||
|
|
_, err = svc.ApplyLabel(ctx, documentID, "OCR_Processed", "user123")
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// Get all labels for document
|
||
|
|
result, err := svc.GetDocumentLabels(ctx, documentID)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.Len(t, result, 2)
|
||
|
|
// Should be ordered by most recent first
|
||
|
|
assert.Equal(t, "OCR_Processed", result[0].Label)
|
||
|
|
assert.Equal(t, "Dashboard_Ready", result[1].Label)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGetMostRecentLabel(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := label.New(cfg)
|
||
|
|
|
||
|
|
clientID := "test-client-recent"
|
||
|
|
err := cfg.GetDBQueries().CreateClient(ctx, &repository.CreateClientParams{
|
||
|
|
Clientid: clientID,
|
||
|
|
Name: "Test Client Recent",
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
hash := "recenthash"
|
||
|
|
filename := "recent.pdf"
|
||
|
|
documentID, err := cfg.GetDBQueries().CreateDocument(ctx, &repository.CreateDocumentParams{
|
||
|
|
Clientid: clientID,
|
||
|
|
Hash: hash,
|
||
|
|
Filename: &filename,
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
labelName := "OCR_Processed"
|
||
|
|
_, err = svc.ApplyLabel(ctx, documentID, labelName, "user123")
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
result, err := svc.GetMostRecentLabel(ctx, documentID, labelName)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.Equal(t, labelName, result.Label)
|
||
|
|
assert.Equal(t, documentID, result.Documentid)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGetDocumentsByLabel(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := label.New(cfg)
|
||
|
|
|
||
|
|
clientID := "test-client-by-label"
|
||
|
|
err := cfg.GetDBQueries().CreateClient(ctx, &repository.CreateClientParams{
|
||
|
|
Clientid: clientID,
|
||
|
|
Name: "Test Client By Label",
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// Create two documents
|
||
|
|
filename1 := "doc1.pdf"
|
||
|
|
doc1ID, err := cfg.GetDBQueries().CreateDocument(ctx, &repository.CreateDocumentParams{
|
||
|
|
Clientid: clientID,
|
||
|
|
Hash: "hash1",
|
||
|
|
Filename: &filename1,
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
filename2 := "doc2.pdf"
|
||
|
|
doc2ID, err := cfg.GetDBQueries().CreateDocument(ctx, &repository.CreateDocumentParams{
|
||
|
|
Clientid: clientID,
|
||
|
|
Hash: "hash2",
|
||
|
|
Filename: &filename2,
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// Apply same label to both
|
||
|
|
labelName := "Dashboard_Ready"
|
||
|
|
_, err = svc.ApplyLabel(ctx, doc1ID, labelName, "user123")
|
||
|
|
require.NoError(t, err)
|
||
|
|
_, err = svc.ApplyLabel(ctx, doc2ID, labelName, "user123")
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// Get documents by label
|
||
|
|
result, err := svc.GetDocumentsByLabel(ctx, clientID, labelName)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.Len(t, result, 2)
|
||
|
|
|
||
|
|
ids := []uuid.UUID{result[0].ID, result[1].ID}
|
||
|
|
assert.Contains(t, ids, doc1ID)
|
||
|
|
assert.Contains(t, ids, doc2ID)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGetDocumentsByLabelAndFolder(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := label.New(cfg)
|
||
|
|
|
||
|
|
clientID := "test-client-folder-label"
|
||
|
|
err := cfg.GetDBQueries().CreateClient(ctx, &repository.CreateClientParams{
|
||
|
|
Clientid: clientID,
|
||
|
|
Name: "Test Client Folder Label",
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// Create folder
|
||
|
|
folder, err := cfg.GetDBQueries().CreateFolder(ctx, &repository.CreateFolderParams{
|
||
|
|
Path: "/test-folder",
|
||
|
|
Clientid: clientID,
|
||
|
|
Createdby: "user123",
|
||
|
|
})
|
||
|
|
if err != nil {
|
||
|
|
// If folder already exists from migration/other test, get it
|
||
|
|
existingFolder, getErr := cfg.GetDBQueries().GetFolderByPath(ctx, &repository.GetFolderByPathParams{
|
||
|
|
Clientid: clientID,
|
||
|
|
Path: "/test-folder",
|
||
|
|
})
|
||
|
|
if getErr == nil {
|
||
|
|
folder = existingFolder
|
||
|
|
} else {
|
||
|
|
require.NoError(t, err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
folderID := folder.ID
|
||
|
|
|
||
|
|
// Create document in folder
|
||
|
|
filename := "foldered.pdf"
|
||
|
|
docID, err := cfg.GetDBQueries().CreateDocument(ctx, &repository.CreateDocumentParams{
|
||
|
|
Clientid: clientID,
|
||
|
|
Hash: "foldedhash",
|
||
|
|
Filename: &filename,
|
||
|
|
Folderid: &folderID,
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// Apply label
|
||
|
|
labelName := "OCR_Processed"
|
||
|
|
_, err = svc.ApplyLabel(ctx, docID, labelName, "user123")
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// Get by label and folder
|
||
|
|
result, err := svc.GetDocumentsByLabelAndFolder(ctx, folderID, labelName)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.GreaterOrEqual(t, len(result), 1)
|
||
|
|
|
||
|
|
// Find our document
|
||
|
|
var found bool
|
||
|
|
for _, doc := range result {
|
||
|
|
if doc.ID == docID {
|
||
|
|
found = true
|
||
|
|
assert.Equal(t, folderID, *doc.Folderid)
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
assert.True(t, found)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGetAllLabels(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := label.New(cfg)
|
||
|
|
|
||
|
|
// Get all labels (should include the 5 from migration)
|
||
|
|
result, err := svc.GetAllLabels(ctx)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.GreaterOrEqual(t, len(result), 5)
|
||
|
|
|
||
|
|
// Check that expected labels exist
|
||
|
|
labelNames := make(map[string]bool)
|
||
|
|
for _, l := range result {
|
||
|
|
labelNames[l.Label] = true
|
||
|
|
}
|
||
|
|
assert.True(t, labelNames["Ingested"])
|
||
|
|
assert.True(t, labelNames["OCR_Processed"])
|
||
|
|
assert.True(t, labelNames["Dashboard_Ready"])
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestCreateLabel(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := label.New(cfg)
|
||
|
|
|
||
|
|
t.Run("create label successfully", func(t *testing.T) {
|
||
|
|
labelName := "Custom_Label_Test"
|
||
|
|
description := "A custom label for testing"
|
||
|
|
|
||
|
|
result, err := svc.CreateLabel(ctx, labelName, description)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.Equal(t, labelName, result.Label)
|
||
|
|
assert.Equal(t, description, result.Description)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("reject empty label", func(t *testing.T) {
|
||
|
|
_, err := svc.CreateLabel(ctx, "", "description")
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.Contains(t, err.Error(), "label cannot be empty")
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("reject empty description", func(t *testing.T) {
|
||
|
|
_, err := svc.CreateLabel(ctx, "Custom_Label", "")
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.Contains(t, err.Error(), "description cannot be empty")
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestGetDocumentLabelHistory(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := label.New(cfg)
|
||
|
|
|
||
|
|
clientID := "test-client-history"
|
||
|
|
err := cfg.GetDBQueries().CreateClient(ctx, &repository.CreateClientParams{
|
||
|
|
Clientid: clientID,
|
||
|
|
Name: "Test Client History",
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// Create document
|
||
|
|
filename := "history.pdf"
|
||
|
|
docID, err := cfg.GetDBQueries().CreateDocument(ctx, &repository.CreateDocumentParams{
|
||
|
|
Clientid: clientID,
|
||
|
|
Hash: "historyhash",
|
||
|
|
Filename: &filename,
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
t.Run("get history with pagination", func(t *testing.T) {
|
||
|
|
// Apply label
|
||
|
|
_, err := svc.ApplyLabel(ctx, docID, "Ingested", "user123")
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// Get history
|
||
|
|
result, err := svc.GetDocumentLabelHistory(ctx, clientID, 10, 0)
|
||
|
|
require.NoError(t, err)
|
||
|
|
assert.GreaterOrEqual(t, len(result), 1)
|
||
|
|
|
||
|
|
// Find our label
|
||
|
|
var found bool
|
||
|
|
for _, h := range result {
|
||
|
|
if h.Documentid == docID && h.Label == "Ingested" {
|
||
|
|
found = true
|
||
|
|
assert.Equal(t, filename, *h.Filename)
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
assert.True(t, found)
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("reject invalid limit", func(t *testing.T) {
|
||
|
|
_, err := svc.GetDocumentLabelHistory(ctx, clientID, 0, 0)
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.Contains(t, err.Error(), "limit must be greater than 0")
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("reject negative offset", func(t *testing.T) {
|
||
|
|
_, err := svc.GetDocumentLabelHistory(ctx, clientID, 10, -1)
|
||
|
|
require.Error(t, err)
|
||
|
|
assert.Contains(t, err.Error(), "offset cannot be negative")
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestReapplyLabel(t *testing.T) {
|
||
|
|
ctx := t.Context()
|
||
|
|
cfg := &TestConfig{}
|
||
|
|
test.CreateDB(t, cfg)
|
||
|
|
svc := label.New(cfg)
|
||
|
|
|
||
|
|
clientID := "test-client-reapply"
|
||
|
|
err := cfg.GetDBQueries().CreateClient(ctx, &repository.CreateClientParams{
|
||
|
|
Clientid: clientID,
|
||
|
|
Name: "Test Client Reapply",
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
filename := "reapply.pdf"
|
||
|
|
documentID, err := cfg.GetDBQueries().CreateDocument(ctx, &repository.CreateDocumentParams{
|
||
|
|
Clientid: clientID,
|
||
|
|
Hash: "reapplyhash",
|
||
|
|
Filename: &filename,
|
||
|
|
})
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
t.Run("can apply same label multiple times", func(t *testing.T) {
|
||
|
|
labelName := "OCR_Processed"
|
||
|
|
appliedBy := "user123"
|
||
|
|
|
||
|
|
// First application
|
||
|
|
result1, err := svc.ApplyLabel(ctx, documentID, labelName, appliedBy)
|
||
|
|
require.NoError(t, err)
|
||
|
|
id1 := result1.ID
|
||
|
|
|
||
|
|
// Second application (reapply)
|
||
|
|
result2, err := svc.ApplyLabel(ctx, documentID, labelName, appliedBy)
|
||
|
|
require.NoError(t, err)
|
||
|
|
id2 := result2.ID
|
||
|
|
|
||
|
|
// Should have different IDs (different records)
|
||
|
|
assert.NotEqual(t, id1, id2)
|
||
|
|
|
||
|
|
// Both should have same label and document
|
||
|
|
assert.Equal(t, labelName, result1.Label)
|
||
|
|
assert.Equal(t, labelName, result2.Label)
|
||
|
|
assert.Equal(t, documentID, result1.Documentid)
|
||
|
|
assert.Equal(t, documentID, result2.Documentid)
|
||
|
|
|
||
|
|
// Check history shows both
|
||
|
|
history, err := svc.GetDocumentLabels(ctx, documentID)
|
||
|
|
require.NoError(t, err)
|
||
|
|
|
||
|
|
// Count how many times OCR_Processed appears
|
||
|
|
count := 0
|
||
|
|
for _, h := range history {
|
||
|
|
if h.Label == labelName {
|
||
|
|
count++
|
||
|
|
}
|
||
|
|
}
|
||
|
|
assert.GreaterOrEqual(t, count, 2)
|
||
|
|
})
|
||
|
|
}
|