Files
kubevela/pkg/definition/defkit/render_test.go
Ayush Kumar 012a134829 Feat: extend fluent builder API validator patterns (#7092)
* 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>
2026-04-09 14:25:06 +01:00

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"))
})
})
})