carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package console
2
3import (
4 "context"
5 "encoding/json"
6 "testing"
7 "time"
8
9 "github.com/aws/smithy-go"
10
11 "github.com/carlosframework/platform/internal/awsinv"
12 "github.com/carlosframework/platform/internal/infraview"
13)
14
15// The pass writes the snapshot where the page reads it, and loadInventory
16// reads back exactly what was written.
17func TestInfraPassWritesSnapshot(t *testing.T) {
18 fx := newConsoleFixture(t)
19 fx.srv.inventory = func(context.Context) (infraview.Inventory, error) {
20 return infraview.Inventory{
21 Provider: "aws", Account: "1234", TakenAt: time.Now().UTC(),
22 Resources: []infraview.Resource{{Provider: "aws", Kind: infraview.KindMachine, ID: "i-1"}},
23 }, nil
24 }
25 if err := fx.srv.infraPass(context.Background()); err != nil {
26 t.Fatalf("infraPass: %v", err)
27 }
28 body, _, err := fx.rel.Get(context.Background(), infraview.InventoryKey)
29 if err != nil {
30 t.Fatalf("read back: %v", err)
31 }
32 var inv infraview.Inventory
33 if err := json.Unmarshal(body, &inv); err != nil {
34 t.Fatalf("parse: %v", err)
35 }
36 if len(inv.Resources) != 1 || inv.Resources[0].ID != "i-1" {
37 t.Fatalf("stored = %+v", inv)
38 }
39 got, why := fx.srv.loadInventory(context.Background())
40 if got == nil || why != "" {
41 t.Fatalf("loadInventory = %+v, %q; want the snapshot", got, why)
42 }
43}
44
45// An auth-shaped failure latches the pass off for the process after ONE
46// attempt: "this deployment has no inventory grant" is a permanent answer,
47// not something to re-ask AWS every hour forever.
48//
49// The fake returns awsinv.ErrNoGrant — the REAL error value
50// awsinv.Provider.Inventory produces when every read comes back denied and
51// nothing was discovered (internal/awsinv/awsinv.go) — not a hand-made
52// smithy.APIError. A prior version of this test used a fake AccessDenied
53// smithy error, an error shape the real seam never actually emits (the
54// per-mapping denials are folded into Partial strings well before
55// assembly decides anything, so no smithy.APIError survives to the
56// caller); that let the pass pass its tests while the real deny path
57// never latched at all. Using the real sentinel is what proves the fix.
58func TestInfraPassLatchesOnAuthShapedFailure(t *testing.T) {
59 fx := newConsoleFixture(t)
60 calls := 0
61 fx.srv.inventory = func(context.Context) (infraview.Inventory, error) {
62 calls++
63 return infraview.Inventory{}, awsinv.ErrNoGrant
64 }
65 if err := fx.srv.infraPass(context.Background()); err == nil {
66 t.Fatal("want an error from the denied pass")
67 }
68 if err := fx.srv.infraPass(context.Background()); err == nil {
69 t.Fatal("want an error from the latched pass")
70 }
71 if calls != 1 {
72 t.Fatalf("provider called %d times, want 1 — the latch must stop the second attempt", calls)
73 }
74 if _, why := fx.srv.loadInventory(context.Background()); why != "ungranted" {
75 t.Fatalf("loadInventory reason = %q, want %q", why, "ungranted")
76 }
77}
78
79// A transient failure is NOT the latch: CE throttles under load and a blip
80// must not silently kill inventory until the next redeploy. Uses a real
81// smithy.GenericAPIError coded ThrottlingException — the same fake type
82// cepull_test.go uses in this package — so this proves a genuine AWS
83// throttle survives errors.As(&smithy.APIError{}) and still fails
84// awsinv.IsAuthShaped's code check, rather than merely proving a plain
85// non-API error fails the type assertion outright.
86func TestInfraPassRetriesTransientFailure(t *testing.T) {
87 fx := newConsoleFixture(t)
88 calls := 0
89 fx.srv.inventory = func(context.Context) (infraview.Inventory, error) {
90 calls++
91 return infraview.Inventory{}, &smithy.GenericAPIError{Code: "ThrottlingException"}
92 }
93 _ = fx.srv.infraPass(context.Background())
94 _ = fx.srv.infraPass(context.Background())
95 if calls != 2 {
96 t.Fatalf("provider called %d times, want 2 — a throttle must not latch", calls)
97 }
98}
99
100// With no snapshot ever written, the page must be told "never", never
101// handed an empty inventory that would render as "this account has no
102// resources".
103func TestLoadInventoryNeverTaken(t *testing.T) {
104 fx := newConsoleFixture(t)
105 inv, why := fx.srv.loadInventory(context.Background())
106 if inv != nil || why != "never" {
107 t.Fatalf("loadInventory = %+v, %q; want nil, \"never\"", inv, why)
108 }
109}
110
111// StartInfraPass leaves as soon as the latch is set, not an hour later. The
112// pass that FLIPS the latch returns its own wrapped error rather than
113// errInfraDisabled — only the NEXT call hits the top-of-function guard — so
114// without the post-pass latch check the goroutine parks on a one-hour ticker
115// with provably nothing left to do. This test would sit for infraPassInterval
116// if that check were removed, which is exactly the regression it exists to
117// catch.
118func TestStartInfraPassStopsWhenLatched(t *testing.T) {
119 fx := newConsoleFixture(t)
120 calls := 0
121 fx.srv.inventory = func(context.Context) (infraview.Inventory, error) {
122 calls++
123 return infraview.Inventory{}, awsinv.ErrNoGrant
124 }
125
126 done := make(chan struct{})
127 go func() {
128 fx.srv.StartInfraPass(context.Background())
129 close(done)
130 }()
131 select {
132 case <-done:
133 case <-time.After(5 * time.Second):
134 t.Fatal("StartInfraPass is still ticking after the latch was set")
135 }
136 if calls != 1 {
137 t.Errorf("provider called %d times, want exactly 1 — the latch is permanent for the process", calls)
138 }
139 if !fx.srv.infraDisabled.Load() {
140 t.Error("the latch was not set")
141 }
142}
143