mirror of
https://github.com/kubevela/kubevela.git
synced 2026-05-19 07:46:51 +00:00
* Feat: Add NotEmpty and NegativePattern constraints to StringParam; implement Closed for MapParam Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: add validation support for array and map parameters - Introduced validators for ArrayParam and MapParam, allowing for cross-field validation within structured parameters. - Added NonEmpty validation for ArrayParam to ensure arrays are not empty. - Implemented ConditionalStructOp for conditional struct generation based on specified conditions. - Created a new Validator type for defining validation rules with optional guard conditions. - Added tests for various validation scenarios, including mutual exclusion and conditional parameters. - Enhanced the CUE generation logic to incorporate new validation features and conditional struct handling. Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: extend fluent API with new scoped field conditions and improve validation checks Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: enhance ArrayParam with NotEmpty constraint and update ScopedField documentation Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: rename ScopedField to LocalField for improved clarity in condition building Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: refactor local field conditions to use RegexMatch and streamline condition building Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: simplify condition handling by removing unused comparison types and refactoring NotCondition usage Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: remove unused raw CUE block handling from baseDefinition and ComponentDefinition Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * test: update condition handling in parameter tests to use NotExpr and Cond methods Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: remove negative pattern handling from StringParam and related tests Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: add support for emitting raw header blocks in template generation Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: remove non-empty check from ArrayParam and update related tests Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: convert parameter constraint tests to use Ginkgo and Gomega for improved readability and maintainability Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: extend fluent APIs for OAM with new CUE generation tests and condition evaluations Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: clean up whitespace in component, cuegen, expr, param, and resource files Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: enhance CUE generation by adding support for new expression types and iterator references Signed-off-by: Ayush Kumar <aykumar@guidewire.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: remove unnecessary whitespace in cuegen.go Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * refactor: rename LenOf to LenOfExpr for clarity in comparison methods Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * feat: enhance CUE generation and validation for string arrays in ArrayParam Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * ci: retrigger checks Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> --------- Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <aykumar@guidewire.com> Co-authored-by: Ayush Kumar <aykumar@guidewire.com>
780 lines
22 KiB
Go
780 lines
22 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("Render", func() {
|
|
|
|
Context("Render with context references", func() {
|
|
It("should resolve context.name", func() {
|
|
comp := defkit.NewComponent("test").
|
|
Workload("apps/v1", "Deployment").
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("apps/v1", "Deployment").
|
|
Set("metadata.name", defkit.VelaCtx().Name()),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(
|
|
defkit.TestContext().WithName("my-comp"),
|
|
)
|
|
|
|
Expect(rendered.Get("metadata.name")).To(Equal("my-comp"))
|
|
})
|
|
|
|
It("should resolve context.namespace", func() {
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
Set("metadata.namespace", defkit.VelaCtx().Namespace()),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(
|
|
defkit.TestContext().WithNamespace("production"),
|
|
)
|
|
|
|
Expect(rendered.Get("metadata.namespace")).To(Equal("production"))
|
|
})
|
|
|
|
It("should resolve context.appName", func() {
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
Set("metadata.labels.app", defkit.VelaCtx().AppName()),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(
|
|
defkit.TestContext().WithAppName("myapp"),
|
|
)
|
|
|
|
Expect(rendered.Get("metadata.labels.app")).To(Equal("myapp"))
|
|
})
|
|
|
|
It("should resolve context.appRevision", func() {
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
Set("metadata.labels.revision", defkit.VelaCtx().AppRevision()),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(
|
|
defkit.TestContext().WithAppRevision("myapp-v3"),
|
|
)
|
|
|
|
Expect(rendered.Get("metadata.labels.revision")).To(Equal("myapp-v3"))
|
|
})
|
|
})
|
|
|
|
Context("Render with various param types", func() {
|
|
It("should resolve string params", func() {
|
|
image := defkit.String("image").Default("nginx")
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("apps/v1", "Deployment").
|
|
Params(image).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("apps/v1", "Deployment").
|
|
Set("spec.template.spec.containers[0].image", image),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(
|
|
defkit.TestContext().WithParam("image", "nginx:1.21"),
|
|
)
|
|
Expect(rendered.Get("spec.template.spec.containers[0].image")).To(Equal("nginx:1.21"))
|
|
})
|
|
|
|
It("should use default values when param not set", func() {
|
|
replicas := defkit.Int("replicas").Default(3)
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("apps/v1", "Deployment").
|
|
Params(replicas).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("apps/v1", "Deployment").
|
|
Set("spec.replicas", replicas),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(defkit.TestContext())
|
|
Expect(rendered.Get("spec.replicas")).To(Equal(3))
|
|
})
|
|
|
|
It("should resolve int params", func() {
|
|
port := defkit.Int("port").Default(80)
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("apps/v1", "Deployment").
|
|
Params(port).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("apps/v1", "Deployment").
|
|
Set("spec.template.spec.containers[0].ports[0].containerPort", port),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(
|
|
defkit.TestContext().WithParam("port", 8080),
|
|
)
|
|
Expect(rendered.Get("spec.template.spec.containers[0].ports[0].containerPort")).To(Equal(8080))
|
|
})
|
|
|
|
It("should resolve bool params", func() {
|
|
enabled := defkit.Bool("enabled").Default(false)
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Params(enabled).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
Set("data.enabled", enabled),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(
|
|
defkit.TestContext().WithParam("enabled", true),
|
|
)
|
|
Expect(rendered.Get("data.enabled")).To(BeTrue())
|
|
})
|
|
|
|
It("should resolve float params", func() {
|
|
ratio := defkit.Float("ratio").Default(0.5)
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Params(ratio).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
Set("data.ratio", ratio),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(
|
|
defkit.TestContext().WithParam("ratio", 0.75),
|
|
)
|
|
Expect(rendered.Get("data.ratio")).To(Equal(0.75))
|
|
})
|
|
|
|
It("should resolve enum params", func() {
|
|
env := defkit.Enum("environment").Values("dev", "staging", "prod").Default("dev")
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Params(env).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
Set("data.env", env),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(
|
|
defkit.TestContext().WithParam("environment", "prod"),
|
|
)
|
|
Expect(rendered.Get("data.env")).To(Equal("prod"))
|
|
})
|
|
|
|
It("should resolve map params", func() {
|
|
labels := defkit.Object("labels")
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Params(labels).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
Set("metadata.labels", labels),
|
|
)
|
|
})
|
|
|
|
labelData := map[string]any{"app": "test", "env": "dev"}
|
|
rendered := comp.Render(
|
|
defkit.TestContext().WithParam("labels", labelData),
|
|
)
|
|
Expect(rendered.Get("metadata.labels")).To(Equal(labelData))
|
|
})
|
|
|
|
It("should resolve literal values", func() {
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
Set("data.fixed", defkit.Lit("constant-value")).
|
|
Set("data.count", defkit.Lit(42)).
|
|
Set("data.flag", defkit.Lit(true)),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(defkit.TestContext())
|
|
Expect(rendered.Get("data.fixed")).To(Equal("constant-value"))
|
|
Expect(rendered.Get("data.count")).To(Equal(42))
|
|
Expect(rendered.Get("data.flag")).To(BeTrue())
|
|
})
|
|
})
|
|
|
|
Context("Render with conditional operations", func() {
|
|
It("should apply SetIf when condition is true", func() {
|
|
cpu := defkit.String("cpu")
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("apps/v1", "Deployment").
|
|
Params(cpu).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("apps/v1", "Deployment").
|
|
SetIf(cpu.IsSet(), "spec.template.spec.containers[0].resources.limits.cpu", cpu),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(
|
|
defkit.TestContext().WithParam("cpu", "500m"),
|
|
)
|
|
Expect(rendered.Get("spec.template.spec.containers[0].resources.limits.cpu")).To(Equal("500m"))
|
|
})
|
|
|
|
It("should skip SetIf when condition is false", func() {
|
|
cpu := defkit.String("cpu")
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("apps/v1", "Deployment").
|
|
Params(cpu).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("apps/v1", "Deployment").
|
|
SetIf(cpu.IsSet(), "spec.template.spec.containers[0].resources.limits.cpu", cpu),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(defkit.TestContext())
|
|
Expect(rendered.Get("spec.template.spec.containers[0].resources.limits.cpu")).To(BeNil())
|
|
})
|
|
|
|
It("should handle If/EndIf blocks", func() {
|
|
enabled := defkit.Bool("enabled")
|
|
replicas := defkit.Int("replicas").Default(1)
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("apps/v1", "Deployment").
|
|
Params(enabled, replicas).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("apps/v1", "Deployment").
|
|
If(defkit.Eq(enabled, defkit.Lit(true))).
|
|
Set("spec.replicas", replicas).
|
|
EndIf(),
|
|
)
|
|
})
|
|
|
|
// Condition true
|
|
renderedTrue := comp.Render(
|
|
defkit.TestContext().
|
|
WithParam("enabled", true).
|
|
WithParam("replicas", 5),
|
|
)
|
|
Expect(renderedTrue.Get("spec.replicas")).To(Equal(5))
|
|
|
|
// Condition false
|
|
renderedFalse := comp.Render(
|
|
defkit.TestContext().
|
|
WithParam("enabled", false).
|
|
WithParam("replicas", 5),
|
|
)
|
|
Expect(renderedFalse.Get("spec.replicas")).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("Render with comparison conditions", func() {
|
|
It("should evaluate equality comparison", func() {
|
|
env := defkit.String("env").Default("dev")
|
|
replicas := defkit.Int("replicas").Default(1)
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("apps/v1", "Deployment").
|
|
Params(env, replicas).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("apps/v1", "Deployment").
|
|
SetIf(defkit.Eq(env, defkit.Lit("prod")), "spec.replicas", defkit.Lit(3)),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(
|
|
defkit.TestContext().WithParam("env", "prod"),
|
|
)
|
|
Expect(rendered.Get("spec.replicas")).To(Equal(3))
|
|
|
|
renderedDev := comp.Render(
|
|
defkit.TestContext().WithParam("env", "dev"),
|
|
)
|
|
Expect(renderedDev.Get("spec.replicas")).To(BeNil())
|
|
})
|
|
|
|
It("should evaluate inequality comparison", func() {
|
|
env := defkit.String("env").Default("dev")
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Params(env).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
SetIf(defkit.Ne(env, defkit.Lit("prod")), "data.debug", defkit.Lit("true")),
|
|
)
|
|
})
|
|
|
|
renderedDev := comp.Render(
|
|
defkit.TestContext().WithParam("env", "dev"),
|
|
)
|
|
Expect(renderedDev.Get("data.debug")).To(Equal("true"))
|
|
|
|
renderedProd := comp.Render(
|
|
defkit.TestContext().WithParam("env", "prod"),
|
|
)
|
|
Expect(renderedProd.Get("data.debug")).To(BeNil())
|
|
})
|
|
|
|
It("should evaluate numeric comparisons", func() {
|
|
replicas := defkit.Int("replicas").Default(1)
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Params(replicas).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
SetIf(defkit.Gt(replicas, defkit.Lit(1)), "data.scaled", defkit.Lit("true")),
|
|
)
|
|
})
|
|
|
|
renderedScaled := comp.Render(
|
|
defkit.TestContext().WithParam("replicas", 3),
|
|
)
|
|
Expect(renderedScaled.Get("data.scaled")).To(Equal("true"))
|
|
|
|
renderedSingle := comp.Render(
|
|
defkit.TestContext().WithParam("replicas", 1),
|
|
)
|
|
Expect(renderedSingle.Get("data.scaled")).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("Render with logical conditions", func() {
|
|
It("should evaluate And conditions", func() {
|
|
enabled := defkit.Bool("enabled")
|
|
debug := defkit.Bool("debug")
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Params(enabled, debug).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
SetIf(
|
|
defkit.And(
|
|
defkit.Eq(enabled, defkit.Lit(true)),
|
|
defkit.Eq(debug, defkit.Lit(true)),
|
|
),
|
|
"data.verbose", defkit.Lit("true"),
|
|
),
|
|
)
|
|
})
|
|
|
|
// Both true
|
|
rendered := comp.Render(
|
|
defkit.TestContext().
|
|
WithParam("enabled", true).
|
|
WithParam("debug", true),
|
|
)
|
|
Expect(rendered.Get("data.verbose")).To(Equal("true"))
|
|
|
|
// One false
|
|
renderedPartial := comp.Render(
|
|
defkit.TestContext().
|
|
WithParam("enabled", true).
|
|
WithParam("debug", false),
|
|
)
|
|
Expect(renderedPartial.Get("data.verbose")).To(BeNil())
|
|
})
|
|
|
|
It("should evaluate Or conditions", func() {
|
|
env := defkit.String("env")
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Params(env).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
SetIf(
|
|
defkit.Or(
|
|
defkit.Eq(env, defkit.Lit("staging")),
|
|
defkit.Eq(env, defkit.Lit("prod")),
|
|
),
|
|
"data.production-like", defkit.Lit("true"),
|
|
),
|
|
)
|
|
})
|
|
|
|
// Staging matches
|
|
renderedStaging := comp.Render(
|
|
defkit.TestContext().WithParam("env", "staging"),
|
|
)
|
|
Expect(renderedStaging.Get("data.production-like")).To(Equal("true"))
|
|
|
|
// Dev doesn't match
|
|
renderedDev := comp.Render(
|
|
defkit.TestContext().WithParam("env", "dev"),
|
|
)
|
|
Expect(renderedDev.Get("data.production-like")).To(BeNil())
|
|
})
|
|
|
|
It("should evaluate Not conditions", func() {
|
|
debug := defkit.Bool("debug")
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Params(debug).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
SetIf(
|
|
defkit.Not(defkit.Eq(debug, defkit.Lit(true))),
|
|
"data.optimized", defkit.Lit("true"),
|
|
),
|
|
)
|
|
})
|
|
|
|
renderedNoDebug := comp.Render(
|
|
defkit.TestContext().WithParam("debug", false),
|
|
)
|
|
Expect(renderedNoDebug.Get("data.optimized")).To(Equal("true"))
|
|
|
|
renderedDebug := comp.Render(
|
|
defkit.TestContext().WithParam("debug", true),
|
|
)
|
|
Expect(renderedDebug.Get("data.optimized")).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("Render with transformed values", func() {
|
|
It("should apply transformation to value", func() {
|
|
port := defkit.Int("port").Default(80)
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Params(port).
|
|
Template(func(tpl *defkit.Template) {
|
|
portStr := defkit.Transform(port, func(v any) any {
|
|
if n, ok := v.(int); ok {
|
|
return n * 2
|
|
}
|
|
return v
|
|
})
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
Set("data.doubledPort", portStr),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(
|
|
defkit.TestContext().WithParam("port", 8080),
|
|
)
|
|
Expect(rendered.Get("data.doubledPort")).To(Equal(16160))
|
|
})
|
|
|
|
It("should handle nil transform function", func() {
|
|
port := defkit.Int("port").Default(80)
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Params(port).
|
|
Template(func(tpl *defkit.Template) {
|
|
noopTransform := defkit.Transform(port, nil)
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
Set("data.port", noopTransform),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(
|
|
defkit.TestContext().WithParam("port", 8080),
|
|
)
|
|
Expect(rendered.Get("data.port")).To(Equal(8080))
|
|
})
|
|
})
|
|
|
|
Context("RenderAll with auxiliary outputs", func() {
|
|
It("should render primary and auxiliary outputs", func() {
|
|
comp := defkit.NewComponent("test").
|
|
Workload("apps/v1", "Deployment").
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("apps/v1", "Deployment").
|
|
Set("spec.replicas", defkit.Lit(1)),
|
|
)
|
|
tpl.Outputs("service",
|
|
defkit.NewResource("v1", "Service").
|
|
Set("spec.type", defkit.Lit("ClusterIP")),
|
|
)
|
|
tpl.Outputs("configmap",
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
Set("data.key", defkit.Lit("value")),
|
|
)
|
|
})
|
|
|
|
outputs := comp.RenderAll(defkit.TestContext())
|
|
|
|
Expect(outputs.Primary).NotTo(BeNil())
|
|
Expect(outputs.Primary.Kind()).To(Equal("Deployment"))
|
|
Expect(outputs.Auxiliary).To(HaveLen(2))
|
|
Expect(outputs.Auxiliary["service"].Kind()).To(Equal("Service"))
|
|
Expect(outputs.Auxiliary["configmap"].Kind()).To(Equal("ConfigMap"))
|
|
})
|
|
|
|
It("should filter conditional outputs when condition is false", func() {
|
|
enabled := defkit.Bool("enabled")
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("apps/v1", "Deployment").
|
|
Params(enabled).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("apps/v1", "Deployment"),
|
|
)
|
|
tpl.OutputsIf(
|
|
defkit.Eq(enabled, defkit.Lit(true)),
|
|
"service",
|
|
defkit.NewResource("v1", "Service"),
|
|
)
|
|
})
|
|
|
|
// Condition false - service should be excluded
|
|
outputs := comp.RenderAll(
|
|
defkit.TestContext().WithParam("enabled", false),
|
|
)
|
|
Expect(outputs.Auxiliary).To(BeEmpty())
|
|
|
|
// Condition true - service should be included
|
|
outputsEnabled := comp.RenderAll(
|
|
defkit.TestContext().WithParam("enabled", true),
|
|
)
|
|
Expect(outputsEnabled.Auxiliary).To(HaveKey("service"))
|
|
})
|
|
})
|
|
|
|
Context("RenderedResource nil safety", func() {
|
|
It("should return empty values for nil RenderedResource", func() {
|
|
var r *defkit.RenderedResource
|
|
Expect(r.APIVersion()).To(BeEmpty())
|
|
Expect(r.Kind()).To(BeEmpty())
|
|
Expect(r.Get("any.path")).To(BeNil())
|
|
Expect(r.Data()).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("Render with nil template", func() {
|
|
It("should return nil output for component with no template", func() {
|
|
comp := defkit.NewComponent("test").
|
|
Workload("apps/v1", "Deployment")
|
|
|
|
rendered := comp.Render(defkit.TestContext())
|
|
Expect(rendered).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("Nested path operations", func() {
|
|
It("should handle deeply nested paths", func() {
|
|
comp := defkit.NewComponent("test").
|
|
Workload("apps/v1", "Deployment").
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("apps/v1", "Deployment").
|
|
Set("spec.template.spec.containers[0].env[0].name", defkit.Lit("FOO")).
|
|
Set("spec.template.spec.containers[0].env[0].value", defkit.Lit("bar")),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(defkit.TestContext())
|
|
Expect(rendered.Get("spec.template.spec.containers[0].env[0].name")).To(Equal("FOO"))
|
|
Expect(rendered.Get("spec.template.spec.containers[0].env[0].value")).To(Equal("bar"))
|
|
})
|
|
|
|
It("should handle map key bracket notation", func() {
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
Set("metadata.labels[app.kubernetes.io/name]", defkit.Lit("myapp")),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(defkit.TestContext())
|
|
labels := rendered.Get("metadata.labels")
|
|
Expect(labels).NotTo(BeNil())
|
|
labelsMap := labels.(map[string]any)
|
|
Expect(labelsMap["app.kubernetes.io/name"]).To(Equal("myapp"))
|
|
})
|
|
})
|
|
|
|
Context("HasExposedPorts condition", func() {
|
|
It("should return true when ports have expose=true", func() {
|
|
ports := defkit.Array("ports")
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Params(ports).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
SetIf(defkit.HasExposedPorts(ports), "data.hasExposed", defkit.Lit("true")),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(
|
|
defkit.TestContext().WithParam("ports", []any{
|
|
map[string]any{"port": 80, "expose": true},
|
|
map[string]any{"port": 443, "expose": false},
|
|
}),
|
|
)
|
|
Expect(rendered.Get("data.hasExposed")).To(Equal("true"))
|
|
})
|
|
|
|
It("should return false when no ports have expose=true", func() {
|
|
ports := defkit.Array("ports")
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Params(ports).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
SetIf(defkit.HasExposedPorts(ports), "data.hasExposed", defkit.Lit("true")),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(
|
|
defkit.TestContext().WithParam("ports", []any{
|
|
map[string]any{"port": 80, "expose": false},
|
|
}),
|
|
)
|
|
Expect(rendered.Get("data.hasExposed")).To(BeNil())
|
|
})
|
|
|
|
It("should return false for non-array ports value", func() {
|
|
ports := defkit.String("ports")
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Params(ports).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
SetIf(defkit.HasExposedPorts(ports), "data.hasExposed", defkit.Lit("true")),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(
|
|
defkit.TestContext().WithParam("ports", "not-an-array"),
|
|
)
|
|
Expect(rendered.Get("data.hasExposed")).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("evaluateCondition with NotExpr", func() {
|
|
It("should negate IsSet via NotExpr (ParamNotSet)", func() {
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Params(defkit.String("optionalField").Optional()).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
SetIf(defkit.ParamNotSet("optionalField"), "data.fallback", defkit.Lit("default")),
|
|
)
|
|
})
|
|
|
|
// Without the param set, ParamNotSet should evaluate to true
|
|
rendered := comp.Render(defkit.TestContext())
|
|
Expect(rendered.Get("data.fallback")).To(Equal("default"))
|
|
|
|
// With the param set, ParamNotSet should evaluate to false
|
|
rendered2 := comp.Render(defkit.TestContext().WithParam("optionalField", "value"))
|
|
Expect(rendered2.Get("data.fallback")).To(BeNil())
|
|
})
|
|
|
|
It("should negate via Not() wrapper with Comparison", func() {
|
|
enabled := defkit.Bool("enabled")
|
|
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Params(enabled.Default(true)).
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
SetIf(defkit.Not(defkit.Eq(enabled, defkit.Lit(true))), "data.disabled", defkit.Lit("yes")),
|
|
)
|
|
})
|
|
|
|
// enabled=true => Not(true==true) => Not(true) => false => field absent
|
|
rendered := comp.Render(defkit.TestContext().WithParam("enabled", true))
|
|
Expect(rendered.Get("data.disabled")).To(BeNil())
|
|
|
|
// enabled=false => Not(false==true) => Not(false) => true => field present
|
|
rendered2 := comp.Render(defkit.TestContext().WithParam("enabled", false))
|
|
Expect(rendered2.Get("data.disabled")).To(Equal("yes"))
|
|
})
|
|
})
|
|
|
|
Context("evaluateCondition with nil", func() {
|
|
It("should treat nil condition as true", func() {
|
|
// This is tested indirectly: a SetIf with no condition should apply
|
|
comp := defkit.NewComponent("test").
|
|
Workload("v1", "ConfigMap").
|
|
Template(func(tpl *defkit.Template) {
|
|
tpl.Output(
|
|
defkit.NewResource("v1", "ConfigMap").
|
|
Set("data.always", defkit.Lit("present")),
|
|
)
|
|
})
|
|
|
|
rendered := comp.Render(defkit.TestContext())
|
|
Expect(rendered.Get("data.always")).To(Equal("present"))
|
|
})
|
|
})
|
|
})
|