Files
capsule/pkg/template/reference_context_test.go
T
Oliver BählerandGitHub c17e4fa812 feat: add leader-election tuning (#2008)
* feat: add leader-election tuning

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* feat: add leader-election tuning

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* feat: add tracing for admission

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* feat: add tracing for admission

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* add tenant

---------

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>
2026-07-08 11:44:43 +02:00

203 lines
6.3 KiB
Go

// Copyright 2020-2026 Project Capsule Authors
// SPDX-License-Identifier: Apache-2.0
package template_test
import (
"context"
"reflect"
"strings"
"testing"
apiruntime "github.com/projectcapsule/capsule/pkg/api/runtime"
tpl "github.com/projectcapsule/capsule/pkg/template"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
)
func TestResourceReferenceTemplating(t *testing.T) {
t.Parallel()
ref := tpl.ResourceReference{
Name: "{{ tenant.name }}-config",
Namespace: "{{ namespace }}",
Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "{{ tenant.name }}"}},
}
if !ref.RequiresTemplating() {
t.Fatalf("RequiresTemplating() = false, want true")
}
got, err := ref.LoadTemplated(map[string]string{"tenant.name": "team-a", "namespace": "team-a-dev"})
if err != nil {
t.Fatalf("LoadTemplated() unexpected error: %v", err)
}
if got.Name != "team-a-config" || got.Namespace != "team-a-dev" || got.Selector.MatchLabels["app"] != "team-a" {
t.Fatalf("LoadTemplated() = %#v", got)
}
if ref.Name == got.Name {
t.Fatalf("LoadTemplated() mutated original reference")
}
}
func TestResourceReferenceLoadResources(t *testing.T) {
t.Parallel()
ctx := context.Background()
scheme := runtime.NewScheme()
if err := corev1.AddToScheme(scheme); err != nil {
t.Fatalf("adding core scheme: %v", err)
}
cl := fake.NewClientBuilder().WithScheme(scheme).WithObjects(
configMap("team-a", "settings", map[string]string{"app": "api", "tenant": "team-a"}),
configMap("team-a", "other", map[string]string{"app": "worker", "tenant": "team-a"}),
configMap("team-b", "settings", map[string]string{"app": "api", "tenant": "team-b"}),
).Build()
mapper := templateRESTMapper()
t.Run("loads named object", func(t *testing.T) {
t.Parallel()
got, err := (tpl.ResourceReference{
VersionKind: tplVersionKind("v1", "ConfigMap"),
Name: "settings",
Optional: true,
}).LoadResources(ctx, cl, mapper, "team-a", nil, nil, false, nil)
if err != nil {
t.Fatalf("LoadResources() unexpected error: %v", err)
}
if len(got) != 1 || got[0].GetName() != "settings" || got[0].GetNamespace() != "team-a" {
t.Fatalf("LoadResources() = %#v", got)
}
})
t.Run("optional missing named object returns nil", func(t *testing.T) {
t.Parallel()
got, err := (tpl.ResourceReference{
VersionKind: tplVersionKind("v1", "ConfigMap"),
Name: "missing",
Optional: true,
}).LoadResources(ctx, cl, mapper, "team-a", nil, nil, false, nil)
if err != nil {
t.Fatalf("LoadResources() unexpected error for optional missing object: %v", err)
}
if got != nil {
t.Fatalf("LoadResources() = %#v, want nil for optional missing object", got)
}
})
t.Run("lists with combined selectors", func(t *testing.T) {
t.Parallel()
additional := labels.SelectorFromSet(labels.Set{"tenant": "team-a"})
got, err := (tpl.ResourceReference{
VersionKind: tplVersionKind("v1", "ConfigMap"),
Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "api"}},
}).LoadResources(ctx, cl, mapper, "team-a", []labels.Selector{additional}, nil, false, nil)
if err != nil {
t.Fatalf("LoadResources() unexpected error for list: %v", err)
}
if len(got) != 1 || got[0].GetName() != "settings" {
t.Fatalf("LoadResources() = %#v, want only team-a/settings", got)
}
})
t.Run("validates namespace", func(t *testing.T) {
t.Parallel()
_, err := (tpl.ResourceReference{
VersionKind: tplVersionKind("v1", "ConfigMap"),
}).LoadResources(ctx, cl, mapper, "team-a", nil, nil, false, func(ns string) error {
if ns != "team-a" {
t.Fatalf("validated namespace = %q", ns)
}
return nil
})
if err != nil {
t.Fatalf("LoadResources() unexpected validation error: %v", err)
}
})
t.Run("invalid apiVersion returns error", func(t *testing.T) {
t.Parallel()
_, err := (tpl.ResourceReference{
VersionKind: tplVersionKind("not/a/version", "ConfigMap"),
}).LoadResources(ctx, cl, mapper, "team-a", nil, nil, false, nil)
if err == nil {
t.Fatalf("LoadResources() expected error for invalid apiVersion")
}
})
}
func TestTemplateContextGatherContext(t *testing.T) {
t.Parallel()
ctx := context.Background()
scheme := runtime.NewScheme()
if err := corev1.AddToScheme(scheme); err != nil {
t.Fatalf("adding core scheme: %v", err)
}
cl := fake.NewClientBuilder().WithScheme(scheme).WithObjects(
configMap("team-a", "settings", map[string]string{"app": "api"}),
).Build()
templateContext := tpl.TemplateContext{
Resources: []*tpl.TemplateResourceReference{{
ResourceReference: tpl.ResourceReference{
VersionKind: tplVersionKind("v1", "ConfigMap"),
Name: "settings",
Optional: true,
},
Index: "configs",
}},
}
got, err := templateContext.GatherContext(ctx, cl, templateRESTMapper(), nil, "team-a", nil, nil)
if err != nil {
t.Fatalf("GatherContext() unexpected error: %v", err)
}
items := got["configs"].([]map[string]any)
if len(items) != 1 || items[0]["metadata"].(map[string]any)["name"] != "settings" {
t.Fatalf("GatherContext() = %#v", got)
}
asString, err := got.String()
if err != nil {
t.Fatalf("ReferenceContext.String() unexpected error: %v", err)
}
if !strings.Contains(asString, "settings") {
t.Fatalf("ReferenceContext.String() = %q, want settings", asString)
}
empty, err := (&tpl.TemplateContext{}).GatherContext(ctx, cl, templateRESTMapper(), nil, "team-a", nil, nil)
if err != nil {
t.Fatalf("GatherContext(empty) unexpected error: %v", err)
}
if !reflect.DeepEqual(empty, tpl.ReferenceContext{}) {
t.Fatalf("GatherContext(empty) = %#v, want empty context", empty)
}
}
func configMap(namespace, name string, lbls map[string]string) *corev1.ConfigMap {
return &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Namespace: namespace, Name: name, Labels: lbls}}
}
func templateRESTMapper() meta.RESTMapper {
mapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{{Version: "v1"}})
mapper.Add(schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}, meta.RESTScopeNamespace)
return mapper
}
func tplVersionKind(apiVersion, kind string) apiruntime.VersionKind {
return apiruntime.VersionKind{APIVersion: apiVersion, Kind: kind}
}