mirror of
https://github.com/kubevela/kubevela.git
synced 2026-05-20 08:13:23 +00:00
* Feat: add MapVariant operation and support for OneOf parameters with default variant Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: enhance string parameter output to include optional prefix in CUE generation Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: add ConditionalOrFieldRef for fallback handling and support inline array values Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: update CUE generation to support inline arrays with conditional wrapping Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: update CUE generation to support inline arrays with conditional wrapping Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: add support for compound optional fields and enhance array builder with guarded filtering Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: add comprehensive tests for ArrayBuilder functionality Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: implement field grouping in StatusBuilder for consolidated CUE output Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: enhance CUE decomposition to support condValues and improve filtering logic Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: add metadata labels to ComponentDefinition and update CUE generation Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: clean up comments and formatting in cuegen and param files Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: enhance CUE generation, trait definitions, and PatchContainer logic CUE Generation: - Simplify condition decomposition logic and rename GetDirective method - Add condition decomposition and lifting logic to improve generated CUE output - Refactor cueTypeForParamType to use a standalone cueTypeStr function for reusability Collections: - Enhance MapVariant operation to merge variant mappings and preserve non-matching items Trait Definitions: - Enhance TraitDefinition and PatchContainerConfig with new attributes (MultiContainerCheckField, MultiContainerErrMsg) - Update emission logic in TraitCUEGenerator for multi-container support PatchContainer: - Update error messages to use camelCase for consistency with KubeVela conventions Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: enhance test descriptions for clarity and accuracy in array_builder, collections, and status tests Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: enhance handling of optional fields in collections and improve test descriptions for clarity Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: improve ConditionalOrFieldRef tests for clarity and accuracy in handling primary and fallback fields Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: enhance test descriptions for clarity and accuracy in array_builder and expr tests Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Feat: improve formatting of test data in collections tests for better readability Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> --------- Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com>
535 lines
19 KiB
Go
535 lines
19 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 (
|
|
"strings"
|
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
|
|
"github.com/oam-dev/kubevela/pkg/definition/defkit"
|
|
)
|
|
|
|
var _ = Describe("Status", func() {
|
|
|
|
Context("StatusBuilder", func() {
|
|
It("should create a status builder that produces empty CUE without fields", func() {
|
|
s := defkit.Status()
|
|
Expect(s).NotTo(BeNil())
|
|
cue := s.Build()
|
|
Expect(cue).To(BeEmpty())
|
|
})
|
|
|
|
It("should add IntField to status", func() {
|
|
s := defkit.Status().
|
|
IntField("ready.replicas", "status.numberReady", 0)
|
|
cue := s.Build()
|
|
Expect(cue).To(ContainSubstring("ready:"))
|
|
Expect(cue).To(ContainSubstring("replicas:"))
|
|
Expect(cue).To(ContainSubstring("*0 | int"))
|
|
Expect(cue).To(ContainSubstring("context.output.status.numberReady"))
|
|
})
|
|
|
|
It("should add StringField to status", func() {
|
|
s := defkit.Status().
|
|
StringField("state", "status.phase", "unknown")
|
|
cue := s.Build()
|
|
Expect(cue).To(ContainSubstring("state:"))
|
|
Expect(cue).To(ContainSubstring(`*"unknown" | string`))
|
|
Expect(cue).To(ContainSubstring("context.output.status.phase"))
|
|
})
|
|
|
|
It("should set message template", func() {
|
|
s := defkit.Status().
|
|
IntField("ready.replicas", "status.readyReplicas", 0).
|
|
Message(`Ready:\(ready.replicas)`)
|
|
cue := s.Build()
|
|
Expect(cue).To(ContainSubstring(`message: "Ready:\(ready.replicas)"`))
|
|
})
|
|
|
|
It("should support RawCUE override", func() {
|
|
rawCUE := `message: "Custom status"`
|
|
s := defkit.Status().
|
|
IntField("ready.replicas", "status.readyReplicas", 0).
|
|
RawCUE(rawCUE)
|
|
cue := s.Build()
|
|
Expect(cue).To(Equal(rawCUE))
|
|
})
|
|
})
|
|
|
|
Context("HealthBuilder", func() {
|
|
It("should create a health builder that produces empty CUE without conditions", func() {
|
|
h := defkit.Health()
|
|
Expect(h).NotTo(BeNil())
|
|
cue := h.Build()
|
|
Expect(cue).To(BeEmpty())
|
|
})
|
|
|
|
It("should add IntField through HealthBuilder", func() {
|
|
h := defkit.Health().
|
|
IntField("ready.replicas", "status.readyReplicas", 0)
|
|
cue := h.Build()
|
|
Expect(cue).To(ContainSubstring("ready:"))
|
|
Expect(cue).To(ContainSubstring("replicas:"))
|
|
Expect(cue).To(ContainSubstring("*0 | int"))
|
|
})
|
|
|
|
It("should add StringField through HealthBuilder", func() {
|
|
h := defkit.Health().
|
|
StringField("state", "status.phase", "unknown")
|
|
cue := h.Build()
|
|
Expect(cue).To(ContainSubstring("state:"))
|
|
Expect(cue).To(ContainSubstring(`*"unknown" | string`))
|
|
})
|
|
|
|
It("should add MetadataField to health builder", func() {
|
|
h := defkit.Health().
|
|
MetadataField("generation.metadata", "metadata.generation")
|
|
cue := h.Build()
|
|
Expect(cue).To(ContainSubstring("generation:"))
|
|
Expect(cue).To(ContainSubstring("context.output.metadata.generation"))
|
|
})
|
|
|
|
It("should add health conditions with HealthyWhen", func() {
|
|
h := defkit.Health().
|
|
IntField("ready.replicas", "status.readyReplicas", 0).
|
|
IntField("desired.replicas", "status.replicas", 0).
|
|
HealthyWhen("ready.replicas == desired.replicas")
|
|
cue := h.Build()
|
|
Expect(cue).To(ContainSubstring("isHealth: ready.replicas == desired.replicas"))
|
|
})
|
|
|
|
It("should add multiple health conditions with auto-parenthesization", func() {
|
|
h := defkit.Health().
|
|
HealthyWhen("condition1", "condition2", "condition3")
|
|
cue := h.Build()
|
|
Expect(cue).To(ContainSubstring("isHealth: (condition1) && (condition2) && (condition3)"))
|
|
})
|
|
|
|
It("should support RawCUE override on health builder", func() {
|
|
rawCUE := `isHealth: true`
|
|
h := defkit.Health().
|
|
IntField("ready.replicas", "status.readyReplicas", 0).
|
|
RawCUE(rawCUE)
|
|
cue := h.Build()
|
|
Expect(cue).To(Equal(rawCUE))
|
|
})
|
|
})
|
|
|
|
Context("Status helper functions", func() {
|
|
It("should create StatusEq expression", func() {
|
|
result := defkit.StatusEq("left.field", "right.field")
|
|
Expect(result).To(Equal("left.field == right.field"))
|
|
})
|
|
|
|
It("should create StatusGte expression", func() {
|
|
result := defkit.StatusGte("left.field", "right.field")
|
|
Expect(result).To(Equal("left.field >= right.field"))
|
|
})
|
|
|
|
It("should create StatusOr expression", func() {
|
|
result := defkit.StatusOr("cond1", "cond2", "cond3")
|
|
Expect(result).To(Equal("(cond1 || cond2 || cond3)"))
|
|
})
|
|
|
|
It("should create StatusAnd expression", func() {
|
|
result := defkit.StatusAnd("cond1", "cond2", "cond3")
|
|
Expect(result).To(Equal("(cond1 && cond2 && cond3)"))
|
|
})
|
|
})
|
|
|
|
Context("Predefined Status Builders", func() {
|
|
It("should create DaemonSetStatus builder", func() {
|
|
s := defkit.DaemonSetStatus()
|
|
cue := s.Build()
|
|
Expect(cue).To(ContainSubstring("ready:"))
|
|
Expect(cue).To(ContainSubstring("desired:"))
|
|
Expect(cue).To(ContainSubstring("status.numberReady"))
|
|
Expect(cue).To(ContainSubstring("status.desiredNumberScheduled"))
|
|
Expect(cue).To(ContainSubstring("message:"))
|
|
})
|
|
|
|
It("should create DaemonSetHealth builder", func() {
|
|
h := defkit.DaemonSetHealth()
|
|
cue := h.Build()
|
|
Expect(cue).To(ContainSubstring("ready:"))
|
|
Expect(cue).To(ContainSubstring("desired:"))
|
|
Expect(cue).To(ContainSubstring("current:"))
|
|
Expect(cue).To(ContainSubstring("updated:"))
|
|
Expect(cue).To(ContainSubstring("generation:"))
|
|
Expect(cue).To(ContainSubstring("isHealth:"))
|
|
})
|
|
|
|
It("should create DeploymentStatus builder", func() {
|
|
s := defkit.DeploymentStatus()
|
|
cue := s.Build()
|
|
Expect(cue).To(ContainSubstring("ready:"))
|
|
Expect(cue).To(ContainSubstring("status.readyReplicas"))
|
|
Expect(cue).To(ContainSubstring("message:"))
|
|
})
|
|
|
|
It("should create DeploymentHealth builder with consolidated fields", func() {
|
|
h := defkit.DeploymentHealth()
|
|
cue := h.Build()
|
|
// Verify consolidated ready block with all fields
|
|
Expect(cue).To(ContainSubstring("ready: {"))
|
|
Expect(cue).To(ContainSubstring("updatedReplicas:"))
|
|
Expect(cue).To(ContainSubstring("readyReplicas:"))
|
|
Expect(cue).To(ContainSubstring("replicas:"))
|
|
Expect(cue).To(ContainSubstring("observedGeneration:"))
|
|
// Verify _isHealth intermediate pattern
|
|
Expect(cue).To(ContainSubstring("_isHealth:"))
|
|
Expect(cue).To(ContainSubstring("isHealth: *_isHealth | bool"))
|
|
// Verify annotation-based disable override
|
|
Expect(cue).To(ContainSubstring("app.oam.dev/disable-health-check"))
|
|
})
|
|
|
|
It("should create StatefulSetStatus builder", func() {
|
|
s := defkit.StatefulSetStatus()
|
|
cue := s.Build()
|
|
Expect(cue).To(ContainSubstring("ready:"))
|
|
Expect(cue).To(ContainSubstring("desired:"))
|
|
Expect(cue).To(ContainSubstring("status.readyReplicas"))
|
|
Expect(cue).To(ContainSubstring("message:"))
|
|
})
|
|
|
|
It("should create StatefulSetHealth builder", func() {
|
|
h := defkit.StatefulSetHealth()
|
|
cue := h.Build()
|
|
Expect(cue).To(ContainSubstring("ready:"))
|
|
Expect(cue).To(ContainSubstring("updated:"))
|
|
Expect(cue).To(ContainSubstring("desired:"))
|
|
Expect(cue).To(ContainSubstring("generation:"))
|
|
Expect(cue).To(ContainSubstring("isHealth:"))
|
|
})
|
|
|
|
It("should create JobHealth builder", func() {
|
|
h := defkit.JobHealth()
|
|
cue := h.Build()
|
|
Expect(cue).To(ContainSubstring("succeeded:"))
|
|
Expect(cue).To(ContainSubstring("status.succeeded"))
|
|
Expect(cue).To(ContainSubstring("isHealth: succeeded == context.output.spec.parallelism"))
|
|
})
|
|
|
|
It("should create CronJobHealth builder", func() {
|
|
h := defkit.CronJobHealth()
|
|
cue := h.Build()
|
|
Expect(cue).To(ContainSubstring("isHealth: true"))
|
|
})
|
|
})
|
|
|
|
Context("StatusBuilder field grouping", func() {
|
|
It("should consolidate multiple fields with same parent into one block", func() {
|
|
s := defkit.Status().
|
|
IntField("status.active", "status.active", 0).
|
|
IntField("status.failed", "status.failed", 0).
|
|
IntField("status.succeeded", "status.succeeded", 0).
|
|
Message(`Active/Failed/Succeeded:\(status.active)/\(status.failed)/\(status.succeeded)`)
|
|
cue := s.Build()
|
|
Expect(strings.Count(cue, "status: {")).To(Equal(1))
|
|
Expect(cue).To(ContainSubstring("active:"))
|
|
Expect(cue).To(ContainSubstring("failed:"))
|
|
Expect(cue).To(ContainSubstring("succeeded:"))
|
|
})
|
|
|
|
It("should keep different parent prefixes as separate blocks", func() {
|
|
s := defkit.Status().
|
|
IntField("ready.replicas", "status.numberReady", 0).
|
|
IntField("desired.replicas", "status.desiredNumberScheduled", 0).
|
|
Message(`Ready:\(ready.replicas)/\(desired.replicas)`)
|
|
cue := s.Build()
|
|
Expect(strings.Count(cue, "ready: {")).To(Equal(1))
|
|
Expect(strings.Count(cue, "desired: {")).To(Equal(1))
|
|
})
|
|
|
|
It("should column-align fields within consolidated block", func() {
|
|
s := defkit.Status().
|
|
IntField("status.active", "status.active", 0).
|
|
IntField("status.succeeded", "status.succeeded", 0)
|
|
cue := s.Build()
|
|
// "active" is shorter than "succeeded", so it should be padded
|
|
Expect(cue).To(ContainSubstring("active: *0 | int"))
|
|
Expect(cue).To(ContainSubstring("succeeded: *0 | int"))
|
|
})
|
|
|
|
It("should handle simple (non-nested) fields without grouping", func() {
|
|
s := defkit.Status().
|
|
IntField("succeeded", "status.succeeded", 0)
|
|
cue := s.Build()
|
|
Expect(cue).To(ContainSubstring("succeeded: *0 | int"))
|
|
Expect(cue).To(ContainSubstring("context.output.status.succeeded"))
|
|
})
|
|
})
|
|
|
|
Context("HealthBuilder field grouping", func() {
|
|
It("should consolidate multiple fields with same parent into one block", func() {
|
|
h := defkit.Health().
|
|
IntField("ready.replicas", "status.readyReplicas", 0).
|
|
IntField("ready.updated", "status.updatedReplicas", 0).
|
|
HealthyWhen("ready.replicas == ready.updated")
|
|
cue := h.Build()
|
|
// Should produce a single consolidated "ready:" block, not two separate ones
|
|
Expect(strings.Count(cue, "ready: {")).To(Equal(1))
|
|
Expect(cue).To(ContainSubstring("replicas:"))
|
|
Expect(cue).To(ContainSubstring("updated:"))
|
|
})
|
|
|
|
It("should keep single-field groups as consolidated blocks", func() {
|
|
h := defkit.Health().
|
|
IntField("ready.replicas", "status.readyReplicas", 0).
|
|
IntField("desired.replicas", "status.replicas", 0).
|
|
HealthyWhen("ready.replicas == desired.replicas")
|
|
cue := h.Build()
|
|
Expect(cue).To(ContainSubstring("ready: {"))
|
|
Expect(cue).To(ContainSubstring("desired: {"))
|
|
})
|
|
|
|
It("should handle simple (non-nested) fields without grouping", func() {
|
|
h := defkit.Health().
|
|
IntField("succeeded", "status.succeeded", 0).
|
|
HealthyWhen("succeeded >= 1")
|
|
cue := h.Build()
|
|
Expect(cue).To(ContainSubstring("succeeded:"))
|
|
Expect(cue).To(ContainSubstring("isHealth: succeeded >= 1"))
|
|
})
|
|
|
|
It("should place metadata fields in defaults block of consolidated group", func() {
|
|
h := defkit.Health().
|
|
MetadataField("generation.metadata", "metadata.generation").
|
|
IntField("generation.observed", "status.observedGeneration", 0)
|
|
cue := h.Build()
|
|
// Should be one consolidated generation: block
|
|
Expect(strings.Count(cue, "generation: {")).To(Equal(1))
|
|
// Metadata field should appear as a direct reference (no default value)
|
|
Expect(cue).To(ContainSubstring("metadata: context.output.metadata.generation"))
|
|
// Int field should have default
|
|
Expect(cue).To(ContainSubstring("observed:"))
|
|
Expect(cue).To(ContainSubstring("*0 | int"))
|
|
})
|
|
|
|
It("should column-align fields in consolidated blocks", func() {
|
|
h := defkit.Health().
|
|
IntField("ready.a", "status.a", 0).
|
|
IntField("ready.longFieldName", "status.longFieldName", 0)
|
|
cue := h.Build()
|
|
// The shorter field "a" should have more padding than "longFieldName"
|
|
Expect(cue).To(ContainSubstring("a:"))
|
|
Expect(cue).To(ContainSubstring("longFieldName:"))
|
|
})
|
|
})
|
|
|
|
Context("HealthBuilder auto-parenthesization", func() {
|
|
It("should NOT parenthesize a single condition", func() {
|
|
h := defkit.Health().
|
|
HealthyWhen("ready.replicas == desired.replicas")
|
|
cue := h.Build()
|
|
Expect(cue).To(ContainSubstring("isHealth: ready.replicas == desired.replicas"))
|
|
})
|
|
|
|
It("should auto-parenthesize multiple conditions", func() {
|
|
h := defkit.Health().
|
|
HealthyWhen("a == b", "c == d")
|
|
cue := h.Build()
|
|
Expect(cue).To(ContainSubstring("isHealth: (a == b) && (c == d)"))
|
|
})
|
|
|
|
It("should NOT double-wrap already-parenthesized conditions", func() {
|
|
h := defkit.Health().
|
|
HealthyWhen("a == b", defkit.StatusOr("x == y", "x > y"))
|
|
cue := h.Build()
|
|
// StatusOr returns "(x == y || x > y)" which is already fully parenthesized
|
|
Expect(cue).To(ContainSubstring("(a == b) && (x == y || x > y)"))
|
|
})
|
|
|
|
It("should NOT treat partially-parenthesized strings as fully wrapped", func() {
|
|
// "(a) && (b)" starts with ( and ends with ) but is not fully enclosed
|
|
h := defkit.Health().
|
|
HealthyWhen("first", "(a) && (b)")
|
|
cue := h.Build()
|
|
Expect(cue).To(ContainSubstring("(first) && ((a) && (b))"))
|
|
})
|
|
|
|
It("should work with StatusEq without manual parens", func() {
|
|
h := defkit.Health().
|
|
HealthyWhen(
|
|
defkit.StatusEq("spec.replicas", "ready.replicas"),
|
|
defkit.StatusEq("spec.replicas", "ready.updated"),
|
|
)
|
|
cue := h.Build()
|
|
Expect(cue).To(ContainSubstring("(spec.replicas == ready.replicas) && (spec.replicas == ready.updated)"))
|
|
})
|
|
|
|
It("should work with WithDefault and StatusEq", func() {
|
|
h := defkit.Health().
|
|
HealthyWhen(
|
|
defkit.StatusEq("a", "b"),
|
|
defkit.StatusEq("c", "d"),
|
|
).
|
|
WithDefault()
|
|
cue := h.Build()
|
|
Expect(cue).To(ContainSubstring("_isHealth: (a == b) && (c == d)"))
|
|
Expect(cue).To(ContainSubstring("isHealth: *_isHealth | bool"))
|
|
})
|
|
|
|
It("should produce correct CUE for DaemonSetHealth with auto-parens", func() {
|
|
h := defkit.DaemonSetHealth()
|
|
cue := h.Build()
|
|
// Each equality condition should be parenthesized
|
|
Expect(cue).To(ContainSubstring("(desired.replicas == ready.replicas)"))
|
|
Expect(cue).To(ContainSubstring("(desired.replicas == updated.replicas)"))
|
|
Expect(cue).To(ContainSubstring("(desired.replicas == current.replicas)"))
|
|
// StatusOr is already wrapped, should not be double-wrapped
|
|
Expect(cue).To(ContainSubstring("(generation.observed == generation.metadata || generation.observed > generation.metadata)"))
|
|
})
|
|
|
|
It("should produce correct CUE for DeploymentHealth with auto-parens", func() {
|
|
h := defkit.DeploymentHealth()
|
|
cue := h.Build()
|
|
Expect(cue).To(ContainSubstring("(context.output.spec.replicas == ready.readyReplicas)"))
|
|
Expect(cue).To(ContainSubstring("(context.output.spec.replicas == ready.updatedReplicas)"))
|
|
Expect(cue).To(ContainSubstring("(context.output.spec.replicas == ready.replicas)"))
|
|
Expect(cue).To(ContainSubstring("_isHealth:"))
|
|
})
|
|
})
|
|
|
|
Context("HealthBuilder Expressions", func() {
|
|
It("should generate Condition expression that checks condition status", func() {
|
|
h := defkit.Health()
|
|
expr := h.Condition("Ready").IsTrue()
|
|
policy := h.Policy(expr)
|
|
Expect(policy).To(ContainSubstring("Ready"))
|
|
Expect(policy).To(ContainSubstring("isHealth:"))
|
|
Expect(policy).To(ContainSubstring(`"True"`))
|
|
})
|
|
|
|
It("should generate Phase expression that checks status.phase", func() {
|
|
h := defkit.Health()
|
|
expr := h.Phase("Running", "Succeeded")
|
|
policy := h.Policy(expr)
|
|
Expect(policy).To(ContainSubstring("isHealth:"))
|
|
Expect(policy).To(ContainSubstring("Running"))
|
|
Expect(policy).To(ContainSubstring("Succeeded"))
|
|
Expect(policy).To(ContainSubstring("context.output.status.phase"))
|
|
})
|
|
|
|
It("should generate PhaseField expression with custom field path", func() {
|
|
h := defkit.Health()
|
|
expr := h.PhaseField("status.currentPhase", "Active", "Ready")
|
|
policy := h.Policy(expr)
|
|
Expect(policy).To(ContainSubstring("isHealth:"))
|
|
Expect(policy).To(ContainSubstring("context.output.status.currentPhase"))
|
|
Expect(policy).To(ContainSubstring("Active"))
|
|
Expect(policy).To(ContainSubstring("Ready"))
|
|
})
|
|
|
|
It("should generate Exists expression that checks field != _|_", func() {
|
|
h := defkit.Health()
|
|
expr := h.Exists("status.loadBalancer.ingress")
|
|
policy := h.Policy(expr)
|
|
Expect(policy).To(ContainSubstring("isHealth:"))
|
|
Expect(policy).To(ContainSubstring("status.loadBalancer.ingress"))
|
|
Expect(policy).To(ContainSubstring("!= _|_"))
|
|
})
|
|
|
|
It("should generate NotExists expression that checks field == _|_", func() {
|
|
h := defkit.Health()
|
|
expr := h.NotExists("status.error")
|
|
policy := h.Policy(expr)
|
|
Expect(policy).To(ContainSubstring("isHealth:"))
|
|
Expect(policy).To(ContainSubstring("status.error"))
|
|
Expect(policy).To(ContainSubstring("== _|_"))
|
|
})
|
|
|
|
It("should generate And expression combining multiple conditions", func() {
|
|
h := defkit.Health()
|
|
expr1 := h.Condition("Ready").IsTrue()
|
|
expr2 := h.Condition("Synced").IsTrue()
|
|
and := h.And(expr1, expr2)
|
|
policy := h.Policy(and)
|
|
Expect(policy).To(ContainSubstring("Ready"))
|
|
Expect(policy).To(ContainSubstring("Synced"))
|
|
Expect(policy).To(ContainSubstring("&&"))
|
|
})
|
|
|
|
It("should generate Or expression combining multiple conditions", func() {
|
|
h := defkit.Health()
|
|
expr1 := h.Phase("Running")
|
|
expr2 := h.Phase("Succeeded")
|
|
or := h.Or(expr1, expr2)
|
|
policy := h.Policy(or)
|
|
Expect(policy).To(ContainSubstring("Running"))
|
|
Expect(policy).To(ContainSubstring("Succeeded"))
|
|
Expect(policy).To(ContainSubstring("||"))
|
|
})
|
|
|
|
It("should generate Not expression negating a condition", func() {
|
|
h := defkit.Health()
|
|
expr := h.Condition("Stalled").IsTrue()
|
|
not := h.Not(expr)
|
|
policy := h.Policy(not)
|
|
Expect(policy).To(ContainSubstring("Stalled"))
|
|
Expect(policy).To(ContainSubstring("!"))
|
|
})
|
|
|
|
It("should generate Always expression as isHealth: true", func() {
|
|
h := defkit.Health()
|
|
expr := h.Always()
|
|
policy := h.Policy(expr)
|
|
Expect(policy).To(ContainSubstring("isHealth: true"))
|
|
})
|
|
|
|
It("should generate AllTrue expression checking multiple conditions are True", func() {
|
|
h := defkit.Health()
|
|
expr := h.AllTrue("Ready", "Synced", "Available")
|
|
policy := h.Policy(expr)
|
|
Expect(policy).To(ContainSubstring("Ready"))
|
|
Expect(policy).To(ContainSubstring("Synced"))
|
|
Expect(policy).To(ContainSubstring("Available"))
|
|
Expect(policy).To(ContainSubstring("&&"))
|
|
})
|
|
|
|
It("should generate AnyTrue expression checking any condition is True", func() {
|
|
h := defkit.Health()
|
|
expr := h.AnyTrue("Ready", "Available")
|
|
policy := h.Policy(expr)
|
|
Expect(policy).To(ContainSubstring("Ready"))
|
|
Expect(policy).To(ContainSubstring("Available"))
|
|
Expect(policy).To(ContainSubstring("||"))
|
|
})
|
|
|
|
It("should set health condition with HealthyWhenExpr and generate correct CUE", func() {
|
|
h := defkit.Health()
|
|
expr := h.Condition("Ready").IsTrue()
|
|
h.HealthyWhenExpr(expr)
|
|
cue := h.Build()
|
|
Expect(cue).To(ContainSubstring("isHealth:"))
|
|
Expect(cue).To(ContainSubstring("Ready"))
|
|
Expect(cue).To(ContainSubstring(`"True"`))
|
|
})
|
|
|
|
It("should generate policy with correct isHealth expression from Condition", func() {
|
|
h := defkit.Health()
|
|
expr := h.Condition("Ready").IsTrue()
|
|
policy := h.Policy(expr)
|
|
Expect(policy).To(ContainSubstring("isHealth:"))
|
|
Expect(policy).To(ContainSubstring("Ready"))
|
|
Expect(policy).To(ContainSubstring(`"True"`))
|
|
})
|
|
})
|
|
})
|