package storage import ( "errors" "testing" ) func TestAdvOrderRoundTrip(t *testing.T) { setupTestDB(t) o, err := InsertAdvOrder("sub-1", "josie", "tok-josie", "Josie", AdvActionExtract) if err != nil { t.Fatalf("insert: %v", err) } if o.GUID == "" || o.Status != AdvOrderPending { t.Fatalf("order = %+v, want a guid and pending", o) } pending, err := PendingAdvOrders(10) if err != nil { t.Fatalf("pending: %v", err) } if len(pending) != 1 || pending[0].GUID != o.GUID || pending[0].Action != AdvActionExtract { t.Fatalf("pending = %+v", pending) } got, err := ResolveAdvOrder(o.GUID, AdvOrderApplied, "out on day 3") if err != nil { t.Fatalf("resolve: %v", err) } if got.Status != AdvOrderApplied || got.Detail != "out on day 3" { t.Fatalf("resolved = %+v", got) } if left, _ := PendingAdvOrders(10); len(left) != 0 { t.Fatalf("a resolved order is still pending: %+v", left) } } // TestAdvOrderVerdictOnlyMovesAPendingRow is the idempotency mechanic: gogobee // retries its verdict push, so the second one must be a read, not a write. func TestAdvOrderVerdictOnlyMovesAPendingRow(t *testing.T) { setupTestDB(t) o, _ := InsertAdvOrder("sub-1", "josie", "tok-josie", "Josie", AdvActionSiegeJoin) if _, err := ResolveAdvOrder(o.GUID, AdvOrderApplied, "first"); err != nil { t.Fatalf("first verdict: %v", err) } got, err := ResolveAdvOrder(o.GUID, AdvRejectedNoSiege, "second") if err != nil { t.Fatalf("second verdict: %v", err) } if got.Status != AdvOrderApplied || got.Detail != "first" { t.Fatalf("order = %q/%q, want the first verdict to stand", got.Status, got.Detail) } } func TestAdvOrderRejectsBadInput(t *testing.T) { setupTestDB(t) if _, err := InsertAdvOrder("sub-1", "josie", "tok", "Josie", "sell_house"); err == nil { t.Fatal("an unknown action was accepted") } o, _ := InsertAdvOrder("sub-1", "josie", "tok", "Josie", AdvActionExtract) if _, err := ResolveAdvOrder(o.GUID, "exploded", ""); err == nil { t.Fatal("an unknown verdict was accepted") } if _, err := AdvOrderByGUID("nope"); !errors.Is(err, ErrNoSuchAdvOrder) { t.Fatalf("unknown guid err = %v, want ErrNoSuchAdvOrder", err) } } // TestHasPendingAdvOrderIsPerVerb: the guard stops a double-click on one button, // not the other button. func TestHasPendingAdvOrderIsPerVerb(t *testing.T) { setupTestDB(t) o, _ := InsertAdvOrder("sub-1", "josie", "tok", "Josie", AdvActionExtract) if got, _ := HasPendingAdvOrder("sub-1", AdvActionExtract); !got { t.Fatal("a pending extract wasn't seen") } if got, _ := HasPendingAdvOrder("sub-1", AdvActionSiegeJoin); got { t.Fatal("a pending extract blocked a bout") } if got, _ := HasPendingAdvOrder("sub-2", AdvActionExtract); got { t.Fatal("one owner's pending order was seen for another") } // A resolved order stops holding the verb. if _, err := ResolveAdvOrder(o.GUID, AdvOrderApplied, ""); err != nil { t.Fatalf("resolve: %v", err) } if got, _ := HasPendingAdvOrder("sub-1", AdvActionExtract); got { t.Fatal("a resolved order still holds its verb") } } func TestAdvOrdersByOwnerScopes(t *testing.T) { setupTestDB(t) if _, err := InsertAdvOrder("sub-A", "alice", "tok-a", "Alice", AdvActionExtract); err != nil { t.Fatalf("insert: %v", err) } if _, err := InsertAdvOrder("sub-B", "bob", "tok-b", "Bob", AdvActionExtract); err != nil { t.Fatalf("insert: %v", err) } got, err := AdvOrdersByOwner("sub-A", 10) if err != nil { t.Fatalf("by owner: %v", err) } if len(got) != 1 || got[0].OwnerLocalpart != "alice" { t.Fatalf("orders = %+v, want only alice's", got) } if n, _ := CountAdvOrdersSince("sub-A", 0); n != 1 { t.Fatalf("count = %d, want 1", n) } }