Files
flagger/pkg/controller/controller_test.go
Barrera, Angel eeeac3543a fix: default namespace for cross-namespace ref validation
When cross-namespace references are disabled, ensure that UpstreamRef,
MetricTemplateRef, and AlertProviderRef default to the canary's namespace
if their namespace field is empty. This aligns the validation logic with
the rest of the controller and prevents false positives when the namespace
is omitted.

Fixes #1827

Signed-off-by: Barrera, Angel <angelbarrerasanchez@protonmail.com>
2025-10-08 09:16:29 +02:00

226 lines
5.3 KiB
Go

package controller
import (
"testing"
flaggerv1 "github.com/fluxcd/flagger/pkg/apis/flagger/v1beta1"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestController_verifyCanary(t *testing.T) {
tests := []struct {
name string
canary flaggerv1.Canary
wantErr bool
}{
{
name: "Gloo upstream in a different namespace should return an error",
canary: flaggerv1.Canary{
ObjectMeta: metav1.ObjectMeta{
Name: "cd-1",
Namespace: "default",
},
Spec: flaggerv1.CanarySpec{
UpstreamRef: &flaggerv1.CrossNamespaceObjectReference{
Name: "upstream",
Namespace: "test",
},
Analysis: &flaggerv1.CanaryAnalysis{},
},
},
wantErr: true,
},
{
name: "Gloo upstream in the same namespace is allowed",
canary: flaggerv1.Canary{
ObjectMeta: metav1.ObjectMeta{
Name: "cd-1",
Namespace: "default",
},
Spec: flaggerv1.CanarySpec{
UpstreamRef: &flaggerv1.CrossNamespaceObjectReference{
Name: "upstream",
Namespace: "default",
},
Analysis: &flaggerv1.CanaryAnalysis{},
},
},
wantErr: false,
},
{
name: "MetricTemplate in a different namespace should return an error",
canary: flaggerv1.Canary{
ObjectMeta: metav1.ObjectMeta{
Name: "cd-1",
Namespace: "default",
},
Spec: flaggerv1.CanarySpec{
Analysis: &flaggerv1.CanaryAnalysis{
Metrics: []flaggerv1.CanaryMetric{
{
TemplateRef: &flaggerv1.CrossNamespaceObjectReference{
Name: "mt-1",
Namespace: "test",
},
},
},
},
},
},
wantErr: true,
},
{
name: "MetricTemplate in same namespace with no namespace specified should not return an error",
canary: flaggerv1.Canary{
ObjectMeta: metav1.ObjectMeta{
Name: "cd-1",
Namespace: "default",
},
Spec: flaggerv1.CanarySpec{
Analysis: &flaggerv1.CanaryAnalysis{
Metrics: []flaggerv1.CanaryMetric{
{
TemplateRef: &flaggerv1.CrossNamespaceObjectReference{
Name: "mt-1",
Namespace: "",
},
},
},
},
},
},
wantErr: false,
},
{
name: "AlertProvider in a different namespace should return an error",
canary: flaggerv1.Canary{
ObjectMeta: metav1.ObjectMeta{
Name: "cd-1",
Namespace: "default",
},
Spec: flaggerv1.CanarySpec{
Analysis: &flaggerv1.CanaryAnalysis{
Alerts: []flaggerv1.CanaryAlert{
{
ProviderRef: flaggerv1.CrossNamespaceObjectReference{
Name: "ap-1",
Namespace: "test",
},
},
},
},
},
},
wantErr: true,
},
{
name: "knative provider with non-knative service should return an error",
canary: flaggerv1.Canary{
ObjectMeta: metav1.ObjectMeta{
Name: "cd-1",
Namespace: "default",
},
Spec: flaggerv1.CanarySpec{
Provider: "knative",
TargetRef: flaggerv1.LocalObjectReference{
Kind: "Deployment",
Name: "podinfo",
},
Analysis: &flaggerv1.CanaryAnalysis{},
},
},
wantErr: true,
},
{
name: "knative service with non-knative provider should return an error",
canary: flaggerv1.Canary{
ObjectMeta: metav1.ObjectMeta{
Name: "cd-1",
Namespace: "default",
},
Spec: flaggerv1.CanarySpec{
Provider: "istio",
TargetRef: flaggerv1.LocalObjectReference{
Kind: "Service",
APIVersion: "serving.knative.dev/v1",
Name: "podinfo",
},
Analysis: &flaggerv1.CanaryAnalysis{},
},
},
wantErr: true,
},
{
name: "knative service with autoscaler ref should return an error",
canary: flaggerv1.Canary{
ObjectMeta: metav1.ObjectMeta{
Name: "cd-1",
Namespace: "default",
},
Spec: flaggerv1.CanarySpec{
Provider: "knative",
AutoscalerRef: &flaggerv1.AutoscalerReference{},
TargetRef: flaggerv1.LocalObjectReference{
Kind: "Service",
APIVersion: "serving.knative.dev/v1",
Name: "podinfo",
},
Analysis: &flaggerv1.CanaryAnalysis{},
},
},
wantErr: true,
},
{
name: "knative service with knative provider is okay",
canary: flaggerv1.Canary{
ObjectMeta: metav1.ObjectMeta{
Name: "cd-1",
Namespace: "default",
},
Spec: flaggerv1.CanarySpec{
Provider: "knative",
TargetRef: flaggerv1.LocalObjectReference{
Kind: "Service",
APIVersion: "serving.knative.dev/v1",
Name: "podinfo",
},
Analysis: &flaggerv1.CanaryAnalysis{},
},
},
wantErr: false,
},
{
name: "session affinity with same cookie names should return an error",
canary: flaggerv1.Canary{
ObjectMeta: metav1.ObjectMeta{
Name: "cd-1",
Namespace: "default",
},
Spec: flaggerv1.CanarySpec{
Analysis: &flaggerv1.CanaryAnalysis{
SessionAffinity: &flaggerv1.SessionAffinity{
CookieName: "smth",
PrimaryCookieName: "smth",
},
},
},
},
wantErr: true,
},
}
ctrl := &Controller{
noCrossNamespaceRefs: true,
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := ctrl.verifyCanary(&test.canary)
if test.wantErr {
require.Error(t, err)
}
})
}
}