Files
fm_be/internal/service/easa_release_service_test.go
2026-07-16 22:16:45 +07:00

174 lines
6.0 KiB
Go

package service
import (
"context"
"errors"
"testing"
"time"
easarelease "wucher/internal/domain/easa_release"
)
type stubEASARepo struct {
row *easarelease.EASARelease
updated *easarelease.EASARelease
created *easarelease.EASARelease
voidedID []byte
createErr error
getErr error
voidErr error
}
func (s *stubEASARepo) Create(_ context.Context, row *easarelease.EASARelease) error {
s.created = row
if len(row.ID) == 0 {
row.ID = []byte("newid0123456789a")
}
return s.createErr
}
func (s *stubEASARepo) Update(_ context.Context, row *easarelease.EASARelease) error {
s.updated = row
return nil
}
func (s *stubEASARepo) Delete(_ context.Context, _, _ []byte) error { return nil }
func (s *stubEASARepo) GetByID(_ context.Context, _ []byte) (*easarelease.EASARelease, error) {
return s.row, s.getErr
}
func (s *stubEASARepo) GetByFlightID(_ context.Context, _ []byte) (*easarelease.EASARelease, error) {
return s.row, s.getErr
}
func (s *stubEASARepo) GetByComplaintID(_ context.Context, _ []byte) (*easarelease.EASARelease, error) {
return s.row, s.getErr
}
func (s *stubEASARepo) ListByHelicopter(_ context.Context, _ []byte) ([]easarelease.EASARelease, error) {
if s.row != nil {
return []easarelease.EASARelease{*s.row}, nil
}
return nil, nil
}
func (s *stubEASARepo) GetLatestByHelicopter(_ context.Context, _ []byte) (*easarelease.EASARelease, error) {
return s.row, nil
}
func (s *stubEASARepo) GetActiveByHelicopter(_ context.Context, _ []byte) (*easarelease.EASARelease, error) {
return s.row, nil
}
func (s *stubEASARepo) VoidByID(_ context.Context, id []byte, _ string, _ []byte) error {
s.voidedID = id
return s.voidErr
}
func completeUnsigned() *easarelease.EASARelease {
now := time.Now()
return &easarelease.EASARelease{
ID: []byte("0123456789abcdef"),
HelicopterID: []byte("fedcba9876543210"),
EASADate: &now,
EASAACHours: ptr("1245.3"),
EASALocation: ptr("LOWI"),
EASAWONo: ptr("WO-1"),
EASASignerID: ptr("019d61db-53c6-7280-87ec-e65f205c6d3b"),
}
}
func TestEASAReleaseServiceSign(t *testing.T) {
actor := []byte("aaaaaaaaaaaaaaaa")
ctx := context.Background()
if err := NewEASAReleaseService(&stubEASARepo{row: nil}).Sign(ctx, []byte("x"), actor); !errors.Is(err, easarelease.ErrNotFound) {
t.Fatalf("want ErrNotFound, got %v", err)
}
incompleteRepo := &stubEASARepo{row: &easarelease.EASARelease{ID: []byte("0123456789abcdef")}}
if err := NewEASAReleaseService(incompleteRepo).Sign(ctx, incompleteRepo.row.ID, actor); !errors.Is(err, easarelease.ErrIncompleteForSign) {
t.Fatalf("want ErrIncompleteForSign, got %v", err)
}
if incompleteRepo.updated != nil {
t.Fatal("incomplete release must not be persisted signed")
}
signed := completeUnsigned()
at := time.Now()
signed.SignedAt = &at
if err := NewEASAReleaseService(&stubEASARepo{row: signed}).Sign(ctx, signed.ID, actor); !errors.Is(err, easarelease.ErrAlreadySigned) {
t.Fatalf("want ErrAlreadySigned, got %v", err)
}
okRepo := &stubEASARepo{row: completeUnsigned()}
if err := NewEASAReleaseService(okRepo).Sign(ctx, okRepo.row.ID, actor); err != nil {
t.Fatalf("unexpected err: %v", err)
}
if okRepo.updated == nil || okRepo.updated.SignedAt == nil || string(okRepo.updated.SignedBy) != string(actor) {
t.Fatal("complete release should be persisted signed by actor")
}
}
func TestEASAReleaseServiceAmendAndDelegation(t *testing.T) {
ctx := context.Background()
repo := &stubEASARepo{row: completeUnsigned()}
svc := NewEASAReleaseService(repo)
newID, err := svc.Amend(ctx, repo.row.ID, "superseded", []byte("actor"))
if err != nil {
t.Fatalf("Amend err: %v", err)
}
if string(repo.voidedID) != string(repo.row.ID) {
t.Fatal("Amend should void the current release")
}
if repo.created == nil || string(repo.created.HelicopterID) != string(repo.row.HelicopterID) {
t.Fatal("Amend should create a copy for the same helicopter")
}
if len(newID) == 0 {
t.Fatal("Amend should return the new id")
}
if _, err := svc.GetLatestByHelicopter(ctx, []byte("h")); err != nil {
t.Fatalf("GetLatestByHelicopter: %v", err)
}
if _, err := svc.GetActiveByHelicopter(ctx, []byte("h")); err != nil {
t.Fatalf("GetActiveByHelicopter: %v", err)
}
if rows, err := svc.ListByHelicopter(ctx, []byte("h")); err != nil || len(rows) != 1 {
t.Fatalf("ListByHelicopter: %v", err)
}
if err := svc.Delete(ctx, []byte("x"), nil); err != nil {
t.Fatalf("Delete: %v", err)
}
if _, err := svc.GetByID(ctx, []byte("x")); err != nil {
t.Fatalf("GetByID: %v", err)
}
// Amend on missing release.
if _, err := NewEASAReleaseService(&stubEASARepo{row: nil}).Amend(ctx, []byte("x"), "r", nil); !errors.Is(err, easarelease.ErrNotFound) {
t.Fatalf("Amend missing: want ErrNotFound, got %v", err)
}
// Amend with void error.
if _, err := NewEASAReleaseService(&stubEASARepo{row: completeUnsigned(), voidErr: errors.New("boom")}).Amend(ctx, []byte("x"), "r", nil); err == nil {
t.Fatal("Amend should propagate void error")
}
// Amend with create error.
if _, err := NewEASAReleaseService(&stubEASARepo{row: completeUnsigned(), createErr: errors.New("boom")}).Amend(ctx, []byte("x"), "r", nil); err == nil {
t.Fatal("Amend should propagate create error")
}
// Amend with GetByID error.
if _, err := NewEASAReleaseService(&stubEASARepo{getErr: errors.New("boom")}).Amend(ctx, []byte("x"), "r", nil); err == nil {
t.Fatal("Amend should propagate GetByID error")
}
}
func TestEASAReleaseServiceCreateUpdateAndErrors(t *testing.T) {
ctx := context.Background()
repo := &stubEASARepo{}
svc := NewEASAReleaseService(repo)
row := completeUnsigned()
if err := svc.Create(ctx, row); err != nil || repo.created != row {
t.Fatalf("Create not delegated: %v", err)
}
if err := svc.Update(ctx, row); err != nil || repo.updated != row {
t.Fatalf("Update not delegated: %v", err)
}
// Sign with GetByID error.
if err := NewEASAReleaseService(&stubEASARepo{getErr: errors.New("boom")}).Sign(ctx, []byte("x"), nil); err == nil {
t.Fatal("Sign should propagate GetByID error")
}
}