|
| 1 | +package topology |
| 2 | + |
| 3 | +import ( |
| 4 | + "testing" |
| 5 | + |
| 6 | + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" |
| 7 | + "k8s.io/apimachinery/pkg/runtime/schema" |
| 8 | +) |
| 9 | + |
| 10 | +func TestKEDAAuthenticationDependenciesObservedAndScoped(t *testing.T) { |
| 11 | + gvrs := map[string]schema.GroupVersionResource{} |
| 12 | + for kind, resource := range map[string]string{"ScaledObject": "scaledobjects", "ScaledJob": "scaledjobs", "TriggerAuthentication": "triggerauthentications", "ClusterTriggerAuthentication": "clustertriggerauthentications"} { |
| 13 | + gvrs[kind] = schema.GroupVersionResource{Group: "keda.sh", Version: "v1alpha1", Resource: resource} |
| 14 | + } |
| 15 | + makeObject := func(kind, namespace, name string) *unstructured.Unstructured { |
| 16 | + return &unstructured.Unstructured{Object: map[string]any{"apiVersion": "keda.sh/v1alpha1", "kind": kind, "metadata": map[string]any{"namespace": namespace, "name": name}}} |
| 17 | + } |
| 18 | + so, sj := makeObject("ScaledObject", "team", "worker"), makeObject("ScaledJob", "team", "jobs") |
| 19 | + so.Object["spec"] = map[string]any{"triggers": []any{ |
| 20 | + map[string]any{"authenticationRef": map[string]any{"name": "local"}}, |
| 21 | + map[string]any{"authenticationRef": map[string]any{"name": "local"}}, |
| 22 | + map[string]any{"authenticationRef": map[string]any{"name": "absent"}}, |
| 23 | + }} |
| 24 | + sj.Object["spec"] = map[string]any{"triggers": []any{map[string]any{"authenticationRef": map[string]any{"name": "global", "kind": "ClusterTriggerAuthentication"}}}} |
| 25 | + p := &issuerTestProvider{monitorDynamicProvider: monitorDynamicProvider{gvrs: gvrs, resources: map[schema.GroupVersionResource][]*unstructured.Unstructured{ |
| 26 | + gvrs["ScaledObject"]: {so}, gvrs["ScaledJob"]: {sj}, |
| 27 | + gvrs["TriggerAuthentication"]: {makeObject("TriggerAuthentication", "team", "local"), makeObject("TriggerAuthentication", "other", "local"), makeObject("TriggerAuthentication", "team", "unused")}, |
| 28 | + gvrs["ClusterTriggerAuthentication"]: {makeObject("ClusterTriggerAuthentication", "", "global")}, |
| 29 | + }}, listCalls: map[string]int{}} |
| 30 | + opts := DefaultBuildOptions() |
| 31 | + opts.Namespaces = []string{"team"} |
| 32 | + topo, err := NewBuilder(&mockProvider{}).WithDynamic(p).Build(opts) |
| 33 | + if err != nil { |
| 34 | + t.Fatal(err) |
| 35 | + } |
| 36 | + if len(topo.Nodes) != 4 || len(topo.Edges) != 2 { |
| 37 | + t.Fatalf("observed authentication graph: nodes=%+v edges=%+v", topo.Nodes, topo.Edges) |
| 38 | + } |
| 39 | + for _, edge := range topo.Edges { |
| 40 | + if edge.Type != EdgeConfigures || edge.Label != "authentication" { |
| 41 | + t.Fatalf("authentication presented as scaler usage: %+v", edge) |
| 42 | + } |
| 43 | + } |
| 44 | + for _, tc := range []struct{ kind, name, auth, namespace string }{{"ScaledObject", "worker", "TriggerAuthentication", "team"}, {"ScaledJob", "jobs", "ClusterTriggerAuthentication", ""}} { |
| 45 | + rel := GetRelationships(tc.kind, "team", tc.name, topo, nil, p) |
| 46 | + if rel == nil || len(rel.Dependencies) != 1 || rel.Dependencies[0].Kind != tc.auth || rel.Dependencies[0].Namespace != tc.namespace || rel.ScaleTarget != nil { |
| 47 | + t.Fatalf("authentication misclassified for %s: %+v", tc.kind, rel) |
| 48 | + } |
| 49 | + name := "local" |
| 50 | + if tc.namespace == "" { |
| 51 | + name = "global" |
| 52 | + } |
| 53 | + reverse := GetRelationships(tc.auth, tc.namespace, name, topo, nil, p) |
| 54 | + if reverse == nil || len(reverse.Dependents) != 1 || reverse.Dependents[0].Kind != tc.kind { |
| 55 | + t.Fatalf("reverse authentication: %+v", reverse) |
| 56 | + } |
| 57 | + } |
| 58 | + if p.getCalls != 0 || p.listCalls["triggerauthentications"] != 1 || p.listCalls["clustertriggerauthentications"] != 1 { |
| 59 | + t.Fatalf("per-object lookup or repeated kind list: gets=%d lists=%v", p.getCalls, p.listCalls) |
| 60 | + } |
| 61 | + if tuples := topo.ClusterScopedDynamicRBACTuples(); len(tuples) != 1 || tuples[0].Group != "keda.sh" || tuples[0].Resource != "clustertriggerauthentications" { |
| 62 | + t.Fatalf("cluster authorization tuples = %+v", tuples) |
| 63 | + } |
| 64 | + topo.StripClusterScopedDynamicExcept(nil) |
| 65 | + if len(topo.Nodes) != 3 || len(topo.Edges) != 1 { |
| 66 | + t.Fatalf("denied cluster authentication retained: %+v", topo) |
| 67 | + } |
| 68 | +} |
0 commit comments