| 1 | package provision |
| 2 | |
| 3 | import "testing" |
| 4 | |
| 5 | // SharedInstanceEligibility must be the reconciler's own predicates, never a |
| 6 | // second reading of the environment (spec §6.1, codex R3-3). |
| 7 | func TestSharedInstanceEligibilityIsTheMintPredicate(t *testing.T) { |
| 8 | cases := []struct { |
| 9 | pools []string |
| 10 | inbound string |
| 11 | shared, accept bool |
| 12 | }{ |
| 13 | {nil, "", true, true}, |
| 14 | {[]string{"tito"}, "", false, true}, |
| 15 | {[]string{"", "tito"}, "", true, true}, |
| 16 | {nil, InboundNone, true, false}, |
| 17 | {[]string{"tito"}, InboundNone, false, false}, |
| 18 | } |
| 19 | for _, c := range cases { |
| 20 | cfg := ReconcileConfig{Pools: c.pools, Inbound: c.inbound} |
| 21 | shared, inbound := cfg.SharedInstanceEligibility() |
| 22 | if shared != poolServed(c.pools, "") || inbound != (c.inbound != InboundNone) { |
| 23 | t.Fatalf("%+v: eligibility diverges from the mint predicates", c) |
| 24 | } |
| 25 | if shared != c.shared || inbound != c.accept { |
| 26 | t.Fatalf("%+v: got (%v, %v), want (%v, %v)", c, shared, inbound, c.shared, c.accept) |
| 27 | } |
| 28 | } |
| 29 | } |
| 30 | |
| 31 | // spec §16, codex plan-R3 4: each published answer pairs with the reconcile |
| 32 | // pass's own behaviour on an ORDINARY record (the shared "" pool, routed). |
| 33 | // A box that publishes both true mints it; a box that publishes either |
| 34 | // false refuses it, so the console's eligibility never offers a region |
| 35 | // whose box would refuse the record. |
| 36 | func TestEligibilityPairsWithTheReconcileRefusal(t *testing.T) { |
| 37 | for _, c := range []struct { |
| 38 | pools []string |
| 39 | inbound string |
| 40 | }{ |
| 41 | {nil, ""}, {[]string{"tito"}, ""}, {[]string{"", "tito"}, ""}, |
| 42 | {nil, InboundNone}, {[]string{"tito"}, InboundNone}, |
| 43 | } { |
| 44 | s, sqid := setup(t) |
| 45 | if err := PutManifest(ctx, s, sqid, "tito", Manifest{Schema: 1, App: "tito", Domain: "go.tito.io"}); err != nil { |
| 46 | t.Fatal(err) |
| 47 | } |
| 48 | rec := acmeRecord(sqid) |
| 49 | rec.Pool = "" |
| 50 | if err := CreateRecord(ctx, s, rec); err != nil { |
| 51 | t.Fatal(err) |
| 52 | } |
| 53 | reg := regWith(t) |
| 54 | cfg := ReconcileConfig{Region: "ie", Pools: c.pools, DataDir: "/data", Inbound: c.inbound} |
| 55 | if err := Reconcile(ctx, s, reg, cfg); err != nil { |
| 56 | t.Fatal(err) |
| 57 | } |
| 58 | rt, err := reg.Get(rec.Host) |
| 59 | minted := err == nil && rt != nil |
| 60 | shared, inbound := cfg.SharedInstanceEligibility() |
| 61 | if minted != (shared && inbound) { |
| 62 | t.Errorf("pools %q inbound %q: minted %v, but the box publishes serves_shared_pool=%v accepts_inbound=%v", c.pools, c.inbound, minted, shared, inbound) |
| 63 | } |
| 64 | } |
| 65 | } |
| 66 | |