Files
gochat/internal/service/captain_document_service_test.go
T

120 lines
4.7 KiB
Go

package service
import (
"context"
"errors"
"fmt"
"testing"
"github.com/gochat/gochat/internal/model"
"github.com/gochat/gochat/internal/repository"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
func setupCaptainDocumentServiceTest(t *testing.T) (*gorm.DB, *CaptainDocumentService) {
t.Helper()
dbName := fmt.Sprintf("file:%s?mode=memory&cache=private", t.Name())
db, err := gorm.Open(sqlite.Open(dbName), &gorm.Config{})
require.NoError(t, err)
require.NoError(t, db.AutoMigrate(&model.Account{}, &model.CaptainAssistant{}, &model.CaptainDocument{}))
t.Cleanup(func() {
sqlDB, _ := db.DB()
sqlDB.Close()
})
documentRepo := repository.NewCaptainDocumentRepo(db)
assistantRepo := repository.NewCaptainAssistantRepo(db)
return db, NewCaptainDocumentService(documentRepo, nil, assistantRepo)
}
func seedCaptainDocumentSyncFixture(t *testing.T, db *gorm.DB) (*model.Account, *model.Account, *model.CaptainDocument) {
t.Helper()
account := &model.Account{Name: "Captain Org", Active: true}
otherAccount := &model.Account{Name: "Other Org", Active: true}
require.NoError(t, db.Create(account).Error)
require.NoError(t, db.Create(otherAccount).Error)
assistant := &model.CaptainAssistant{AccountID: account.ID, Name: "Fin", Description: "Support", Status: model.AssistantStatusActive}
require.NoError(t, db.Create(assistant).Error)
doc := &model.CaptainDocument{
AccountID: account.ID,
AssistantID: assistant.ID,
Name: "Help",
ExternalLink: "https://example.com/help",
Status: model.DocumentStatusCompleted,
SyncStatus: model.DocumentSyncStatusSynced,
}
require.NoError(t, db.Create(doc).Error)
return account, otherAccount, doc
}
func TestCaptainDocumentService_SyncDocumentByAccountDisabledMarksFailed(t *testing.T) {
db, svc := setupCaptainDocumentServiceTest(t)
account, _, doc := seedCaptainDocumentSyncFixture(t, db)
updated, err := svc.SyncDocumentByAccount(context.Background(), account.ID, doc.ID)
require.NoError(t, err)
assert.Equal(t, model.DocumentSyncStatusFailed, updated.SyncStatus)
assert.Equal(t, "sync_disabled", updated.LastSyncErrorCode)
assert.NotNil(t, updated.LastSyncAttemptedAt)
}
func TestCaptainDocumentService_SyncDocumentByAccountUsesFakeBackend(t *testing.T) {
db, svc := setupCaptainDocumentServiceTest(t)
account, _, doc := seedCaptainDocumentSyncFixture(t, db)
backend := &captainDocumentFakeSyncBackend{result: &CaptainDocumentSyncResult{Title: "Fresh Help", Content: "hello\n\nworld"}}
svc.SetSyncBackend(backend)
updated, err := svc.SyncDocumentByAccount(context.Background(), account.ID, doc.ID)
require.NoError(t, err)
assert.Equal(t, doc.ID, backend.documentID)
assert.Equal(t, "Fresh Help", updated.Name)
assert.Equal(t, "hello\n\nworld", updated.Content)
assert.Equal(t, computeFingerprint("hello world"), updated.ContentFingerprint)
assert.Equal(t, model.DocumentStatusCompleted, updated.Status)
assert.Equal(t, model.DocumentSyncStatusSynced, updated.SyncStatus)
assert.Empty(t, updated.LastSyncErrorCode)
assert.NotNil(t, updated.LastSyncedAt)
}
func TestCaptainDocumentService_SyncDocumentByAccountRecordsBackendFailures(t *testing.T) {
db, svc := setupCaptainDocumentServiceTest(t)
account, _, doc := seedCaptainDocumentSyncFixture(t, db)
svc.SetSyncBackend(&captainDocumentFakeSyncBackend{err: errors.New("boom")})
updated, err := svc.SyncDocumentByAccount(context.Background(), account.ID, doc.ID)
require.Error(t, err)
assert.Equal(t, model.DocumentSyncStatusFailed, updated.SyncStatus)
assert.Equal(t, "sync_error", updated.LastSyncErrorCode)
svc.SetSyncBackend(&captainDocumentFakeSyncBackend{result: &CaptainDocumentSyncResult{ErrorCode: "access_denied"}})
updated, err = svc.SyncDocumentByAccount(context.Background(), account.ID, doc.ID)
require.NoError(t, err)
assert.Equal(t, model.DocumentSyncStatusFailed, updated.SyncStatus)
assert.Equal(t, "access_denied", updated.LastSyncErrorCode)
}
func TestCaptainDocumentService_SyncDocumentByAccountScopesDocument(t *testing.T) {
db, svc := setupCaptainDocumentServiceTest(t)
_, otherAccount, doc := seedCaptainDocumentSyncFixture(t, db)
svc.SetSyncBackend(&captainDocumentFakeSyncBackend{result: &CaptainDocumentSyncResult{Content: "fresh"}})
_, err := svc.SyncDocumentByAccount(context.Background(), otherAccount.ID, doc.ID)
require.Error(t, err)
}
type captainDocumentFakeSyncBackend struct {
result *CaptainDocumentSyncResult
err error
documentID uint
}
func (b *captainDocumentFakeSyncBackend) SyncCaptainDocument(ctx context.Context, doc *model.CaptainDocument) (*CaptainDocumentSyncResult, error) {
b.documentID = doc.ID
if b.err != nil {
return nil, b.err
}
return b.result, nil
}