pkg/resourceapi/coverage_test.go
Rama main · réplica de lectura del repositorio original.
package resourceapi
import (
"encoding/json"
"fmt"
"slices"
"strings"
"testing"
)
func TestSetsListAllMembersOrNone(t *testing.T) {
names := make([]string, 1000)
for i := range names {
names[i] = fmt.Sprintf("team-%04d", 999-i)
}
original := slices.Clone(names)
if set := Names(names, MCPSetLimit); set.Count != 1000 || set.Names != nil {
t.Fatalf("a set over the limit lists no names: %+v", set)
}
if !slices.Equal(names, original) {
t.Fatal("Names mutated the caller's slice")
}
if got := Names([]string{"beta", "alpha", "alpha"}, RESTSetLimit); got.Count != 2 || !slices.Equal(got.Names, []string{"alpha", "beta"}) {
t.Fatalf("set = %+v", got)
}
if got := Names(names[:MCPSetLimit], MCPSetLimit); got.Count != MCPSetLimit || len(got.Names) != MCPSetLimit {
t.Fatalf("a set at the limit lists every name: %+v", got)
}
if got := Names(names[:64], RESTSetLimit).Capped(MCPSetLimit); got.Count != 64 || got.Names != nil {
t.Fatalf("capping drops names over the smaller limit: %+v", got)
}
}
// An empty set lists its (no) members; a set over the limit lists none.
func TestSetsMarshal(t *testing.T) {
for _, v := range []any{Names(nil, 8), Kinds(nil, 8), Objects(nil, 0, 8)} {
raw, err := json.Marshal(v)
if err != nil {
t.Fatal(err)
}
if string(raw) != `{"count":0,"names":[]}` {
t.Fatalf("%T = %s", v, raw)
}
}
raw, _ := json.Marshal(Names([]string{"a", "b", "c"}, 2))
if string(raw) != `{"count":3}` {
t.Fatalf("over the limit = %s", raw)
}
}
func TestObjectsListOnlyAKnownWholeSet(t *testing.T) {
if set := Objects([]ObjectRef{{Kind: "Pod", Namespace: "a", Name: "x"}}, 37, 8); set.Count != 37 || set.Names != nil {
t.Fatalf("a partly known set lists no names: %+v", set)
}
if set := Objects([]ObjectRef{{Kind: "Pod", Namespace: "a", Name: "x"}}, 1, 8); set.Count != 1 || len(set.Names) != 1 {
t.Fatalf("set = %+v", set)
}
}
func TestKindsDeduplicatesByKindAndGroup(t *testing.T) {
set := Kinds([]KindRef{{Kind: "Service", Group: "serving.knative.dev"}, {Kind: "Service"}, {Kind: "Service"}}, 8)
if set.Count != 2 || set.Names[0] != (KindRef{Kind: "Service"}) {
t.Fatalf("set = %+v", set)
}
}
func TestObjectsSortAndDeduplicate(t *testing.T) {
b := ObjectRef{Kind: "Pod", Namespace: "beta", Name: "web"}
a := ObjectRef{Kind: "Pod", Namespace: "alpha", Name: "web"}
set := Objects([]ObjectRef{b, a, b}, 2, 8)
if set.Count != 2 || len(set.Names) != 2 || set.Names[0] != a || set.Names[1] != b {
t.Fatalf("set = %+v, want alpha/web then beta/web", set)
}
}
func TestCoverageGapsMarshalAsAnArray(t *testing.T) {
for name, v := range map[string]any{"value": Coverage{}, "pointer": &Coverage{}, "error body": ReadError{Coverage: &Coverage{}}, "search": SearchCoverage{}, "search pointer": &SearchCoverage{}} {
b, err := json.Marshal(v)
if err != nil || !strings.Contains(string(b), `"gaps":[]`) {
t.Fatalf("%s: %s %v, want gaps as []", name, b, err)
}
}
}
// Narrowing values are wire contracts: a released Radar's values must keep
// meaning the same thing to every later consumer.
func TestNarrowingSpellings(t *testing.T) {
got := []Narrowing{NarrowedByUserAccess, NarrowedByNamespacePin, NarrowedByNamespaceCollection, NarrowedByKindCollection}
want := []Narrowing{"user_access", "namespace_pin", "namespace_collection", "kind_collection"}
if !slices.Equal(got, want) {
t.Fatalf("narrowings = %v, want %v", got, want)
}
}
// A gap that can't list an axis says how much of it it reaches, never by
// leaving the axis out, and carries the action its code calls for.
func TestGapsStateExtentAndAction(t *testing.T) {
for _, tc := range []struct {
gap Gap
want string
}{
{Gap{Code: "kind_sync_pending", Namespaces: AllNames()}, `{"code":"kind_sync_pending","action":"retry","namespaces":{"extent":"all"}}`},
{Gap{Code: "radar_namespace_not_collected", Namespaces: UnknownNames()}, `{"code":"radar_namespace_not_collected","action":"radar_config","namespaces":{"extent":"unknown"}}`},
{Gap{Code: "read_error", Kinds: UnknownKinds()}, `{"code":"read_error","action":"retry","kinds":{"extent":"unknown"}}`},
{Gap{Code: "user_forbidden", Namespaces: Names([]string{"b"}, MCPSetLimit)}, `{"code":"user_forbidden","action":"user_access","namespaces":{"count":1,"names":["b"]}}`},
{Gap{Code: "some_future_code", Namespaces: AllNames()}, `{"code":"some_future_code","namespaces":{"extent":"all"}}`},
} {
raw, err := json.Marshal(tc.gap)
if err != nil || string(raw) != tc.want {
t.Errorf("marshal = %s, %v; want %s", raw, err, tc.want)
}
}
if AllNames().Capped(1).Extent != ExtentAll || UnknownKinds().Capped(1).Extent != ExtentUnknown {
t.Error("capping keeps an extent set as it is")
}
}
func TestValidate(t *testing.T) {
ns := func(names ...string) *NameSet { return Names(names, MCPSetLimit) }
scoped := func(set *NameSet) Scope { return Scope{Type: ScopeNamespaces, Namespaces: set} }
all := Scope{Type: ScopeAllNamespaces}
valid := []Coverage{
{Status: CoverageComplete, Scope: all, Read: &all},
{Status: CoverageComplete, Scope: Scope{Type: ScopeCluster}, Read: &Scope{Type: ScopeCluster}},
{Status: CoveragePartial, Scope: scoped(ns("a", "g")), Read: ptr(scoped(ns("a"))), Gaps: []Gap{{Code: "kind_sync_pending", Namespaces: ns("g")}}},
{Status: CoveragePartial, Scope: scoped(&NameSet{Count: 20}), Read: ptr(scoped(ns("a", "b"))), Gaps: []Gap{{Code: "kind_sync_pending", Namespaces: &NameSet{Count: 18}}}},
{Status: CoveragePartial, Scope: all, Gaps: []Gap{{Code: "kind_sync_pending", Namespaces: AllNames()}}},
{Status: CoveragePartial, Scope: scoped(ns("a", "b")), Gaps: []Gap{{Code: "user_forbidden", Namespaces: ns("a")}, {Code: "radar_kind_not_collected", Namespaces: ns("b")}}},
{Status: CoveragePartial, Scope: all, Read: ptr(scoped(ns("a"))), Gaps: []Gap{{Code: "radar_namespace_not_collected", Namespaces: UnknownNames()}}},
}
for i, c := range valid {
if err := c.Validate(); err != nil {
t.Errorf("valid[%d]: %v", i, err)
}
}
invalid := map[string]Coverage{
"complete with a gap": {Status: CoverageComplete, Scope: all, Read: &all, Gaps: []Gap{{Code: "kind_sync_pending", Namespaces: AllNames()}}},
"partial with no gap": {Status: CoveragePartial, Scope: all, Read: &all},
"gap leaves namespaces out": {Status: CoveragePartial, Scope: scoped(ns("a", "g")), Read: ptr(scoped(ns("a"))), Gaps: []Gap{{Code: "kind_sync_pending"}}},
"namespaces on a cluster": {Status: CoveragePartial, Scope: Scope{Type: ScopeCluster}, Gaps: []Gap{{Code: "kind_sync_pending", Namespaces: AllNames()}}},
"namespace in two places": {Status: CoveragePartial, Scope: scoped(ns("a", "g")), Read: ptr(scoped(ns("a", "g"))), Gaps: []Gap{{Code: "kind_sync_pending", Namespaces: ns("g")}}},
"parts don't add up": {Status: CoveragePartial, Scope: scoped(&NameSet{Count: 20}), Read: ptr(scoped(ns("a"))), Gaps: []Gap{{Code: "kind_sync_pending", Namespaces: &NameSet{Count: 18}}}},
"scope namespace unread": {Status: CoveragePartial, Scope: scoped(ns("a", "b", "g")), Read: ptr(scoped(ns("a"))), Gaps: []Gap{{Code: "kind_sync_pending", Namespaces: ns("g")}, {Code: "user_forbidden", Namespaces: ns("x")}}},
"whole-scope gap beside read": {Status: CoveragePartial, Scope: scoped(ns("a", "b")), Read: ptr(scoped(ns("a"))), Gaps: []Gap{{Code: "kind_sync_pending", Namespaces: AllNames()}}},
"whole-scope gap beside a gap": {Status: CoveragePartial, Scope: scoped(ns("a", "b")), Gaps: []Gap{{Code: "user_forbidden", Namespaces: ns("a")}, {Code: "kind_sync_pending", Namespaces: AllNames()}}},
"complete read isn't scope": {Status: CoverageComplete, Scope: all, Read: ptr(scoped(ns("a")))},
"gap outside scope": {Status: CoveragePartial, Scope: scoped(ns("a", "b")), Read: ptr(scoped(&NameSet{Count: 1})), Gaps: []Gap{{Code: "kind_sync_pending", Namespaces: ns("x")}}},
"extent on scope": {Status: CoverageComplete, Scope: scoped(UnknownNames()), Read: ptr(scoped(UnknownNames()))},
"unsorted names": {Status: CoverageComplete, Scope: scoped(&NameSet{Count: 2, Names: []string{"b", "a"}}), Read: ptr(scoped(&NameSet{Count: 2, Names: []string{"b", "a"}}))},
}
for name, c := range invalid {
if err := c.Validate(); err == nil {
t.Errorf("%s: Validate passed %+v", name, c)
}
}
}
func ptr[T any](v T) *T { return &v }