package db import ( "errors" "reflect" "testing" ) // RegistryBreakdown and RegistryBreakdownList over the slice of the registry // filter. Run 1 holds three addresses (cycle 1), run 2 a re-check of .1 (cycle 2). func TestRegistryBreakdown(t *testing.T) { d, ctx := newTestDB(t) const a1, a2, a3 = "10.0.0.1", "10.0.0.2", "10.0.1.1" submit(t, d, RunManual, a1, a2, a3) s1, s2 := InboundSource(1), InboundSource(2) for _, c := range []struct { addr, source, typ, target string ok bool }{ {a1, SourceEgress, "https", "T1", true}, {a1, SourceEgress, "https", "T2", false}, {a1, s1, "tcp-22", a1, true}, {a1, s1, "tcp-443", a1, false}, {a1, s2, "tcp-443", a1, true}, {a2, SourceEgress, "https", "T1", false}, {a2, SourceEgress, "https", "T2", false}, {a2, s1, "tcp-443", a2, true}, {a3, SourceEgress, "https", "T1", true}, {a3, SourceEgress, "https", "T3", true}, } { addCheck(t, d, c.addr, c.source, c.typ, c.target, c.ok) } finish(t, d, a1, ResultPartial, -1) finish(t, d, a2, ResultFail, -1) finish(t, d, a3, ResultPass, -1) run1 := runs(t, d)[0].ID submit(t, d, RunManual, a1) addCheck(t, d, a1, SourceEgress, "https", "T1", false) addCheck(t, d, a1, SourceEgress, "https", "T2", true) finish(t, d, a1, ResultPartial, -1) eg := RegistryFilter{Level: LevelEgress, Family: "https"} in := RegistryFilter{Level: LevelIngress, Family: "tcp"} for _, tc := range []struct { name string f RegistryFilter group string addrs int want []BreakdownRow }{ {"egress, run 1: most successful first", withRun(eg, run1), BreakdownTarget, 3, []BreakdownRow{{"T1", 3, 2}, {"T3", 1, 1}, {"T2", 2, 0}}}, {"egress, newest cycle; equal counts by key", eg, BreakdownTarget, 3, []BreakdownRow{{"T1", 3, 1}, {"T2", 2, 1}, {"T3", 1, 1}}}, {"egress, subnet", RegistryFilter{RunID: run1, Level: LevelEgress, Family: "https", Subnet: "10.0.0.0/24"}, BreakdownTarget, 2, []BreakdownRow{{"T1", 2, 1}, {"T2", 2, 0}}}, {"egress, status in scope", RegistryFilter{RunID: run1, Level: LevelEgress, Family: "https", LastResult: ResultFail}, BreakdownTarget, 1, []BreakdownRow{{"T1", 1, 0}, {"T2", 1, 0}}}, {"ingress by site, checks not addresses", withRun(in, run1), BreakdownSite, 2, []BreakdownRow{{s1, 3, 2}, {s2, 1, 1}}}, {"egress tls does not exist", RegistryFilter{Level: LevelEgress, Family: "tls"}, BreakdownTarget, 0, nil}, } { b, err := d.RegistryBreakdown(ctx, tc.f) if err != nil { t.Fatalf("%s: %v", tc.name, err) } if b.Group != tc.group || b.Addresses != tc.addrs || !reflect.DeepEqual(b.Rows, tc.want) { t.Errorf("%s: group=%s addresses=%d rows=%v, want %s %d %v", tc.name, b.Group, b.Addresses, b.Rows, tc.group, tc.addrs, tc.want) } // The chart covers the addresses of the list. if _, total, err := d.ListRegistryPage(ctx, tc.f, 10, 0); err != nil || total != b.Addresses { t.Errorf("%s: list total=%d err=%v, chart addresses=%d", tc.name, total, err, b.Addresses) } } // The list: failures first, then registry order; the key picks the group. for _, tc := range []struct { name string f RegistryFilter key string want [][3]string // address, type, success }{ {"egress T1", withRun(eg, run1), "T1", [][3]string{{a2, "https", "0"}, {a1, "https", "1"}, {a3, "https", "1"}}}, {"ingress site 1", withRun(in, run1), s1, [][3]string{{a1, "tcp-443", "0"}, {a1, "tcp-22", "1"}, {a2, "tcp-443", "1"}}}, } { got, err := d.RegistryBreakdownList(ctx, tc.f, tc.key) if err != nil { t.Fatalf("%s: %v", tc.name, err) } var rows [][3]string for _, c := range got { ok := "0" if c.Success { ok = "1" } rows = append(rows, [3]string{c.IPAddress, c.CheckType, ok}) } if !reflect.DeepEqual(rows, tc.want) { t.Errorf("%s: %v, want %v", tc.name, rows, tc.want) } } if _, err := d.RegistryBreakdownList(ctx, withRun(eg, run1), "nope"); !errors.Is(err, ErrNotFound) { t.Errorf("unknown key: %v", err) } for _, f := range []RegistryFilter{{}, {Level: LevelEgress}, {Family: "https"}, {Level: "sideways", Family: "https"}} { if _, err := d.RegistryBreakdown(ctx, f); !errors.Is(err, ErrValidation) { t.Errorf("%+v: %v", f, err) } } } func withRun(f RegistryFilter, run int64) RegistryFilter { f.RunID = run return f }