mirror of
https://github.com/kubevela/kubevela.git
synced 2026-05-17 23:07:34 +00:00
* Chore: Added fail fast validation logic of component having multiple steps including workflow, component etc. Signed-off-by: Chaitanya Reddy Onteddu <chaitanyareddy0702@gmail.com> * testing updated param filter logic Signed-off-by: Amit Singh <singhamitch@outlook.com> * Added validation logic for struct type parameter Signed-off-by: Chaitanya Reddy Onteddu <chaitanyareddy0702@gmail.com> * fixed code when struct type parameter is provided in component Signed-off-by: Chaitanya Reddy Onteddu <chaitanyareddy0702@gmail.com> * refactor: minor code improvements Signed-off-by: Amit Singh <singhamitch@outlook.com> * fixed go lint issue Signed-off-by: Chaitanya Reddy Onteddu <chaitanyareddy0702@gmail.com> * Chore: Add test cases for fail fast logic Signed-off-by: Vishal Kumar <vishal210893@gmail.com> * updated expect logic Signed-off-by: Chaitanya Reddy Onteddu <chaitanyareddy0702@gmail.com> * Added e2e test cases for required param validation Signed-off-by: Chaitanya Reddy Onteddu <chaitanyareddy0702@gmail.com> * Added feature gate in e2e test cases for required param validation Signed-off-by: Chaitanya Reddy Onteddu <chaitanyareddy0702@gmail.com> * Added feature gate make e2e_test file and removed for ginkgo test file Signed-off-by: Chaitanya Reddy Onteddu <chaitanyareddy0702@gmail.com> * Fixed code to quoted string Signed-off-by: Chaitanya Reddy Onteddu <chaitanyareddy0702@gmail.com> * Added logic and test case for policy type override Signed-off-by: Chaitanya Reddy Onteddu <chaitanyareddy0702@gmail.com> * Added license header Signed-off-by: Chaitanya Reddy Onteddu <chaitanyareddy0702@gmail.com> --------- Signed-off-by: Chaitanya Reddy Onteddu <chaitanyareddy0702@gmail.com> Signed-off-by: Amit Singh <singhamitch@outlook.com> Signed-off-by: Vishal Kumar <vishal210893@gmail.com> Co-authored-by: Amit Singh <singhamitch@outlook.com> Co-authored-by: Chaitanya Reddy Onteddu <chaitanyareddy0702@gmail.com>
231 lines
6.7 KiB
Go
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"
|
|
|
|
workflowv1alpha1 "github.com/kubevela/workflow/api/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,
|
|
workflowv1alpha1.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: []workflowv1alpha1.WorkflowStep{{
|
|
WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{
|
|
Name: "apply",
|
|
Type: "apply-component",
|
|
Inputs: workflowv1alpha1.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
|
|
}
|