Files
kubevela/test/e2e-test/requiredparam_validation_test.go
Amit Singh 5ead6db8d7
Some checks failed
Webhook Upgrade Validation / webhook-upgrade-check (push) Failing after 1m29s
Chore: bumps up pkg and workflow dependency versions (#7026)
* chore: bumps up workflow and pkg versions and updates import statements

Signed-off-by: Amit Singh <singhamitch@outlook.com>

* chore: minor linter fixes

Signed-off-by: Amit Singh <singhamitch@outlook.com>

---------

Signed-off-by: Amit Singh <singhamitch@outlook.com>
2026-01-20 15:32:03 +00:00

231 lines
6.7 KiB
Go

/*
Copyright 2024 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controllers_test
import (
"context"
"encoding/json"
"fmt"
"time"
wfTypesv1alpha1 "github.com/kubevela/pkg/apis/oam/v1alpha1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/pkg/oam/util"
)
var _ = Describe("Application required-parameter validation", Ordered, func() {
var (
ctx context.Context
nsName string
namespace corev1.Namespace
)
BeforeAll(func() {
ctx = context.Background()
nsName = randomNamespaceName("requiredparam-validation-test")
namespace = corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: nsName}}
By("creating the test namespace")
Eventually(func() error {
return k8sClient.Create(ctx, &namespace)
}, 3*time.Second, 300*time.Millisecond).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
By("Apply the component definition")
Expect(k8sClient.Create(ctx, newConfigMapComponent(nsName))).To(Succeed())
})
AfterEach(func() {
By("Cleaning up resources after each test")
Expect(k8sClient.DeleteAllOf(ctx, &v1beta1.Application{}, client.InNamespace(nsName))).To(Succeed())
})
AfterAll(func() {
By("Cleaning up resources after all the test")
Expect(k8sClient.DeleteAllOf(ctx, &v1beta1.ComponentDefinition{}, client.InNamespace(nsName))).To(Succeed())
Expect(k8sClient.Delete(ctx, &namespace)).To(Succeed())
})
// -------------------------------------------------------------------------
// Scenario 1: missing parameter → expect failure
// -------------------------------------------------------------------------
It("fails when the required parameter is missing", func() {
app := appWithWorkflow.DeepCopy()
app.Name = "app-missing-param"
app.Namespace = nsName
err := k8sClient.Create(ctx, app)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring(fmt.Sprintf(`component %q: missing parameters: secondkey.value2.value3.value5`, "configmap-component")))
})
// -------------------------------------------------------------------------
// Scenario 2: param provided via workflow → expect success
// -------------------------------------------------------------------------
It("succeeds when the parameter is provided in the workflow", func() {
app := appWithWorkflow.DeepCopy()
app.Name = "app-with-param-wf"
app.Namespace = nsName
// inject missing parameter
app.Spec.Workflow.Steps[0].Inputs = append(app.Spec.Workflow.Steps[0].Inputs,
wfTypesv1alpha1.InputItem{
ParameterKey: "secondkey.value2.value3.value5",
From: "dummy",
})
Expect(k8sClient.Create(ctx, app)).To(Succeed())
})
// -------------------------------------------------------------------------
// Scenario 3: param provided via policy → expect success
// -------------------------------------------------------------------------
It("succeeds when the parameter is provided in a policy", func() {
app := appWithPolicy.DeepCopy()
app.Name = "app-with-param-policy"
app.Namespace = nsName
Expect(k8sClient.Create(ctx, app)).To(Succeed())
})
})
/* -------------------------------------------------------------------------- */
/* Helpers */
/* -------------------------------------------------------------------------- */
func newConfigMapComponent(namespace string) *v1beta1.ComponentDefinition {
return &v1beta1.ComponentDefinition{
TypeMeta: metav1.TypeMeta{
Kind: "ComponentDefinition",
APIVersion: "core.oam.dev/v1beta1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "configmap-component",
Namespace: namespace, // set it here
},
Spec: v1beta1.ComponentDefinitionSpec{
Schematic: &common.Schematic{
CUE: &common.CUE{Template: configMapOutputTemp},
},
},
}
}
var configMapOutputTemp = `
parameter: {
firstkey: string & !="" & !~".*-$"
secondkey: {
value1: string
value2: {
value3: {
value4: *"default-value-2" | string
value5: string
}
}
}
thirdkey?: string
}
output: {
apiVersion: "v1"
kind: "ConfigMap"
metadata: { name: context.name }
data: {
one: parameter.firstkey
two: parameter.secondkey.value2.value3.value5
three: parameter.secondkey.value1
four: parameter.thirdkey
}
}
`
var appWithWorkflow = v1beta1.Application{
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{{
Name: "configmap-component",
Type: "configmap-component",
Properties: &runtime.RawExtension{Raw: []byte(`{
"secondkey": { "value2": { "value3": { "value4": "1" } } }
}`)},
}},
Workflow: &v1beta1.Workflow{
Steps: []wfTypesv1alpha1.WorkflowStep{{
WorkflowStepBase: wfTypesv1alpha1.WorkflowStepBase{
Name: "apply",
Type: "apply-component",
Inputs: wfTypesv1alpha1.StepInputs{
{ParameterKey: "firstkey", From: "dummy1"},
{ParameterKey: "secondkey.value1", From: "dummy2"},
{ParameterKey: "thirdkey", From: "dummy3"},
},
Properties: util.Object2RawExtension(map[string]any{"component": "express-server"}),
},
}},
},
},
}
var appWithPolicy = v1beta1.Application{
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{{
Name: "app-policy",
Type: "configmap-component",
Properties: &runtime.RawExtension{Raw: []byte(`{
"secondkey": { "value2": { "value3": { "value4": "1" } } }
}`)},
}},
Policies: []v1beta1.AppPolicy{{
Name: "override-configmap-data",
Type: "override",
Properties: &runtime.RawExtension{Raw: mustJSON(policyProperties)},
}},
},
}
var policyProperties = map[string]any{
"components": []any{map[string]any{
"name": "express-server",
"properties": map[string]any{
"firstkey": "nginx:1.20",
"secondkey": map[string]any{
"value1": "abc",
"value2": map[string]any{
"value3": map[string]any{
"value5": "1",
},
},
},
"thirdkey": "123",
},
}},
}
func mustJSON(v any) []byte {
out, err := json.Marshal(v)
if err != nil {
panic(err)
}
return out
}