469 lines
18 KiB
Go
469 lines
18 KiB
Go
package sqlite
|
|
|
|
import (
|
|
"context"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestRunStateStore(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx := context.Background()
|
|
store := openTestDB(t)
|
|
|
|
run := ImportRun{
|
|
RunID: "run-1",
|
|
HostID: "host-1",
|
|
Mode: "strict",
|
|
AccessMode: "subscription",
|
|
SubscriptionUsersJSON: `["user-1"]`,
|
|
SubscriptionDays: 30,
|
|
ProbeAPIKey: "probe-key",
|
|
State: "running",
|
|
TotalItems: 1,
|
|
}
|
|
if err := store.ImportRuns().Create(ctx, run); err != nil {
|
|
t.Fatalf("ImportRuns().Create() error = %v", err)
|
|
}
|
|
|
|
run.State = "completed_with_warnings"
|
|
run.CompletedItems = 1
|
|
run.ActiveItems = 1
|
|
run.WarningItems = 1
|
|
run.FinishedAt = "2026-05-22T12:00:00Z"
|
|
if err := store.ImportRuns().Update(ctx, run); err != nil {
|
|
t.Fatalf("ImportRuns().Update() error = %v", err)
|
|
}
|
|
|
|
gotRun, err := store.ImportRuns().GetByRunID(ctx, "run-1")
|
|
if err != nil {
|
|
t.Fatalf("ImportRuns().GetByRunID() error = %v", err)
|
|
}
|
|
if gotRun.State != "completed_with_warnings" {
|
|
t.Fatalf("run.State = %q, want completed_with_warnings", gotRun.State)
|
|
}
|
|
if gotRun.WarningItems != 1 {
|
|
t.Fatalf("run.WarningItems = %d, want 1", gotRun.WarningItems)
|
|
}
|
|
if gotRun.HostID != "host-1" {
|
|
t.Fatalf("run.HostID = %q, want host-1", gotRun.HostID)
|
|
}
|
|
if gotRun.SubscriptionUsersJSON != `["user-1"]` {
|
|
t.Fatalf("run.SubscriptionUsersJSON = %q, want persisted subscription users", gotRun.SubscriptionUsersJSON)
|
|
}
|
|
if gotRun.SubscriptionDays != 30 {
|
|
t.Fatalf("run.SubscriptionDays = %d, want 30", gotRun.SubscriptionDays)
|
|
}
|
|
if gotRun.ProbeAPIKey != "probe-key" {
|
|
t.Fatalf("run.ProbeAPIKey = %q, want probe-key", gotRun.ProbeAPIKey)
|
|
}
|
|
|
|
legacyBatchID := int64(88)
|
|
reusedAccountID := int64(321)
|
|
channelID := int64(66)
|
|
accountID := int64(77)
|
|
|
|
item := ImportRunItem{
|
|
ItemID: "item-1",
|
|
RunID: "run-1",
|
|
BaseURL: "https://api.deepseek.com/v1",
|
|
ProviderID: "api-deepseek-12345678",
|
|
APIKeyFingerprint: "fp_abc123",
|
|
RequestedModelsJSON: `["kimi 2.6"]`,
|
|
RawModelsJSON: `["kimi-k2.6"]`,
|
|
NormalizedModelsJSON: `["kimi-k2.6"]`,
|
|
CanonicalFamiliesJSON: `["kimi-2.6"]`,
|
|
RecommendedModelsJSON: `["kimi-k2.6"]`,
|
|
CurrentStage: "confirm",
|
|
ConfirmationStatus: "pending",
|
|
AccessStatus: "unknown",
|
|
MatchedAccountState: "deprecated",
|
|
AccountResolution: "reactivated",
|
|
ProvisionReused: true,
|
|
ReusedFromProviderID: "api-deepseek-87654321",
|
|
ReusedFromAccountID: &reusedAccountID,
|
|
ChannelID: &channelID,
|
|
AccountID: &accountID,
|
|
RetryCount: 2,
|
|
ConfirmationAttempts: 3,
|
|
LastRetryAt: "2026-05-22T12:01:00Z",
|
|
NextRetryAt: "2026-05-22T12:02:00Z",
|
|
LeaseOwner: "worker-1",
|
|
LeaseUntil: "2026-05-22T12:03:00Z",
|
|
AdvisoryMessagesJSON: `["warmup"]`,
|
|
LastErrorStage: "confirm",
|
|
LastError: "no available accounts",
|
|
LegacyBatchID: &legacyBatchID,
|
|
LegacyProviderID: "legacy-provider",
|
|
CapabilityProfileJSON: `{"transport_profile":{"supports_openai_chat_completions":true}}`,
|
|
ResolvedSmokeModel: "kimi-k2.6",
|
|
}
|
|
|
|
if err := store.ImportRunItems().Upsert(ctx, item); err != nil {
|
|
t.Fatalf("ImportRunItems().Upsert() error = %v", err)
|
|
}
|
|
|
|
gotItem, err := store.ImportRunItems().GetByItemID(ctx, "item-1")
|
|
if err != nil {
|
|
t.Fatalf("ImportRunItems().GetByItemID() error = %v", err)
|
|
}
|
|
if gotItem.APIKeyFingerprint != "fp_abc123" {
|
|
t.Fatalf("item.APIKeyFingerprint = %q, want fp_abc123", gotItem.APIKeyFingerprint)
|
|
}
|
|
if gotItem.CanonicalFamiliesJSON != `["kimi-2.6"]` {
|
|
t.Fatalf("item.CanonicalFamiliesJSON = %q, want canonical families json", gotItem.CanonicalFamiliesJSON)
|
|
}
|
|
if gotItem.MatchedAccountState != "deprecated" {
|
|
t.Fatalf("item.MatchedAccountState = %q, want deprecated", gotItem.MatchedAccountState)
|
|
}
|
|
if gotItem.AccountResolution != "reactivated" {
|
|
t.Fatalf("item.AccountResolution = %q, want reactivated", gotItem.AccountResolution)
|
|
}
|
|
if !gotItem.ProvisionReused {
|
|
t.Fatal("item.ProvisionReused = false, want true")
|
|
}
|
|
if gotItem.ReusedFromProviderID != "api-deepseek-87654321" {
|
|
t.Fatalf("item.ReusedFromProviderID = %q, want reused provider id", gotItem.ReusedFromProviderID)
|
|
}
|
|
if gotItem.ReusedFromAccountID == nil || *gotItem.ReusedFromAccountID != reusedAccountID {
|
|
t.Fatalf("item.ReusedFromAccountID = %#v, want %d", gotItem.ReusedFromAccountID, reusedAccountID)
|
|
}
|
|
if gotItem.LeaseOwner != "worker-1" || gotItem.LeaseUntil != "2026-05-22T12:03:00Z" {
|
|
t.Fatalf("lease = (%q, %q), want persisted lease fields", gotItem.LeaseOwner, gotItem.LeaseUntil)
|
|
}
|
|
|
|
event := ImportRunItemEvent{
|
|
EventID: "evt-1",
|
|
RunID: "run-1",
|
|
ItemID: "item-1",
|
|
EventType: "retry_scheduled",
|
|
Stage: "confirm",
|
|
Attempt: 2,
|
|
Message: "retry after warmup",
|
|
PayloadJSON: `{"next_retry_at":"2026-05-22T12:02:00Z"}`,
|
|
}
|
|
if err := store.ImportRunEvents().Append(ctx, event); err != nil {
|
|
t.Fatalf("ImportRunEvents().Append() error = %v", err)
|
|
}
|
|
|
|
events, err := store.ImportRunEvents().ListByItemID(ctx, "item-1")
|
|
if err != nil {
|
|
t.Fatalf("ImportRunEvents().ListByItemID() error = %v", err)
|
|
}
|
|
if len(events) != 1 {
|
|
t.Fatalf("len(events) = %d, want 1", len(events))
|
|
}
|
|
if events[0].EventType != "retry_scheduled" {
|
|
t.Fatalf("events[0].EventType = %q, want retry_scheduled", events[0].EventType)
|
|
}
|
|
|
|
items, err := store.ImportRunItems().ListByRunID(ctx, "run-1")
|
|
if err != nil {
|
|
t.Fatalf("ImportRunItems().ListByRunID() error = %v", err)
|
|
}
|
|
if len(items) != 1 {
|
|
t.Fatalf("len(items) = %d, want 1", len(items))
|
|
}
|
|
if !reflect.DeepEqual(items[0].AdvisoryMessagesJSON, `["warmup"]`) {
|
|
t.Fatalf("items[0].AdvisoryMessagesJSON = %q, want advisory json", items[0].AdvisoryMessagesJSON)
|
|
}
|
|
}
|
|
|
|
func TestImportRunsRepoList(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx := context.Background()
|
|
store := openTestDB(t)
|
|
|
|
for _, run := range []ImportRun{
|
|
{RunID: "run-a", HostID: "host-a", Mode: "strict", AccessMode: "subscription", State: "running"},
|
|
{RunID: "run-b", HostID: "host-b", Mode: "partial", AccessMode: "self_service", State: "completed"},
|
|
} {
|
|
if err := store.ImportRuns().Create(ctx, run); err != nil {
|
|
t.Fatalf("ImportRuns().Create(%q) error = %v", run.RunID, err)
|
|
}
|
|
}
|
|
|
|
runs, err := store.ImportRuns().List(ctx, 1)
|
|
if err != nil {
|
|
t.Fatalf("ImportRuns().List(limit=1) error = %v", err)
|
|
}
|
|
if len(runs) != 1 {
|
|
t.Fatalf("ImportRuns().List(limit=1) len = %d, want 1", len(runs))
|
|
}
|
|
|
|
runs, err = store.ImportRuns().List(ctx, 0)
|
|
if err != nil {
|
|
t.Fatalf("ImportRuns().List(limit=0) error = %v", err)
|
|
}
|
|
if len(runs) != 2 {
|
|
t.Fatalf("ImportRuns().List(limit=0) len = %d, want 2", len(runs))
|
|
}
|
|
}
|
|
|
|
func TestImportRunItemsRepoCreateUpdateAndLease(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx := context.Background()
|
|
store := openTestDB(t)
|
|
|
|
run := ImportRun{RunID: "run-lease", HostID: "host-lease", Mode: "strict", AccessMode: "subscription", State: "running"}
|
|
if err := store.ImportRuns().Create(ctx, run); err != nil {
|
|
t.Fatalf("ImportRuns().Create() error = %v", err)
|
|
}
|
|
|
|
item := ImportRunItem{
|
|
ItemID: "item-lease",
|
|
RunID: "run-lease",
|
|
BaseURL: "https://api.example.com/v1",
|
|
ProviderID: "provider-lease",
|
|
APIKeyFingerprint: "fp_lease",
|
|
CurrentStage: "confirm",
|
|
ConfirmationStatus: "pending",
|
|
AccessStatus: "unknown",
|
|
MatchedAccountState: "active",
|
|
AccountResolution: "created",
|
|
RequestedModelsJSON: `["model-a"]`,
|
|
AdvisoryMessagesJSON: `["first"]`,
|
|
}
|
|
if err := store.ImportRunItems().Create(ctx, item); err != nil {
|
|
t.Fatalf("ImportRunItems().Create() error = %v", err)
|
|
}
|
|
|
|
item.ConfirmationStatus = "confirmed"
|
|
item.CurrentStage = "validate"
|
|
item.AccessStatus = "active"
|
|
item.AdvisoryMessagesJSON = `["updated"]`
|
|
if err := store.ImportRunItems().Update(ctx, item); err != nil {
|
|
t.Fatalf("ImportRunItems().Update() error = %v", err)
|
|
}
|
|
|
|
got, err := store.ImportRunItems().GetByItemID(ctx, "item-lease")
|
|
if err != nil {
|
|
t.Fatalf("ImportRunItems().GetByItemID() error = %v", err)
|
|
}
|
|
if got.CurrentStage != "validate" || got.ConfirmationStatus != "confirmed" {
|
|
t.Fatalf("updated item = %+v, want validate/confirmed", got)
|
|
}
|
|
|
|
leaseItem := item
|
|
leaseItem.ItemID = "item-pending"
|
|
leaseItem.CurrentStage = "confirm"
|
|
leaseItem.ConfirmationStatus = "pending"
|
|
leaseItem.AccessStatus = "unknown"
|
|
if err := store.ImportRunItems().Create(ctx, leaseItem); err != nil {
|
|
t.Fatalf("ImportRunItems().Create(item-pending) error = %v", err)
|
|
}
|
|
|
|
now := time.Date(2026, 5, 23, 1, 2, 3, 0, time.UTC)
|
|
leased, ok, err := store.ImportRunItems().TryAcquireConfirmationLease(ctx, "item-pending", "worker-1", now, 2*time.Minute)
|
|
if err != nil {
|
|
t.Fatalf("TryAcquireConfirmationLease() error = %v", err)
|
|
}
|
|
if !ok {
|
|
t.Fatal("TryAcquireConfirmationLease() ok = false, want true")
|
|
}
|
|
if leased.LeaseOwner != "worker-1" {
|
|
t.Fatalf("LeaseOwner = %q, want worker-1", leased.LeaseOwner)
|
|
}
|
|
if leased.ConfirmationAttempts != 1 {
|
|
t.Fatalf("ConfirmationAttempts = %d, want 1", leased.ConfirmationAttempts)
|
|
}
|
|
|
|
_, ok, err = store.ImportRunItems().TryAcquireConfirmationLease(ctx, "item-pending", "worker-2", now.Add(30*time.Second), time.Minute)
|
|
if err != nil {
|
|
t.Fatalf("TryAcquireConfirmationLease(second) error = %v", err)
|
|
}
|
|
if ok {
|
|
t.Fatal("TryAcquireConfirmationLease(second) ok = true, want false while lease active")
|
|
}
|
|
}
|
|
|
|
func TestImportRunItemsRepoUpsertDefaultsOptionalJSONAndNullableFields(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx := context.Background()
|
|
store := openTestDB(t)
|
|
|
|
run := ImportRun{RunID: "run-upsert-defaults", HostID: "host-upsert", Mode: "strict", AccessMode: "subscription", State: "running"}
|
|
if err := store.ImportRuns().Create(ctx, run); err != nil {
|
|
t.Fatalf("ImportRuns().Create() error = %v", err)
|
|
}
|
|
|
|
if err := store.ImportRunItems().Upsert(ctx, ImportRunItem{
|
|
ItemID: "item-upsert-defaults",
|
|
RunID: "run-upsert-defaults",
|
|
BaseURL: "https://api.example.com/v1",
|
|
ProviderID: "provider-upsert",
|
|
APIKeyFingerprint: "fp-upsert",
|
|
CurrentStage: "confirm",
|
|
ConfirmationStatus: "pending",
|
|
AccessStatus: "unknown",
|
|
MatchedAccountState: "active",
|
|
AccountResolution: "created",
|
|
ResolvedSmokeModel: " gpt-5.4 ",
|
|
LastRetryAt: " ",
|
|
NextRetryAt: " ",
|
|
LeaseOwner: " worker-upsert ",
|
|
LeaseUntil: " 2026-05-23T12:00:00Z ",
|
|
LastErrorStage: " confirm ",
|
|
LastError: " timeout ",
|
|
LegacyProviderID: " legacy-provider ",
|
|
}); err != nil {
|
|
t.Fatalf("ImportRunItems().Upsert() error = %v", err)
|
|
}
|
|
|
|
got, err := store.ImportRunItems().GetByItemID(ctx, "item-upsert-defaults")
|
|
if err != nil {
|
|
t.Fatalf("ImportRunItems().GetByItemID() error = %v", err)
|
|
}
|
|
if got.RequestedModelsJSON != "[]" {
|
|
t.Fatalf("RequestedModelsJSON = %q, want []", got.RequestedModelsJSON)
|
|
}
|
|
if got.RawModelsJSON != "[]" {
|
|
t.Fatalf("RawModelsJSON = %q, want []", got.RawModelsJSON)
|
|
}
|
|
if got.NormalizedModelsJSON != "[]" {
|
|
t.Fatalf("NormalizedModelsJSON = %q, want []", got.NormalizedModelsJSON)
|
|
}
|
|
if got.CanonicalFamiliesJSON != "[]" {
|
|
t.Fatalf("CanonicalFamiliesJSON = %q, want []", got.CanonicalFamiliesJSON)
|
|
}
|
|
if got.RecommendedModelsJSON != "[]" {
|
|
t.Fatalf("RecommendedModelsJSON = %q, want []", got.RecommendedModelsJSON)
|
|
}
|
|
if got.CapabilityProfileJSON != "{}" {
|
|
t.Fatalf("CapabilityProfileJSON = %q, want {}", got.CapabilityProfileJSON)
|
|
}
|
|
if got.AdvisoryMessagesJSON != "[]" {
|
|
t.Fatalf("AdvisoryMessagesJSON = %q, want []", got.AdvisoryMessagesJSON)
|
|
}
|
|
if got.ResolvedSmokeModel != "gpt-5.4" {
|
|
t.Fatalf("ResolvedSmokeModel = %q, want gpt-5.4", got.ResolvedSmokeModel)
|
|
}
|
|
if got.LeaseOwner != "worker-upsert" {
|
|
t.Fatalf("LeaseOwner = %q, want worker-upsert", got.LeaseOwner)
|
|
}
|
|
if got.LeaseUntil != "2026-05-23T12:00:00Z" {
|
|
t.Fatalf("LeaseUntil = %q, want trimmed lease_until", got.LeaseUntil)
|
|
}
|
|
if got.LastErrorStage != "confirm" {
|
|
t.Fatalf("LastErrorStage = %q, want confirm", got.LastErrorStage)
|
|
}
|
|
if got.LastError != "timeout" {
|
|
t.Fatalf("LastError = %q, want timeout", got.LastError)
|
|
}
|
|
if got.LegacyProviderID != "legacy-provider" {
|
|
t.Fatalf("LegacyProviderID = %q, want legacy-provider", got.LegacyProviderID)
|
|
}
|
|
if got.LastRetryAt != "" || got.NextRetryAt != "" {
|
|
t.Fatalf("retry timestamps = (%q, %q), want empty strings", got.LastRetryAt, got.NextRetryAt)
|
|
}
|
|
}
|
|
|
|
func TestImportRunItemsRepoUpsertValidationErrors(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx := context.Background()
|
|
store := openTestDB(t)
|
|
run := ImportRun{RunID: "run-upsert-validation", HostID: "host-upsert-validation", Mode: "strict", AccessMode: "subscription", State: "running"}
|
|
if err := store.ImportRuns().Create(ctx, run); err != nil {
|
|
t.Fatalf("ImportRuns().Create() error = %v", err)
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
item ImportRunItem
|
|
}{
|
|
{name: "missing item_id", item: ImportRunItem{RunID: "run-upsert-validation", BaseURL: "https://api.example.com/v1", ProviderID: "provider", APIKeyFingerprint: "fp", CurrentStage: "confirm", ConfirmationStatus: "pending", AccessStatus: "unknown", MatchedAccountState: "active", AccountResolution: "created"}},
|
|
{name: "missing run_id", item: ImportRunItem{ItemID: "item", BaseURL: "https://api.example.com/v1", ProviderID: "provider", APIKeyFingerprint: "fp", CurrentStage: "confirm", ConfirmationStatus: "pending", AccessStatus: "unknown", MatchedAccountState: "active", AccountResolution: "created"}},
|
|
{name: "missing base_url", item: ImportRunItem{ItemID: "item", RunID: "run-upsert-validation", ProviderID: "provider", APIKeyFingerprint: "fp", CurrentStage: "confirm", ConfirmationStatus: "pending", AccessStatus: "unknown", MatchedAccountState: "active", AccountResolution: "created"}},
|
|
{name: "missing provider_id", item: ImportRunItem{ItemID: "item", RunID: "run-upsert-validation", BaseURL: "https://api.example.com/v1", APIKeyFingerprint: "fp", CurrentStage: "confirm", ConfirmationStatus: "pending", AccessStatus: "unknown", MatchedAccountState: "active", AccountResolution: "created"}},
|
|
{name: "missing fingerprint", item: ImportRunItem{ItemID: "item", RunID: "run-upsert-validation", BaseURL: "https://api.example.com/v1", ProviderID: "provider", CurrentStage: "confirm", ConfirmationStatus: "pending", AccessStatus: "unknown", MatchedAccountState: "active", AccountResolution: "created"}},
|
|
{name: "missing current_stage", item: ImportRunItem{ItemID: "item", RunID: "run-upsert-validation", BaseURL: "https://api.example.com/v1", ProviderID: "provider", APIKeyFingerprint: "fp", ConfirmationStatus: "pending", AccessStatus: "unknown", MatchedAccountState: "active", AccountResolution: "created"}},
|
|
{name: "missing confirmation_status", item: ImportRunItem{ItemID: "item", RunID: "run-upsert-validation", BaseURL: "https://api.example.com/v1", ProviderID: "provider", APIKeyFingerprint: "fp", CurrentStage: "confirm", AccessStatus: "unknown", MatchedAccountState: "active", AccountResolution: "created"}},
|
|
{name: "missing access_status", item: ImportRunItem{ItemID: "item", RunID: "run-upsert-validation", BaseURL: "https://api.example.com/v1", ProviderID: "provider", APIKeyFingerprint: "fp", CurrentStage: "confirm", ConfirmationStatus: "pending", MatchedAccountState: "active", AccountResolution: "created"}},
|
|
{name: "missing matched_account_state", item: ImportRunItem{ItemID: "item", RunID: "run-upsert-validation", BaseURL: "https://api.example.com/v1", ProviderID: "provider", APIKeyFingerprint: "fp", CurrentStage: "confirm", ConfirmationStatus: "pending", AccessStatus: "unknown", AccountResolution: "created"}},
|
|
{name: "missing account_resolution", item: ImportRunItem{ItemID: "item", RunID: "run-upsert-validation", BaseURL: "https://api.example.com/v1", ProviderID: "provider", APIKeyFingerprint: "fp", CurrentStage: "confirm", ConfirmationStatus: "pending", AccessStatus: "unknown", MatchedAccountState: "active"}},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if err := store.ImportRunItems().Upsert(ctx, tt.item); err == nil {
|
|
t.Fatal("Upsert() error = nil, want validation error")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestImportRunEventsRepoCreateAndHelpers(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx := context.Background()
|
|
store := openTestDB(t)
|
|
|
|
if err := store.ImportRuns().Create(ctx, ImportRun{
|
|
RunID: "run-events",
|
|
HostID: "host-events",
|
|
Mode: "strict",
|
|
AccessMode: "subscription",
|
|
State: "running",
|
|
}); err != nil {
|
|
t.Fatalf("ImportRuns().Create() error = %v", err)
|
|
}
|
|
if err := store.ImportRunItems().Create(ctx, ImportRunItem{
|
|
ItemID: "item-events",
|
|
RunID: "run-events",
|
|
BaseURL: "https://api.example.com/v1",
|
|
ProviderID: "provider-events",
|
|
APIKeyFingerprint: "fp_events",
|
|
CurrentStage: "confirm",
|
|
ConfirmationStatus: "pending",
|
|
AccessStatus: "unknown",
|
|
MatchedAccountState: "active",
|
|
AccountResolution: "created",
|
|
}); err != nil {
|
|
t.Fatalf("ImportRunItems().Create() error = %v", err)
|
|
}
|
|
|
|
event := ImportRunItemEvent{
|
|
EventID: "evt-create",
|
|
RunID: "run-events",
|
|
ItemID: "item-events",
|
|
EventType: "confirmation",
|
|
Stage: "confirm",
|
|
Message: "created by wrapper",
|
|
}
|
|
if err := store.ImportRunEvents().Create(ctx, event); err != nil {
|
|
t.Fatalf("ImportRunEvents().Create() error = %v", err)
|
|
}
|
|
if err := store.ImportRunItemEvents().Create(ctx, ImportRunItemEvent{
|
|
EventID: "evt-alias",
|
|
RunID: "run-events",
|
|
ItemID: "item-events",
|
|
EventType: "alias",
|
|
Stage: "confirm",
|
|
Message: "created by alias accessor",
|
|
}); err != nil {
|
|
t.Fatalf("ImportRunItemEvents().Create() error = %v", err)
|
|
}
|
|
|
|
events, err := store.ImportRunEvents().ListByItemID(ctx, "item-events")
|
|
if err != nil {
|
|
t.Fatalf("ImportRunEvents().ListByItemID() error = %v", err)
|
|
}
|
|
if len(events) != 2 {
|
|
t.Fatalf("ImportRunEvents().ListByItemID() len = %d, want 2", len(events))
|
|
}
|
|
|
|
nullable := sqlNullInt64{Int64: 42, Valid: true}
|
|
if ptr := nullable.ptr(); ptr == nil || *ptr != 42 {
|
|
t.Fatalf("sqlNullInt64.ptr() = %#v, want 42", ptr)
|
|
}
|
|
if ptr := (sqlNullInt64{}).ptr(); ptr != nil {
|
|
t.Fatalf("sqlNullInt64{}.ptr() = %#v, want nil", ptr)
|
|
}
|
|
}
|