| 1 | package infraview |
| 2 | |
| 3 | import ( |
| 4 | "encoding/json" |
| 5 | "testing" |
| 6 | "time" |
| 7 | ) |
| 8 | |
| 9 | // An inventory written before a field existed must still parse, and a kind |
| 10 | // no reader knows must survive as itself rather than being dropped — the |
| 11 | // repo's additive wire-shape rule applied to a bucket object. |
| 12 | func TestInventoryParsesAdditively(t *testing.T) { |
| 13 | old := []byte(`{ |
| 14 | "provider":"aws","account":"1234","taken_at":"2026-08-19T10:00:00Z", |
| 15 | "resources":[ |
| 16 | {"provider":"aws","kind":"machine","native_type":"ec2:instance", |
| 17 | "id":"i-123","name":"carlos-eu-west-1","region":"eu-west-1", |
| 18 | "attrs":{"type":"t4g.medium","public_ip":"52.0.0.1"}}, |
| 19 | {"provider":"aws","kind":"quantum_widget","native_type":"qc:widget","id":"q-1"} |
| 20 | ], |
| 21 | "future_field":"ignored" |
| 22 | }`) |
| 23 | var inv Inventory |
| 24 | if err := json.Unmarshal(old, &inv); err != nil { |
| 25 | t.Fatalf("parse: %v", err) |
| 26 | } |
| 27 | if inv.Provider != "aws" || inv.Account != "1234" { |
| 28 | t.Fatalf("header: %+v", inv) |
| 29 | } |
| 30 | if !inv.TakenAt.Equal(time.Date(2026, 8, 19, 10, 0, 0, 0, time.UTC)) { |
| 31 | t.Fatalf("taken_at: %v", inv.TakenAt) |
| 32 | } |
| 33 | if len(inv.Resources) != 2 { |
| 34 | t.Fatalf("resources: %d, want 2 (an unknown kind must not be dropped)", len(inv.Resources)) |
| 35 | } |
| 36 | if got := inv.Resources[1].Kind; got != "quantum_widget" { |
| 37 | t.Fatalf("unknown kind = %q, want it carried verbatim", got) |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | func TestByKindAndFind(t *testing.T) { |
| 42 | inv := Inventory{Resources: []Resource{ |
| 43 | {Kind: KindMachine, ID: "i-1", Attrs: map[string]string{"public_ip": "52.0.0.1"}}, |
| 44 | {Kind: KindMachine, ID: "i-2", Attrs: map[string]string{"public_ip": "52.0.0.2"}}, |
| 45 | {Kind: KindBucket, ID: "carlos-data-ie"}, |
| 46 | }} |
| 47 | if got := len(inv.ByKind(KindMachine)); got != 2 { |
| 48 | t.Fatalf("ByKind(machine) = %d, want 2", got) |
| 49 | } |
| 50 | if got := inv.Find(KindMachine, "public_ip", "52.0.0.2"); got == nil || got.ID != "i-2" { |
| 51 | t.Fatalf("Find = %+v, want i-2", got) |
| 52 | } |
| 53 | if got := inv.Find(KindMachine, "public_ip", "10.0.0.9"); got != nil { |
| 54 | t.Fatalf("Find(miss) = %+v, want nil", got) |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | // A resource with no Attrs map must not panic any accessor — an inventory |
| 59 | // read from an older writer is full of them. |
| 60 | func TestFindNilAttrs(t *testing.T) { |
| 61 | inv := Inventory{Resources: []Resource{{Kind: KindMachine, ID: "i-1"}}} |
| 62 | if got := inv.Find(KindMachine, "public_ip", "52.0.0.1"); got != nil { |
| 63 | t.Fatalf("Find over nil Attrs = %+v, want nil", got) |
| 64 | } |
| 65 | } |
| 66 | |