Files
kubevela/pkg/definition/defkit/workflow_step_test.go
Vishal Kumar 3cd345c243 Fix: defkit CUE generation for task health, nested array schemas, and patch traits (#7041)
* Fix: Update JobHealth logic to reflect correct health status based on parallelism

Signed-off-by: Reetika Malhotra <malhotra.reetika25@gmail.com>
Signed-off-by: vishal210893 <vishal210893@gmail.com>

* Fix: Correct formatting in status output for better readability

Signed-off-by: Reetika Malhotra <malhotra.reetika25@gmail.com>
Signed-off-by: vishal210893 <vishal210893@gmail.com>

* Fix: Enhance CUE generation for nested array structs and lift shared conditions to parent nodes

Signed-off-by: Reetika Malhotra <malhotra.reetika25@gmail.com>
Signed-off-by: vishal210893 <vishal210893@gmail.com>

* Fix: Improve handling of array values in CUE generation for patchKey operations

Signed-off-by: Reetika Malhotra <malhotra.reetika25@gmail.com>
Signed-off-by: vishal210893 <vishal210893@gmail.com>

* Feat: Defkit Refactor and Clean-Up (#7042)

* feat: Enhance status and health policy CUE generation with field grouping, column alignment, `_isHealth` pattern, and annotation-based health disable.

Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com>

* feat: introduce defkit package for a structured Go API to define KubeVela component and trait templates with outputs, patches, and helpers.

Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com>

* refactor: Consolidate two `append` calls into one for health expression parts.

Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com>

---------

Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com>

update status.go

Signed-off-by: vishal210893 <vishal210893@gmail.com>

* Fix: Correct formatting in status output for better readability

Signed-off-by: Reetika Malhotra <malhotra.reetika25@gmail.com>

# Conflicts:
#	pkg/definition/defkit/status.go
Signed-off-by: vishal210893 <vishal210893@gmail.com>

* removed unitended commited file

Signed-off-by: Reetika Malhotra <malhotra.reetika25@gmail.com>
Signed-off-by: vishal210893 <vishal210893@gmail.com>

* Fix: Preserve explicit action variable names in BuiltinAction and update CUE generation

Signed-off-by: Reetika Malhotra <malhotra.reetika25@gmail.com>
Signed-off-by: vishal210893 <vishal210893@gmail.com>

* Fix: Update default WebhookConfig settings for improved configuration

Signed-off-by: Reetika Malhotra <malhotra.reetika25@gmail.com>
Signed-off-by: vishal210893 <vishal210893@gmail.com>

* Fix: Enhance CUE generation with ForEachMapOp support and add alias handling in workflow steps

Signed-off-by: Vaibhav Agrawal <vaibhav.agrawal0096@gmail.com>
Signed-off-by: vishal210893 <vishal210893@gmail.com>

---------

Signed-off-by: Reetika Malhotra <malhotra.reetika25@gmail.com>
Signed-off-by: vishal210893 <vishal210893@gmail.com>
Signed-off-by: Vaibhav Agrawal <vaibhav.agrawal0096@gmail.com>
Co-authored-by: Ayush Kumar <65535504+roguepikachu@users.noreply.github.com>
2026-02-18 06:24:57 -08:00

286 lines
8.7 KiB
Go

/*
Copyright 2025 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 defkit_test
import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/oam-dev/kubevela/pkg/definition/defkit"
)
var _ = Describe("WorkflowStepDefinition", func() {
Context("Basic Builder Methods", func() {
It("should create workflow step with name", func() {
step := defkit.NewWorkflowStep("deploy")
Expect(step.DefName()).To(Equal("deploy"))
Expect(step.DefType()).To(Equal(defkit.DefinitionTypeWorkflowStep))
})
It("should set description", func() {
step := defkit.NewWorkflowStep("deploy").
Description("A powerful deploy step")
Expect(step.GetDescription()).To(Equal("A powerful deploy step"))
})
It("should set category", func() {
step := defkit.NewWorkflowStep("deploy").
Category("Application Delivery")
Expect(step.GetCategory()).To(Equal("Application Delivery"))
})
It("should set scope", func() {
step := defkit.NewWorkflowStep("deploy").
Scope("Application")
Expect(step.GetScope()).To(Equal("Application"))
})
It("should add parameters using Params", func() {
step := defkit.NewWorkflowStep("deploy").
Params(
defkit.Bool("auto").Default(true),
defkit.Int("parallelism").Default(5),
)
Expect(step.GetParams()).To(HaveLen(2))
})
It("should add single parameter using Param", func() {
step := defkit.NewWorkflowStep("deploy").
Param(defkit.Bool("auto"))
Expect(step.GetParams()).To(HaveLen(1))
})
})
Context("Helper Method", func() {
It("should add helper definition with param", func() {
helperParam := defkit.Struct("placement").Fields(
defkit.Field("clusterName", defkit.ParamTypeString),
)
step := defkit.NewWorkflowStep("deploy").
Helper("Placement", helperParam)
helpers := step.GetHelperDefinitions()
Expect(helpers).To(HaveLen(1))
Expect(helpers[0].GetName()).To(Equal("Placement"))
Expect(helpers[0].HasParam()).To(BeTrue())
})
})
Context("Status and Health Methods", func() {
It("should set custom status", func() {
step := defkit.NewWorkflowStep("deploy").
CustomStatus("message: \"Deploying...\"")
Expect(step.GetCustomStatus()).To(Equal("message: \"Deploying...\""))
})
It("should set health policy", func() {
step := defkit.NewWorkflowStep("deploy").
HealthPolicy("isHealth: true")
Expect(step.GetHealthPolicy()).To(Equal("isHealth: true"))
})
It("should set health policy expression", func() {
h := defkit.Health()
step := defkit.NewWorkflowStep("deploy").
HealthPolicyExpr(h.Condition("Ready").IsTrue())
Expect(step.GetHealthPolicy()).NotTo(BeEmpty())
})
})
Context("Imports", func() {
It("should add imports with WithImports", func() {
step := defkit.NewWorkflowStep("deploy").
WithImports("vela/multicluster", "vela/builtin")
Expect(step.GetImports()).To(ConsistOf("vela/multicluster", "vela/builtin"))
})
})
Context("RawCUE", func() {
It("should set raw CUE and bypass template generation", func() {
rawCUE := `import (
"vela/multicluster"
)
"deploy": {
type: "workflow-step"
description: "Raw CUE step"
}
template: {
deploy: multicluster.#Deploy
parameter: auto: *true | bool
}`
step := defkit.NewWorkflowStep("deploy").RawCUE(rawCUE)
Expect(step.ToCue()).To(Equal(rawCUE))
})
})
Context("ToCue Generation", func() {
It("should generate complete CUE definition", func() {
step := defkit.NewWorkflowStep("deploy").
Description("Deploy step").
Category("Application Delivery").
Scope("Application").
Params(
defkit.Bool("auto").Default(true),
defkit.Int("parallelism").Default(5),
)
cue := step.ToCue()
Expect(cue).To(ContainSubstring(`type: "workflow-step"`))
Expect(cue).To(ContainSubstring(`annotations:`))
Expect(cue).To(ContainSubstring(`"category": "Application Delivery"`))
Expect(cue).To(ContainSubstring(`labels:`))
Expect(cue).To(ContainSubstring(`"scope": "Application"`))
Expect(cue).To(ContainSubstring(`template:`))
Expect(cue).To(ContainSubstring(`parameter:`))
})
It("should include imports in CUE output", func() {
step := defkit.NewWorkflowStep("deploy").
Description("Deploy step").
WithImports("vela/multicluster", "vela/builtin")
cue := step.ToCue()
Expect(cue).To(ContainSubstring(`import (`))
Expect(cue).To(ContainSubstring(`"vela/multicluster"`))
Expect(cue).To(ContainSubstring(`"vela/builtin"`))
})
})
Context("ToYAML Generation", func() {
It("should generate valid YAML manifest", func() {
step := defkit.NewWorkflowStep("deploy").
Description("Deploy components").
Category("Application Delivery").
Scope("Application").
Params(defkit.Bool("auto").Default(true))
yamlBytes, err := step.ToYAML()
Expect(err).NotTo(HaveOccurred())
yaml := string(yamlBytes)
Expect(yaml).To(ContainSubstring("kind: WorkflowStepDefinition"))
Expect(yaml).To(ContainSubstring("name: deploy"))
})
})
Context("WorkflowStepTemplate", func() {
It("should create template with Suspend action", func() {
tpl := defkit.NewWorkflowStepTemplate()
tpl.Suspend("Waiting for approval")
Expect(tpl.GetSuspendMessage()).To(Equal("Waiting for approval"))
})
It("should create template with SuspendIf action", func() {
auto := defkit.Bool("auto").Default(true)
tpl := defkit.NewWorkflowStepTemplate()
tpl.SuspendIf(defkit.Not(auto.IsTrue()), "Waiting for approval")
Expect(tpl.GetActions()).To(HaveLen(1))
})
It("should create template with Builtin action", func() {
policies := defkit.StringList("policies")
parallelism := defkit.Int("parallelism").Default(5)
tpl := defkit.NewWorkflowStepTemplate()
tpl.Builtin("deploy", "multicluster.#Deploy").
WithParams(map[string]defkit.Value{
"policies": policies,
"parallelism": parallelism,
}).Build()
Expect(tpl.GetActions()).To(HaveLen(1))
})
})
Context("Template with Actions", func() {
It("should generate CUE with template actions", func() {
auto := defkit.Bool("auto").Default(true)
policies := defkit.StringList("policies")
parallelism := defkit.Int("parallelism").Default(5)
step := defkit.NewWorkflowStep("deploy").
Description("Deploy step").
WithImports("vela/multicluster", "vela/builtin").
Params(auto, policies, parallelism).
Template(func(tpl *defkit.WorkflowStepTemplate) {
tpl.SuspendIf(defkit.Not(auto.IsTrue()), "Waiting approval to the deploy step")
tpl.Builtin("deploy", "multicluster.#Deploy").
WithParams(map[string]defkit.Value{
"policies": policies,
"parallelism": parallelism,
}).Build()
})
cue := step.ToCue()
Expect(cue).To(ContainSubstring(`template:`))
})
It("should preserve explicit builtin action names", func() {
step := defkit.NewWorkflowStep("apply-deployment").
Description("Apply deployment with specified image and cmd.").
WithImports("vela/kube", "vela/builtin").
Template(func(tpl *defkit.WorkflowStepTemplate) {
tpl.Builtin("output", "kube.#Apply").
WithParams(map[string]defkit.Value{
"value": defkit.Reference("parameter.value"),
}).
Build()
tpl.Builtin("wait", "builtin.#ConditionalWait").
WithParams(map[string]defkit.Value{
"continue": defkit.Reference("output.$returns.value.status.readyReplicas == parameter.replicas"),
}).
Build()
})
cue := step.ToCue()
Expect(cue).To(ContainSubstring(`output: kube.#Apply & {`))
Expect(cue).To(ContainSubstring(`wait: builtin.#ConditionalWait & {`))
Expect(cue).NotTo(ContainSubstring(`apply: kube.#Apply & {`))
Expect(cue).NotTo(ContainSubstring(`conditionalwait: builtin.#ConditionalWait & {`))
})
})
Context("Registry", func() {
BeforeEach(func() {
defkit.Clear()
})
AfterEach(func() {
defkit.Clear()
})
It("should register workflow steps", func() {
step1 := defkit.NewWorkflowStep("deploy").Description("Deploy").Category("Application Delivery")
step2 := defkit.NewWorkflowStep("suspend").Description("Suspend").Category("Workflow Control")
comp := defkit.NewComponent("webservice").Description("Component")
defkit.Register(step1)
defkit.Register(step2)
defkit.Register(comp)
Expect(defkit.Count()).To(Equal(3))
Expect(defkit.WorkflowSteps()).To(HaveLen(2))
})
})
})