375 lines
13 KiB
Go
375 lines
13 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
filemanager "wucher/internal/domain/file_manager"
|
|
helicopterfile "wucher/internal/domain/helicopter_file"
|
|
helicopterfilerealtime "wucher/internal/realtime/helicopterfile"
|
|
"wucher/internal/shared/pkg/uuidv7"
|
|
)
|
|
|
|
type helicopterFileServiceRepoStub struct {
|
|
listPendingFn func(context.Context, int) ([]helicopterfile.HelicopterFile, error)
|
|
listPendingBySourceFn func(context.Context, []byte, int) ([]helicopterfile.HelicopterFile, error)
|
|
updateFn func(context.Context, *helicopterfile.HelicopterFile) error
|
|
}
|
|
|
|
func (r *helicopterFileServiceRepoStub) Create(context.Context, *helicopterfile.HelicopterFile) error {
|
|
return nil
|
|
}
|
|
|
|
func (r *helicopterFileServiceRepoStub) Update(ctx context.Context, row *helicopterfile.HelicopterFile) error {
|
|
if r.updateFn != nil {
|
|
return r.updateFn(ctx, row)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *helicopterFileServiceRepoStub) Delete(context.Context, []byte) error { return nil }
|
|
|
|
func (r *helicopterFileServiceRepoStub) GetByID(context.Context, []byte) (*helicopterfile.HelicopterFile, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (r *helicopterFileServiceRepoStub) List(context.Context, string, string, int, int) ([]helicopterfile.HelicopterFile, int64, error) {
|
|
return nil, 0, nil
|
|
}
|
|
|
|
func (r *helicopterFileServiceRepoStub) ListPendingAttachments(ctx context.Context, limit int) ([]helicopterfile.HelicopterFile, error) {
|
|
if r.listPendingFn != nil {
|
|
return r.listPendingFn(ctx, limit)
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (r *helicopterFileServiceRepoStub) ListPendingAttachmentsBySourceFileID(ctx context.Context, sourceFileID []byte, limit int) ([]helicopterfile.HelicopterFile, error) {
|
|
if r.listPendingBySourceFn != nil {
|
|
return r.listPendingBySourceFn(ctx, sourceFileID, limit)
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (r *helicopterFileServiceRepoStub) ListByHelicopter(context.Context, []byte) ([]helicopterfile.HelicopterFile, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (r *helicopterFileServiceRepoStub) ListByHelicopterAndSection(context.Context, []byte, string) ([]helicopterfile.HelicopterFile, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (r *helicopterFileServiceRepoStub) HelicopterExists(context.Context, []byte) (bool, error) {
|
|
return false, nil
|
|
}
|
|
|
|
func (r *helicopterFileServiceRepoStub) AttachmentExists(context.Context, []byte) (bool, error) {
|
|
return false, nil
|
|
}
|
|
|
|
type helicopterFileServiceManagerStub struct {
|
|
filemanager.Service
|
|
|
|
createAttachmentFn func(context.Context, filemanager.CreateAttachmentParams) (*filemanager.Attachment, error)
|
|
getAttachmentByIDFn func(context.Context, []byte) (*filemanager.Attachment, error)
|
|
markFileActiveFn func(context.Context, []byte, []byte) error
|
|
createAttachmentArgs []filemanager.CreateAttachmentParams
|
|
markFileActiveArgs []struct {
|
|
fileID []byte
|
|
actorID []byte
|
|
}
|
|
}
|
|
|
|
func (m *helicopterFileServiceManagerStub) CreateAttachment(ctx context.Context, params filemanager.CreateAttachmentParams) (*filemanager.Attachment, error) {
|
|
copied := params
|
|
copied.FileID = append([]byte(nil), params.FileID...)
|
|
copied.ActorID = append([]byte(nil), params.ActorID...)
|
|
m.createAttachmentArgs = append(m.createAttachmentArgs, copied)
|
|
if m.createAttachmentFn != nil {
|
|
return m.createAttachmentFn(ctx, params)
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *helicopterFileServiceManagerStub) GetAttachmentByID(ctx context.Context, id []byte) (*filemanager.Attachment, error) {
|
|
if m.getAttachmentByIDFn != nil {
|
|
return m.getAttachmentByIDFn(ctx, id)
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *helicopterFileServiceManagerStub) MarkFileActive(ctx context.Context, fileID []byte, actorID []byte) error {
|
|
m.markFileActiveArgs = append(m.markFileActiveArgs, struct {
|
|
fileID []byte
|
|
actorID []byte
|
|
}{fileID: append([]byte(nil), fileID...), actorID: append([]byte(nil), actorID...)})
|
|
if m.markFileActiveFn != nil {
|
|
return m.markFileActiveFn(ctx, fileID, actorID)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m *helicopterFileServiceManagerStub) ReconcileFileLifecycle(context.Context, []byte, []byte) error {
|
|
return nil
|
|
}
|
|
|
|
func (m *helicopterFileServiceManagerStub) CleanupOrphanPendingFiles(context.Context, time.Time, time.Duration, int, bool) (filemanager.FileCleanupStats, error) {
|
|
return filemanager.FileCleanupStats{}, nil
|
|
}
|
|
|
|
type helicopterFileServiceEventsStub struct {
|
|
publishedUsers []string
|
|
event *helicopterfilerealtime.Event
|
|
}
|
|
|
|
func (m *helicopterFileServiceEventsStub) PublishToUsers(userUUIDs []string, event helicopterfilerealtime.Event) int {
|
|
m.publishedUsers = append([]string(nil), userUUIDs...)
|
|
copied := event
|
|
m.event = &copied
|
|
return len(userUUIDs)
|
|
}
|
|
|
|
func TestHelicopterFileServiceFinalizePendingAttachmentsPublishesReadyEvent(t *testing.T) {
|
|
actorID := uuidv7.MustBytes()
|
|
helicopterID := uuidv7.MustBytes()
|
|
helicopterFileID := uuidv7.MustBytes()
|
|
sourceFileID := uuidv7.MustBytes()
|
|
attachmentID := uuidv7.MustBytes()
|
|
|
|
sourceFile := &filemanager.File{
|
|
ID: sourceFileID,
|
|
Name: "purchase_orders 1 (15).xlsx",
|
|
MimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
Status: filemanager.FileStatusReady,
|
|
}
|
|
|
|
repo := &helicopterFileServiceRepoStub{
|
|
listPendingFn: func(_ context.Context, limit int) ([]helicopterfile.HelicopterFile, error) {
|
|
if limit != 1 {
|
|
t.Fatalf("expected limit 1, got %d", limit)
|
|
}
|
|
return []helicopterfile.HelicopterFile{
|
|
{
|
|
ID: helicopterFileID,
|
|
HelicopterID: helicopterID,
|
|
SourceFileID: sourceFileID,
|
|
CreatedBy: actorID,
|
|
UpdatedBy: actorID,
|
|
SourceFile: sourceFile,
|
|
Position: 4,
|
|
IsMandatory: false,
|
|
Section: helicopterfile.SectionBeforeFirstFlightInspection,
|
|
UpdatedAt: time.Unix(100, 0).UTC(),
|
|
CreatedAt: time.Unix(90, 0).UTC(),
|
|
FileAttachmentID: nil,
|
|
},
|
|
}, nil
|
|
},
|
|
updateFn: func(_ context.Context, row *helicopterfile.HelicopterFile) error {
|
|
if row == nil {
|
|
t.Fatal("expected row to be updated")
|
|
}
|
|
if len(row.FileAttachmentID) != 16 {
|
|
t.Fatalf("expected attachment id to be set, got %d bytes", len(row.FileAttachmentID))
|
|
}
|
|
if len(row.SourceFileID) != 0 {
|
|
t.Fatalf("expected source file id to be cleared, got %d bytes", len(row.SourceFileID))
|
|
}
|
|
return nil
|
|
},
|
|
}
|
|
|
|
fm := &helicopterFileServiceManagerStub{
|
|
createAttachmentFn: func(_ context.Context, params filemanager.CreateAttachmentParams) (*filemanager.Attachment, error) {
|
|
if got, want := uuidStringOrFail(t, params.FileID), uuidStringOrFail(t, sourceFileID); got != want {
|
|
t.Fatalf("unexpected file id: got %s want %s", got, want)
|
|
}
|
|
if got, want := params.RefType, "helicopter"; got != want {
|
|
t.Fatalf("unexpected ref type: got %q want %q", got, want)
|
|
}
|
|
if got, want := params.RefID, uuidStringOrFail(t, helicopterID); got != want {
|
|
t.Fatalf("unexpected ref id: got %q want %q", got, want)
|
|
}
|
|
if params.Category == nil || *params.Category != "helicopter_file" {
|
|
t.Fatalf("expected helicopter_file category, got %#v", params.Category)
|
|
}
|
|
return &filemanager.Attachment{
|
|
ID: attachmentID,
|
|
FileID: sourceFileID,
|
|
File: sourceFile,
|
|
}, nil
|
|
},
|
|
getAttachmentByIDFn: func(_ context.Context, id []byte) (*filemanager.Attachment, error) {
|
|
if got, want := uuidStringOrFail(t, id), uuidStringOrFail(t, attachmentID); got != want {
|
|
t.Fatalf("unexpected attachment lookup id: got %s want %s", got, want)
|
|
}
|
|
return &filemanager.Attachment{
|
|
ID: attachmentID,
|
|
FileID: sourceFileID,
|
|
File: sourceFile,
|
|
}, nil
|
|
},
|
|
}
|
|
events := &helicopterFileServiceEventsStub{}
|
|
|
|
svc := NewHelicopterFileService(repo).
|
|
WithFileManagerService(fm).
|
|
WithHelicopterFileEvents(events)
|
|
|
|
finalized, err := svc.FinalizePendingAttachments(context.Background(), 1)
|
|
if err != nil {
|
|
t.Fatalf("FinalizePendingAttachments returned error: %v", err)
|
|
}
|
|
if finalized != 1 {
|
|
t.Fatalf("expected one finalized attachment, got %d", finalized)
|
|
}
|
|
if len(fm.createAttachmentArgs) != 1 {
|
|
t.Fatalf("expected one attachment create call, got %d", len(fm.createAttachmentArgs))
|
|
}
|
|
if len(fm.markFileActiveArgs) != 1 {
|
|
t.Fatalf("expected one mark active call, got %d", len(fm.markFileActiveArgs))
|
|
}
|
|
if events.event == nil {
|
|
t.Fatal("expected helicopter file event to be published")
|
|
}
|
|
|
|
expectedUser := uuidStringOrFail(t, actorID)
|
|
if len(events.publishedUsers) != 1 || events.publishedUsers[0] != expectedUser {
|
|
t.Fatalf("unexpected published users: %#v", events.publishedUsers)
|
|
}
|
|
if events.event.EventType != helicopterfilerealtime.DefaultEventType {
|
|
t.Fatalf("expected default event type, got %q", events.event.EventType)
|
|
}
|
|
if events.event.HelicopterID != uuidStringOrFail(t, helicopterID) {
|
|
t.Fatalf("unexpected helicopter id: %+v", events.event)
|
|
}
|
|
if events.event.HelicopterFileID != uuidStringOrFail(t, helicopterFileID) {
|
|
t.Fatalf("unexpected helicopter file id: %+v", events.event)
|
|
}
|
|
if events.event.FileID != uuidStringOrFail(t, attachmentID) {
|
|
t.Fatalf("expected finalized event to point to attachment id, got %+v", events.event)
|
|
}
|
|
if events.event.AttachmentPending {
|
|
t.Fatalf("expected finalized event to mark attachment pending false, got %+v", events.event)
|
|
}
|
|
if events.event.Name != sourceFile.Name || events.event.MimeType != sourceFile.MimeType {
|
|
t.Fatalf("unexpected file metadata in event: %+v", events.event)
|
|
}
|
|
}
|
|
|
|
func TestHelicopterFileServiceFinalizePendingAttachmentsBySourceFileUUIDPublishesReadyEvent(t *testing.T) {
|
|
actorID := uuidv7.MustBytes()
|
|
helicopterID := uuidv7.MustBytes()
|
|
helicopterFileID := uuidv7.MustBytes()
|
|
sourceFileID := uuidv7.MustBytes()
|
|
attachmentID := uuidv7.MustBytes()
|
|
sourceFileUUID := uuidStringOrFail(t, sourceFileID)
|
|
|
|
sourceFile := &filemanager.File{
|
|
ID: sourceFileID,
|
|
Name: "purchase_orders 1 (15).xlsx",
|
|
MimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
Status: filemanager.FileStatusReady,
|
|
}
|
|
|
|
repo := &helicopterFileServiceRepoStub{
|
|
listPendingBySourceFn: func(_ context.Context, source []byte, limit int) ([]helicopterfile.HelicopterFile, error) {
|
|
if got, want := uuidStringOrFail(t, source), sourceFileUUID; got != want {
|
|
t.Fatalf("unexpected source file id: got %s want %s", got, want)
|
|
}
|
|
if limit != 1 {
|
|
t.Fatalf("expected limit 1, got %d", limit)
|
|
}
|
|
return []helicopterfile.HelicopterFile{
|
|
{
|
|
ID: helicopterFileID,
|
|
HelicopterID: helicopterID,
|
|
SourceFileID: sourceFileID,
|
|
CreatedBy: actorID,
|
|
UpdatedBy: actorID,
|
|
SourceFile: sourceFile,
|
|
Position: 4,
|
|
IsMandatory: false,
|
|
Section: helicopterfile.SectionBeforeFirstFlightInspection,
|
|
UpdatedAt: time.Unix(100, 0).UTC(),
|
|
CreatedAt: time.Unix(90, 0).UTC(),
|
|
FileAttachmentID: nil,
|
|
},
|
|
}, nil
|
|
},
|
|
updateFn: func(_ context.Context, row *helicopterfile.HelicopterFile) error {
|
|
if row == nil {
|
|
t.Fatal("expected row to be updated")
|
|
}
|
|
if len(row.FileAttachmentID) != 16 {
|
|
t.Fatalf("expected attachment id to be set, got %d bytes", len(row.FileAttachmentID))
|
|
}
|
|
if len(row.SourceFileID) != 0 {
|
|
t.Fatalf("expected source file id to be cleared, got %d bytes", len(row.SourceFileID))
|
|
}
|
|
return nil
|
|
},
|
|
}
|
|
|
|
fm := &helicopterFileServiceManagerStub{
|
|
createAttachmentFn: func(_ context.Context, params filemanager.CreateAttachmentParams) (*filemanager.Attachment, error) {
|
|
if got, want := uuidStringOrFail(t, params.FileID), sourceFileUUID; got != want {
|
|
t.Fatalf("unexpected file id: got %s want %s", got, want)
|
|
}
|
|
return &filemanager.Attachment{
|
|
ID: attachmentID,
|
|
FileID: sourceFileID,
|
|
File: sourceFile,
|
|
}, nil
|
|
},
|
|
getAttachmentByIDFn: func(_ context.Context, id []byte) (*filemanager.Attachment, error) {
|
|
if got, want := uuidStringOrFail(t, id), uuidStringOrFail(t, attachmentID); got != want {
|
|
t.Fatalf("unexpected attachment lookup id: got %s want %s", got, want)
|
|
}
|
|
return &filemanager.Attachment{
|
|
ID: attachmentID,
|
|
FileID: sourceFileID,
|
|
File: sourceFile,
|
|
}, nil
|
|
},
|
|
}
|
|
events := &helicopterFileServiceEventsStub{}
|
|
|
|
svc := NewHelicopterFileService(repo).
|
|
WithFileManagerService(fm).
|
|
WithHelicopterFileEvents(events)
|
|
|
|
finalized, err := svc.FinalizePendingAttachmentsBySourceFileUUID(context.Background(), sourceFileUUID, 1)
|
|
if err != nil {
|
|
t.Fatalf("FinalizePendingAttachmentsBySourceFileUUID returned error: %v", err)
|
|
}
|
|
if finalized != 1 {
|
|
t.Fatalf("expected one finalized attachment, got %d", finalized)
|
|
}
|
|
if len(fm.createAttachmentArgs) != 1 {
|
|
t.Fatalf("expected one attachment create call, got %d", len(fm.createAttachmentArgs))
|
|
}
|
|
if len(fm.markFileActiveArgs) != 1 {
|
|
t.Fatalf("expected one mark active call, got %d", len(fm.markFileActiveArgs))
|
|
}
|
|
if events.event == nil {
|
|
t.Fatal("expected helicopter file event to be published")
|
|
}
|
|
if events.event.FileID != uuidStringOrFail(t, attachmentID) {
|
|
t.Fatalf("expected finalized event to point to attachment id, got %+v", events.event)
|
|
}
|
|
if events.event.AttachmentPending {
|
|
t.Fatalf("expected finalized event to mark attachment pending false, got %+v", events.event)
|
|
}
|
|
}
|
|
|
|
func uuidStringOrFail(t *testing.T, raw []byte) string {
|
|
t.Helper()
|
|
out, err := uuidv7.BytesToString(raw)
|
|
if err != nil {
|
|
t.Fatalf("convert uuid: %v", err)
|
|
}
|
|
return out
|
|
}
|