Files
Jay Brown 8c218f162b Merged in feature/textExtractionsPart3 (pull request #195)
enrich doc responses

* enrich doc responses
2025-12-11 14:25:51 +00:00

531 lines
15 KiB
Go

package folder_test
import (
"testing"
"queryorchestration/internal/database/repository"
"queryorchestration/internal/fieldextraction"
"queryorchestration/internal/folder"
"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 TestCreateFolder(t *testing.T) {
ctx := t.Context()
cfg := &TestConfig{}
test.CreateDB(t, cfg)
svc := folder.New(cfg)
// Create test client first
clientID := "test-client-folders"
err := cfg.GetDBQueries().CreateClient(ctx, &repository.CreateClientParams{
Clientid: clientID,
Name: "Test Client Folders",
})
require.NoError(t, err)
t.Run("create root folder successfully", func(t *testing.T) {
path := "/documents"
createdBy := "user123"
result, err := svc.CreateFolder(ctx, path, nil, clientID, createdBy)
require.NoError(t, err)
require.NotNil(t, result)
assert.Equal(t, path, result.Path)
assert.Nil(t, result.Parentid)
assert.Equal(t, clientID, result.Clientid)
assert.Equal(t, createdBy, result.Createdby)
})
t.Run("create subfolder with valid parent", func(t *testing.T) {
// Create parent folder
parentPath := "/contracts"
parentResult, err := svc.CreateFolder(ctx, parentPath, nil, clientID, "user123")
require.NoError(t, err)
parentID := parentResult.ID
// Create subfolder
subPath := "/contracts/2025"
result, err := svc.CreateFolder(ctx, subPath, &parentID, clientID, "user123")
require.NoError(t, err)
require.NotNil(t, result)
assert.Equal(t, subPath, result.Path)
require.NotNil(t, result.Parentid)
assert.Equal(t, parentID, *result.Parentid)
})
t.Run("reject empty path", func(t *testing.T) {
_, err := svc.CreateFolder(ctx, "", nil, clientID, "user123")
require.Error(t, err)
assert.Contains(t, err.Error(), "must start with /")
})
t.Run("reject empty clientID", func(t *testing.T) {
_, err := svc.CreateFolder(ctx, "/test", nil, "", "user123")
require.Error(t, err)
assert.Contains(t, err.Error(), "clientID cannot be empty")
})
t.Run("reject empty createdBy", func(t *testing.T) {
_, err := svc.CreateFolder(ctx, "/test", nil, clientID, "")
require.Error(t, err)
assert.Contains(t, err.Error(), "createdBy cannot be empty")
})
t.Run("reject parent from different client", func(t *testing.T) {
// Create another client
otherClientID := "other-client"
err := cfg.GetDBQueries().CreateClient(ctx, &repository.CreateClientParams{
Clientid: otherClientID,
Name: "Other Client",
})
require.NoError(t, err)
// Create parent folder for other client
parentResult, err := svc.CreateFolder(ctx, "/other", nil, otherClientID, "user123")
require.NoError(t, err)
parentID := parentResult.ID
// Try to create subfolder with parent from different client
_, err = svc.CreateFolder(ctx, "/test", &parentID, clientID, "user123")
require.Error(t, err)
assert.Contains(t, err.Error(), "different client")
})
}
func TestGetFolder(t *testing.T) {
ctx := t.Context()
cfg := &TestConfig{}
test.CreateDB(t, cfg)
svc := folder.New(cfg)
clientID := "test-client-get"
err := cfg.GetDBQueries().CreateClient(ctx, &repository.CreateClientParams{
Clientid: clientID,
Name: "Test Client Get",
})
require.NoError(t, err)
// Create a folder
path := "/documents"
created, err := svc.CreateFolder(ctx, path, nil, clientID, "user123")
require.NoError(t, err)
// Get the folder
result, err := svc.GetFolder(ctx, created.ID)
require.NoError(t, err)
assert.Equal(t, created.ID, result.ID)
assert.Equal(t, path, result.Path)
}
func TestGetFolderByPath(t *testing.T) {
ctx := t.Context()
cfg := &TestConfig{}
test.CreateDB(t, cfg)
svc := folder.New(cfg)
clientID := "test-client-path"
err := cfg.GetDBQueries().CreateClient(ctx, &repository.CreateClientParams{
Clientid: clientID,
Name: "Test Client Path",
})
require.NoError(t, err)
// Create a folder
path := "/documents/2025"
created, err := svc.CreateFolder(ctx, path, nil, clientID, "user123")
require.NoError(t, err)
// Get by path
result, err := svc.GetFolderByPath(ctx, clientID, path)
require.NoError(t, err)
assert.Equal(t, created.ID, result.ID)
assert.Equal(t, path, result.Path)
assert.Equal(t, clientID, result.Clientid)
}
func TestRenameFolder(t *testing.T) {
ctx := t.Context()
cfg := &TestConfig{}
test.CreateDB(t, cfg)
svc := folder.New(cfg)
clientID := "test-client-rename"
err := cfg.GetDBQueries().CreateClient(ctx, &repository.CreateClientParams{
Clientid: clientID,
Name: "Test Client Rename",
})
require.NoError(t, err)
t.Run("rename successfully", func(t *testing.T) {
oldPath := "/old-path"
created, err := svc.CreateFolder(ctx, oldPath, nil, clientID, "user123")
require.NoError(t, err)
newPath := "/new-path"
err = svc.RenameFolder(ctx, created.ID, newPath)
require.NoError(t, err)
// Verify rename
result, err := svc.GetFolder(ctx, created.ID)
require.NoError(t, err)
assert.Equal(t, newPath, result.Path)
})
t.Run("reject empty path", func(t *testing.T) {
err := svc.RenameFolder(ctx, uuid.New(), "")
require.Error(t, err)
// The folder won't be found, so we can't test path validation
assert.Contains(t, err.Error(), "folder not found")
})
t.Run("reject invalid path characters", func(t *testing.T) {
path := "/test-rename-invalid"
created, err := svc.CreateFolder(ctx, path, nil, clientID, "user123")
require.NoError(t, err)
err = svc.RenameFolder(ctx, created.ID, "/invalid@path")
require.Error(t, err)
assert.True(t, folder.IsPathValidationError(err))
})
t.Run("reject root folder rename", func(t *testing.T) {
// Create root folder
rootPath := "/"
rootFolder, err := svc.CreateFolder(ctx, rootPath, nil, clientID, "user123")
require.NoError(t, err)
// Try to rename root folder
err = svc.RenameFolder(ctx, rootFolder.ID, "/renamed-root")
require.Error(t, err)
assert.True(t, folder.IsPathValidationError(err))
assert.Contains(t, err.Error(), "root folder cannot be renamed")
})
}
func TestGetFolderTree(t *testing.T) {
ctx := t.Context()
cfg := &TestConfig{}
test.CreateDB(t, cfg)
svc := folder.New(cfg)
clientID := "test-client-tree"
err := cfg.GetDBQueries().CreateClient(ctx, &repository.CreateClientParams{
Clientid: clientID,
Name: "Test Client Tree",
})
require.NoError(t, err)
// Create folder hierarchy
root, err := svc.CreateFolder(ctx, "/documents", nil, clientID, "user123")
require.NoError(t, err)
child1, err := svc.CreateFolder(ctx, "/documents/2025", &root.ID, clientID, "user123")
require.NoError(t, err)
_, err = svc.CreateFolder(ctx, "/documents/2025/january", &child1.ID, clientID, "user123")
require.NoError(t, err)
// Get tree
result, err := svc.GetFolderTree(ctx, root.ID)
require.NoError(t, err)
assert.Len(t, result, 3) // root + 2 descendants
assert.Equal(t, root.ID, result[0].ID)
}
func TestGetFoldersByClient(t *testing.T) {
ctx := t.Context()
cfg := &TestConfig{}
test.CreateDB(t, cfg)
svc := folder.New(cfg)
clientID := "test-client-list"
err := cfg.GetDBQueries().CreateClient(ctx, &repository.CreateClientParams{
Clientid: clientID,
Name: "Test Client List",
})
require.NoError(t, err)
// Create multiple folders
_, err = svc.CreateFolder(ctx, "/documents", nil, clientID, "user123")
require.NoError(t, err)
_, err = svc.CreateFolder(ctx, "/contracts", nil, clientID, "user123")
require.NoError(t, err)
result, err := svc.GetFoldersByClient(ctx, clientID)
require.NoError(t, err)
assert.GreaterOrEqual(t, len(result), 2)
}
func TestGetRootFolders(t *testing.T) {
ctx := t.Context()
cfg := &TestConfig{}
test.CreateDB(t, cfg)
svc := folder.New(cfg)
clientID := "test-client-roots"
err := cfg.GetDBQueries().CreateClient(ctx, &repository.CreateClientParams{
Clientid: clientID,
Name: "Test Client Roots",
})
require.NoError(t, err)
// Create root folder
root, err := svc.CreateFolder(ctx, "/documents", nil, clientID, "user123")
require.NoError(t, err)
// Create child folder
_, err = svc.CreateFolder(ctx, "/documents/sub", &root.ID, clientID, "user123")
require.NoError(t, err)
// Get only root folders
result, err := svc.GetRootFolders(ctx, clientID)
require.NoError(t, err)
// Filter to only this test's root
var foundRoot *repository.Folder
for _, f := range result {
if f.ID == root.ID {
foundRoot = f
break
}
}
require.NotNil(t, foundRoot)
assert.Nil(t, foundRoot.Parentid)
}
func TestGetSubfolders(t *testing.T) {
ctx := t.Context()
cfg := &TestConfig{}
test.CreateDB(t, cfg)
svc := folder.New(cfg)
clientID := "test-client-subs"
err := cfg.GetDBQueries().CreateClient(ctx, &repository.CreateClientParams{
Clientid: clientID,
Name: "Test Client Subs",
})
require.NoError(t, err)
// Create parent
parent, err := svc.CreateFolder(ctx, "/documents", nil, clientID, "user123")
require.NoError(t, err)
// Create child
child, err := svc.CreateFolder(ctx, "/documents/2025", &parent.ID, clientID, "user123")
require.NoError(t, err)
// Get subfolders
result, err := svc.GetSubfolders(ctx, parent.ID)
require.NoError(t, err)
assert.Len(t, result, 1)
assert.Equal(t, child.ID, result[0].ID)
assert.Equal(t, parent.ID, *result[0].Parentid)
}
func TestGetDocumentsByFolder(t *testing.T) {
ctx := t.Context()
cfg := &TestConfig{}
test.CreateDB(t, cfg)
svc := folder.New(cfg)
clientID := "test-client-docs-by-folder"
err := cfg.GetDBQueries().CreateClient(ctx, &repository.CreateClientParams{
Clientid: clientID,
Name: "Test Client Docs By Folder",
})
require.NoError(t, err)
t.Run("get documents in folder", func(t *testing.T) {
// Create folder
folderResult, err := svc.CreateFolder(ctx, "/contracts", nil, clientID, "user123")
require.NoError(t, err)
// Create documents in folder
filename1 := "contract1.pdf"
doc1ID, err := cfg.GetDBQueries().CreateDocument(ctx, &repository.CreateDocumentParams{
Clientid: clientID,
Hash: "foldertest1",
Filename: &filename1,
Folderid: &folderResult.ID,
})
require.NoError(t, err)
filename2 := "contract2.pdf"
doc2ID, err := cfg.GetDBQueries().CreateDocument(ctx, &repository.CreateDocumentParams{
Clientid: clientID,
Hash: "foldertest2",
Filename: &filename2,
Folderid: &folderResult.ID,
})
require.NoError(t, err)
// Get documents by folder
docs, err := svc.GetDocumentsByFolder(ctx, folderResult.ID)
require.NoError(t, err)
assert.Len(t, docs, 2)
// Verify both documents are returned
docIDs := make(map[uuid.UUID]bool)
for _, doc := range docs {
docIDs[doc.ID] = true
}
assert.True(t, docIDs[doc1ID])
assert.True(t, docIDs[doc2ID])
})
t.Run("return empty for folder with no documents", func(t *testing.T) {
// Create folder with no documents
emptyFolder, err := svc.CreateFolder(ctx, "/empty", nil, clientID, "user123")
require.NoError(t, err)
docs, err := svc.GetDocumentsByFolder(ctx, emptyFolder.ID)
require.NoError(t, err)
assert.Len(t, docs, 0)
})
}
func TestGetDocumentsEnriched(t *testing.T) {
ctx := t.Context()
cfg := &TestConfig{}
test.CreateDB(t, cfg)
svc := folder.New(cfg)
clientID := "test-client-docs-enriched"
err := cfg.GetDBQueries().CreateClient(ctx, &repository.CreateClientParams{
Clientid: clientID,
Name: "Test Client Docs Enriched",
})
require.NoError(t, err)
t.Run("get enriched documents without text record", func(t *testing.T) {
// Create folder
folderResult, err := svc.CreateFolder(ctx, "/enriched-no-text", nil, clientID, "user123")
require.NoError(t, err)
// Create document in folder
filename := "enriched1.pdf"
originalPath := "/uploads/enriched1.pdf"
docID, err := cfg.GetDBQueries().CreateDocument(ctx, &repository.CreateDocumentParams{
Clientid: clientID,
Hash: "enrichedtest1",
Filename: &filename,
Originalpath: &originalPath,
Folderid: &folderResult.ID,
})
require.NoError(t, err)
// Get enriched documents
docs, err := svc.GetDocumentsEnriched(ctx, folderResult.ID, false)
require.NoError(t, err)
assert.Len(t, docs, 1)
assert.Equal(t, docID, docs[0].ID)
assert.Equal(t, "enrichedtest1", docs[0].Hash)
assert.Equal(t, filename, *docs[0].Filename)
assert.Equal(t, originalPath, *docs[0].OriginalPath)
assert.False(t, docs[0].HasTextRecord)
assert.Nil(t, docs[0].TextRecord)
assert.Empty(t, docs[0].Labels)
})
t.Run("get enriched documents with text record", func(t *testing.T) {
// Create folder
folderResult, err := svc.CreateFolder(ctx, "/enriched-with-text", nil, clientID, "user123")
require.NoError(t, err)
// Create document in folder
filename := "enriched2.pdf"
docID, err := cfg.GetDBQueries().CreateDocument(ctx, &repository.CreateDocumentParams{
Clientid: clientID,
Hash: "enrichedtest2",
Filename: &filename,
Folderid: &folderResult.ID,
})
require.NoError(t, err)
// Create field extraction for this document
fieldSvc := fieldextraction.New(cfg)
contractTitle := "Enriched Test Contract"
input := &fieldextraction.CreateFieldExtractionInput{
DocumentID: docID,
SingleFields: &repository.AddFieldExtractionParams{
Documentid: docID,
Filename: &filename,
Contracttitle: &contractTitle,
Createdby: "testuser",
},
ArrayFields: []*repository.AddFieldExtractionArrayFieldParams{},
}
_, err = fieldSvc.CreateFieldExtraction(ctx, input)
require.NoError(t, err)
// Get enriched documents with text record
docs, err := svc.GetDocumentsEnriched(ctx, folderResult.ID, true)
require.NoError(t, err)
assert.Len(t, docs, 1)
assert.Equal(t, docID, docs[0].ID)
assert.True(t, docs[0].HasTextRecord)
assert.NotNil(t, docs[0].TextRecord)
assert.Equal(t, docID, docs[0].TextRecord.DocumentID)
assert.Equal(t, int32(1), docs[0].TextRecord.Version)
assert.Equal(t, "testuser", docs[0].TextRecord.CreatedBy)
})
t.Run("get enriched documents with text record but not requesting it", func(t *testing.T) {
// Create folder
folderResult, err := svc.CreateFolder(ctx, "/enriched-skip-text", nil, clientID, "user123")
require.NoError(t, err)
// Create document in folder
filename := "enriched3.pdf"
docID, err := cfg.GetDBQueries().CreateDocument(ctx, &repository.CreateDocumentParams{
Clientid: clientID,
Hash: "enrichedtest3",
Filename: &filename,
Folderid: &folderResult.ID,
})
require.NoError(t, err)
// Create field extraction
fieldSvc := fieldextraction.New(cfg)
contractTitle := "Skip Text Contract"
input := &fieldextraction.CreateFieldExtractionInput{
DocumentID: docID,
SingleFields: &repository.AddFieldExtractionParams{
Documentid: docID,
Filename: &filename,
Contracttitle: &contractTitle,
Createdby: "skipuser",
},
ArrayFields: []*repository.AddFieldExtractionArrayFieldParams{},
}
_, err = fieldSvc.CreateFieldExtraction(ctx, input)
require.NoError(t, err)
// Get enriched documents without requesting text record
docs, err := svc.GetDocumentsEnriched(ctx, folderResult.ID, false)
require.NoError(t, err)
assert.Len(t, docs, 1)
assert.True(t, docs[0].HasTextRecord) // Has text record
assert.Nil(t, docs[0].TextRecord) // But not fetched
})
t.Run("return empty for empty folder", func(t *testing.T) {
// Create folder with no documents
emptyFolder, err := svc.CreateFolder(ctx, "/enriched-empty", nil, clientID, "user123")
require.NoError(t, err)
docs, err := svc.GetDocumentsEnriched(ctx, emptyFolder.ID, false)
require.NoError(t, err)
assert.Len(t, docs, 0)
})
}