230 lines
9.0 KiB
Go
230 lines
9.0 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"supply-intelligence/internal/admission"
|
|
"supply-intelligence/internal/discovery"
|
|
"supply-intelligence/internal/domain"
|
|
"supply-intelligence/internal/gatewayconsumer"
|
|
"supply-intelligence/internal/probe"
|
|
"supply-intelligence/internal/publish"
|
|
"supply-intelligence/internal/repository"
|
|
)
|
|
|
|
func TestAdmissionStateEndpointReturnsCurrentCandidateAndPackageTruth(t *testing.T) {
|
|
repo := repository.NewMemoryRepository()
|
|
repo.UpsertDiscoveryCandidateContext(nil, domain.DiscoveryCandidate{
|
|
CandidateID: "cand-1",
|
|
AccountID: 301,
|
|
Platform: "openai",
|
|
Model: "gpt-4.1-mini",
|
|
Source: "manual_seed",
|
|
Status: domain.DiscoveryCandidateStatusDiscovered,
|
|
ReasonCode: "earlier_state",
|
|
DiscoveredAt: time.Unix(90, 0).UTC(),
|
|
UpdatedAt: time.Unix(90, 0).UTC(),
|
|
Version: 1,
|
|
})
|
|
repo.UpsertDiscoveryCandidateContext(nil, domain.DiscoveryCandidate{
|
|
CandidateID: "cand-2",
|
|
AccountID: 301,
|
|
Platform: "openai",
|
|
Model: "gpt-4.1-mini",
|
|
Source: "manual_seed",
|
|
Status: domain.DiscoveryCandidateStatusTestPassed,
|
|
ReasonCode: "ready_for_package",
|
|
DiscoveredAt: time.Unix(100, 0).UTC(),
|
|
UpdatedAt: time.Unix(110, 0).UTC(),
|
|
Version: 2,
|
|
})
|
|
repo.UpsertSupplyPackage(nil, domain.SupplyPackage{
|
|
PackageID: 9,
|
|
Platform: "openai",
|
|
Model: "gpt-4.1-mini",
|
|
Status: "draft",
|
|
Source: "manual_seed",
|
|
})
|
|
_, _ = repo.AppendPackageEventContext(nil, domain.PackageChangeEvent{
|
|
EventID: "evt-other-newer",
|
|
EventType: publish.PackagePublishedEventType,
|
|
PackageID: 10,
|
|
Platform: "openai",
|
|
Model: "gpt-4.1",
|
|
OccurredAt: time.Unix(130, 0).UTC(),
|
|
Version: 1,
|
|
GatewaySyncStatus: domain.GatewaySyncStatusFailed,
|
|
})
|
|
_, _ = repo.AppendPackageEventContext(nil, domain.PackageChangeEvent{
|
|
EventID: "evt-old",
|
|
EventType: publish.PackagePublishedEventType,
|
|
PackageID: 9,
|
|
Platform: "openai",
|
|
Model: "gpt-4.1-mini",
|
|
OccurredAt: time.Unix(100, 0).UTC(),
|
|
Version: 1,
|
|
GatewaySyncStatus: domain.GatewaySyncStatusPending,
|
|
})
|
|
_, _ = repo.AppendPackageEventContext(nil, domain.PackageChangeEvent{
|
|
EventID: "evt-latest",
|
|
EventType: publish.PackagePublishedEventType,
|
|
PackageID: 9,
|
|
Platform: "openai",
|
|
Model: "gpt-4.1-mini",
|
|
OccurredAt: time.Unix(120, 0).UTC(),
|
|
Version: 2,
|
|
GatewaySyncStatus: domain.GatewaySyncStatusApplied,
|
|
})
|
|
server := NewServer(repo, probe.NewService(repo), publish.NewService(repo), gatewayconsumer.NewService(repo), nil, discovery.NewService(repo), admission.NewService(nil, nil, []admission.TestSuite{}, nil, nil), nil, nil)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/internal/supply-intelligence/models/openai/gpt-4.1-mini/admission-state", nil)
|
|
rr := httptest.NewRecorder()
|
|
server.Routes().ServeHTTP(rr, req)
|
|
|
|
if rr.Code != http.StatusOK {
|
|
t.Fatalf("expected implemented admission-state endpoint, got status=%d body=%s", rr.Code, rr.Body.String())
|
|
}
|
|
|
|
var body struct {
|
|
Platform string `json:"platform"`
|
|
Model string `json:"model"`
|
|
Candidate *domain.DiscoveryCandidate `json:"candidate"`
|
|
Package *domain.SupplyPackage `json:"package"`
|
|
GatewaySyncStatus domain.GatewaySyncStatus `json:"gateway_sync_status"`
|
|
LastEvent *domain.PackageChangeEvent `json:"last_event"`
|
|
}
|
|
if err := json.NewDecoder(rr.Body).Decode(&body); err != nil {
|
|
t.Fatalf("decode response: %v", err)
|
|
}
|
|
if body.Candidate == nil || body.Candidate.CandidateID != "cand-2" || body.Candidate.Status != domain.DiscoveryCandidateStatusTestPassed {
|
|
t.Fatalf("expected latest candidate truth, got %+v", body.Candidate)
|
|
}
|
|
if body.Package == nil || body.Package.Status != "draft" {
|
|
t.Fatalf("expected package truth, got %+v", body.Package)
|
|
}
|
|
if body.LastEvent == nil || body.LastEvent.EventID != "evt-latest" {
|
|
t.Fatalf("expected latest matching event truth, got %+v", body.LastEvent)
|
|
}
|
|
if body.GatewaySyncStatus != domain.GatewaySyncStatusApplied {
|
|
t.Fatalf("expected gateway sync status from latest matching event, got %q", body.GatewaySyncStatus)
|
|
}
|
|
}
|
|
|
|
func TestAdmissionStateEndpointReflectsPublishTransitionAndAck(t *testing.T) {
|
|
repo := repository.NewMemoryRepository()
|
|
repo.UpsertDiscoveryCandidateContext(nil, domain.DiscoveryCandidate{
|
|
CandidateID: "cand-publish",
|
|
AccountID: 401,
|
|
Platform: "openai",
|
|
Model: "gpt-4.1-mini",
|
|
Source: "manual_seed",
|
|
Status: domain.DiscoveryCandidateStatusTestPassed,
|
|
DiscoveredAt: time.Unix(100, 0).UTC(),
|
|
UpdatedAt: time.Unix(110, 0).UTC(),
|
|
Version: 2,
|
|
})
|
|
repo.UpsertSupplyPackage(nil, domain.SupplyPackage{
|
|
PackageID: 21,
|
|
Platform: "openai",
|
|
Model: "gpt-4.1-mini",
|
|
Status: "draft",
|
|
Source: "manual_seed",
|
|
UpdatedAt: time.Unix(110, 0).UTC(),
|
|
Version: 1,
|
|
})
|
|
publishService := publish.NewService(repo)
|
|
if _, err := publishService.PublishDraft(nil, publish.PublishDraftInput{EventID: "evt-publish", Platform: "openai", Model: "gpt-4.1-mini", OccurredAt: time.Unix(120, 0).UTC()}); err != nil {
|
|
t.Fatalf("publish draft: %v", err)
|
|
}
|
|
server := NewServer(repo, probe.NewService(repo), publishService, gatewayconsumer.NewService(repo), nil, discovery.NewService(repo), admission.NewService(nil, nil, []admission.TestSuite{}, nil, nil), nil, nil)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/internal/supply-intelligence/models/openai/gpt-4.1-mini/admission-state", nil)
|
|
rr := httptest.NewRecorder()
|
|
server.Routes().ServeHTTP(rr, req)
|
|
if rr.Code != http.StatusOK {
|
|
t.Fatalf("expected status 200, got=%d body=%s", rr.Code, rr.Body.String())
|
|
}
|
|
var body struct {
|
|
Candidate *domain.DiscoveryCandidate `json:"candidate"`
|
|
Package *domain.SupplyPackage `json:"package"`
|
|
GatewaySyncStatus domain.GatewaySyncStatus `json:"gateway_sync_status"`
|
|
}
|
|
if err := json.NewDecoder(rr.Body).Decode(&body); err != nil {
|
|
t.Fatalf("decode response: %v", err)
|
|
}
|
|
if body.Candidate == nil || body.Candidate.Status != domain.DiscoveryCandidateStatusPublished {
|
|
t.Fatalf("expected published candidate, got %+v", body.Candidate)
|
|
}
|
|
if body.Package == nil || body.Package.Status != "active" {
|
|
t.Fatalf("expected active package, got %+v", body.Package)
|
|
}
|
|
if body.GatewaySyncStatus != domain.GatewaySyncStatusPending {
|
|
t.Fatalf("expected pending sync status, got %q", body.GatewaySyncStatus)
|
|
}
|
|
|
|
_, err := repo.AckPackageEvent(nil, "evt-publish", "gateway", domain.GatewayAckResultApplied, "ok", time.Unix(130, 0).UTC())
|
|
if err != nil {
|
|
t.Fatalf("ack event: %v", err)
|
|
}
|
|
ackedReq := httptest.NewRequest(http.MethodGet, "/internal/supply-intelligence/models/openai/gpt-4.1-mini/admission-state", nil)
|
|
ackedRR := httptest.NewRecorder()
|
|
server.Routes().ServeHTTP(ackedRR, ackedReq)
|
|
var ackedBody struct {
|
|
GatewaySyncStatus domain.GatewaySyncStatus `json:"gateway_sync_status"`
|
|
}
|
|
if err := json.NewDecoder(ackedRR.Body).Decode(&ackedBody); err != nil {
|
|
t.Fatalf("decode acked response: %v", err)
|
|
}
|
|
if ackedBody.GatewaySyncStatus != domain.GatewaySyncStatusApplied {
|
|
t.Fatalf("expected applied sync status after ack, got %q", ackedBody.GatewaySyncStatus)
|
|
}
|
|
}
|
|
|
|
func TestAdmissionStateEndpointOmitsForeignLatestEvent(t *testing.T) {
|
|
repo := repository.NewMemoryRepository()
|
|
repo.UpsertSupplyPackage(nil, domain.SupplyPackage{
|
|
PackageID: 9,
|
|
Platform: "openai",
|
|
Model: "gpt-4.1-mini",
|
|
Status: "draft",
|
|
Source: "manual_seed",
|
|
})
|
|
_, _ = repo.AppendPackageEventContext(nil, domain.PackageChangeEvent{
|
|
EventID: "evt-only-other-model",
|
|
EventType: publish.PackagePublishedEventType,
|
|
PackageID: 10,
|
|
Platform: "openai",
|
|
Model: "gpt-4.1",
|
|
OccurredAt: time.Unix(130, 0).UTC(),
|
|
Version: 1,
|
|
GatewaySyncStatus: domain.GatewaySyncStatusFailed,
|
|
})
|
|
server := NewServer(repo, probe.NewService(repo), publish.NewService(repo), gatewayconsumer.NewService(repo), nil, discovery.NewService(repo), admission.NewService(nil, nil, []admission.TestSuite{}, nil, nil), nil, nil)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/internal/supply-intelligence/models/openai/gpt-4.1-mini/admission-state", nil)
|
|
rr := httptest.NewRecorder()
|
|
server.Routes().ServeHTTP(rr, req)
|
|
|
|
if rr.Code != http.StatusOK {
|
|
t.Fatalf("expected implemented admission-state endpoint, got status=%d body=%s", rr.Code, rr.Body.String())
|
|
}
|
|
|
|
var body struct {
|
|
GatewaySyncStatus domain.GatewaySyncStatus `json:"gateway_sync_status"`
|
|
LastEvent *domain.PackageChangeEvent `json:"last_event"`
|
|
}
|
|
if err := json.NewDecoder(rr.Body).Decode(&body); err != nil {
|
|
t.Fatalf("decode response: %v", err)
|
|
}
|
|
if body.LastEvent != nil {
|
|
t.Fatalf("expected no last event for unrelated latest event, got %+v", body.LastEvent)
|
|
}
|
|
if body.GatewaySyncStatus != "" {
|
|
t.Fatalf("expected empty gateway sync status without matching event, got %q", body.GatewaySyncStatus)
|
|
}
|
|
}
|