Files
supply-intelligence/internal/publish/service_postgres_tx_test.go
2026-05-12 18:49:52 +08:00

104 lines
3.4 KiB
Go

package publish_test
import (
"context"
"testing"
"time"
"supply-intelligence/internal/domain"
"supply-intelligence/internal/publish"
)
type txCaptureRepo struct {
candidate domain.DiscoveryCandidate
pkg domain.SupplyPackage
event domain.PackageChangeEvent
publishCalled bool
}
func (r *txCaptureRepo) AppendPackageEventContext(ctx context.Context, evt domain.PackageChangeEvent) (domain.PackageChangeEvent, error) {
panic("AppendPackageEventContext should not be called directly when publish transaction is supported")
}
func (r *txCaptureRepo) GetLatestDiscoveryCandidateContext(ctx context.Context, platform, model string) (domain.DiscoveryCandidate, bool) {
return r.candidate, r.candidate.Platform == platform && r.candidate.Model == model
}
func (r *txCaptureRepo) UpdateCandidateStatus(ctx context.Context, candidateID string, status domain.DiscoveryCandidateStatus, failureCode, failureSummary string) error {
panic("UpdateCandidateStatus should not be called directly when publish transaction is supported")
}
func (r *txCaptureRepo) GetSupplyPackage(ctx context.Context, platform, model string) (domain.SupplyPackage, bool) {
return r.pkg, r.pkg.Platform == platform && r.pkg.Model == model
}
func (r *txCaptureRepo) UpsertSupplyPackage(ctx context.Context, pkg domain.SupplyPackage) error {
panic("UpsertSupplyPackage should not be called directly when publish transaction is supported")
}
func (r *txCaptureRepo) PublishPackageAtomically(ctx context.Context, input publish.PublishPackageAtomicInput) (publish.PublishPackageAtomicResult, error) {
r.publishCalled = true
r.event = input.Event
r.candidate = input.Candidate
r.pkg = input.Package
return publish.PublishPackageAtomicResult{
Candidate: input.Candidate,
Package: input.Package,
Event: input.Event,
}, nil
}
func TestServicePublishDraftUsesAtomicPublisherWhenAvailable(t *testing.T) {
repo := &txCaptureRepo{
candidate: domain.DiscoveryCandidate{
CandidateID: "cand-atomic",
AccountID: 9001,
Platform: "openai",
Model: "gpt-4.1-mini",
Source: "admission",
Status: domain.DiscoveryCandidateStatusTestPassed,
DiscoveredAt: time.Unix(100, 0).UTC(),
UpdatedAt: time.Unix(110, 0).UTC(),
Version: 2,
},
pkg: domain.SupplyPackage{
PackageID: 88,
Platform: "openai",
Model: "gpt-4.1-mini",
Status: "draft",
Source: "admission",
CreatedAt: time.Unix(90, 0).UTC(),
UpdatedAt: time.Unix(110, 0).UTC(),
Version: 5,
},
}
service := publish.NewService(repo)
now := time.Unix(200, 0).UTC()
out, err := service.PublishDraft(context.Background(), publish.PublishDraftInput{
EventID: "evt-atomic-1",
Platform: "openai",
Model: "gpt-4.1-mini",
OccurredAt: now,
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !repo.publishCalled {
t.Fatal("expected atomic publish path to be used")
}
if out.Candidate.Status != domain.DiscoveryCandidateStatusPublished {
t.Fatalf("expected published candidate, got %+v", out.Candidate)
}
if out.Package.Status != "active" {
t.Fatalf("expected active package, got %+v", out.Package)
}
if out.Event.EventID != "evt-atomic-1" || out.Event.GatewaySyncStatus != domain.GatewaySyncStatusPending {
t.Fatalf("unexpected event: %+v", out.Event)
}
if out.Package.Version != 6 {
t.Fatalf("expected package version incremented, got %+v", out.Package)
}
}