Merge pull request #3395 from realnumber666/add-unit-test

Add UT for workstatus.go and taint.go and rule.go
This commit is contained in:
karmada-bot 2023-04-24 19:56:11 +08:00 committed by GitHub
commit 2ef01942f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 1361 additions and 0 deletions

View File

@ -2,15 +2,19 @@ package helper
import (
"context"
"fmt"
"reflect"
"testing"
"time"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1"
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
"github.com/karmada-io/karmada/pkg/util/gclient"
)
@ -98,6 +102,16 @@ func TestUpdateClusterControllerTaint(t *testing.T) {
wantTaints: []corev1.Taint{*notReadyTaintTemplate},
wantErr: false,
},
{
name: "clusterTaintsToAdd is nil and clusterTaintsToRemove is nil",
args: args{
taints: []corev1.Taint{*unreachableTaintTemplate},
taintsToAdd: []*corev1.Taint{unreachableTaintTemplate.DeepCopy()},
taintsToRemove: []*corev1.Taint{notReadyTaintTemplate.DeepCopy()},
},
wantTaints: []corev1.Taint{*unreachableTaintTemplate},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@ -266,6 +280,31 @@ func TestTolerationExists(t *testing.T) {
}
}
func TestAddTolerations(t *testing.T) {
placement := &policyv1alpha1.Placement{
ClusterTolerations: []corev1.Toleration{},
}
toleration1 := &corev1.Toleration{
Key: "key1",
Operator: corev1.TolerationOpEqual,
Value: "value1",
Effect: corev1.TaintEffectNoSchedule,
}
toleration2 := &corev1.Toleration{
Key: "key2",
Operator: corev1.TolerationOpEqual,
Value: "value2",
Effect: corev1.TaintEffectNoSchedule,
}
AddTolerations(placement, toleration1, toleration2)
assert.Equal(t, 2, len(placement.ClusterTolerations))
assert.Equal(t, *toleration1, placement.ClusterTolerations[0])
assert.Equal(t, *toleration2, placement.ClusterTolerations[1])
}
func TestHasNoExecuteTaints(t *testing.T) {
tests := []struct {
name string
@ -357,3 +396,319 @@ func TestGetNoExecuteTaints(t *testing.T) {
})
}
}
func TestGetMinTolerationTime(t *testing.T) {
tests := []struct {
name string
noExecuteTaints []corev1.Taint
usedTolerantion []corev1.Toleration
wantResult time.Duration
}{
{
name: "no noExecuteTaints",
noExecuteTaints: []corev1.Taint{},
usedTolerantion: []corev1.Toleration{
{
Key: "key",
Operator: corev1.TolerationOpExists,
Effect: corev1.TaintEffectNoExecute,
TolerationSeconds: &[]int64{60}[0],
},
},
wantResult: -1,
},
{
name: "no usedTolerations",
noExecuteTaints: []corev1.Taint{
{
Key: "key",
Value: "value",
Effect: corev1.TaintEffectNoExecute,
TimeAdded: &metav1.Time{Time: time.Now()},
},
},
usedTolerantion: []corev1.Toleration{},
wantResult: 0,
},
{
name: "with noExecuteTaints and usedTolerations",
noExecuteTaints: []corev1.Taint{
{
Key: "key",
Value: "value",
Effect: corev1.TaintEffectNoExecute,
TimeAdded: &metav1.Time{Time: time.Now()},
},
},
usedTolerantion: []corev1.Toleration{
{
Key: "key",
Operator: corev1.TolerationOpExists,
Effect: corev1.TaintEffectNoExecute,
TolerationSeconds: &[]int64{60}[0],
},
},
wantResult: 60,
},
{
name: "usedTolerantion.TolerationSeconds is nil",
noExecuteTaints: []corev1.Taint{
{
Key: "key",
Value: "value",
Effect: corev1.TaintEffectNoExecute,
TimeAdded: &metav1.Time{Time: time.Now()},
},
},
usedTolerantion: []corev1.Toleration{
{
Key: "key",
Operator: corev1.TolerationOpExists,
Effect: corev1.TaintEffectNoExecute,
TolerationSeconds: nil,
},
},
wantResult: -1,
},
{
name: "noExecuteTaints.TimeAdded is nil",
noExecuteTaints: []corev1.Taint{
{
Key: "key",
Value: "value",
Effect: corev1.TaintEffectNoExecute,
TimeAdded: nil,
},
},
usedTolerantion: []corev1.Toleration{
{
Key: "key",
Operator: corev1.TolerationOpExists,
Effect: corev1.TaintEffectNoExecute,
TolerationSeconds: &[]int64{60}[0],
},
},
wantResult: -1,
},
{
name: "find the latest trigger time",
noExecuteTaints: []corev1.Taint{
{
Key: "key1",
Value: "value1",
Effect: corev1.TaintEffectNoExecute,
TimeAdded: &metav1.Time{Time: time.Now()},
},
{
Key: "key2",
Value: "value2",
Effect: corev1.TaintEffectNoExecute,
TimeAdded: &metav1.Time{Time: time.Now()},
},
},
usedTolerantion: []corev1.Toleration{
{
Key: "key1",
Operator: corev1.TolerationOpExists,
Effect: corev1.TaintEffectNoExecute,
TolerationSeconds: &[]int64{120}[0],
},
{
Key: "key2",
Operator: corev1.TolerationOpExists,
Effect: corev1.TaintEffectNoExecute,
TolerationSeconds: &[]int64{60}[0],
},
},
wantResult: 60,
},
{
name: "trigger time is up",
noExecuteTaints: []corev1.Taint{
{
Key: "key",
Value: "value",
Effect: corev1.TaintEffectNoExecute,
TimeAdded: &metav1.Time{
Time: time.Now().Add(-time.Hour),
},
},
},
usedTolerantion: []corev1.Toleration{
{
Key: "key",
Operator: corev1.TolerationOpExists,
Effect: corev1.TaintEffectNoExecute,
TolerationSeconds: &[]int64{60}[0],
},
},
wantResult: 0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := GetMinTolerationTime(tt.noExecuteTaints, tt.usedTolerantion)
fmt.Printf("%+v", result)
if result > 0 {
if result > (tt.wantResult+1)*time.Second || result < (tt.wantResult-1)*time.Second {
t.Errorf("GetMinTolerationTime() = %v, want %v", result, tt.wantResult)
}
} else if result != tt.wantResult {
t.Errorf("GetMinTolerationTime() = %v, want %v", result, tt.wantResult)
}
})
}
}
func TestGetMatchingTolerations(t *testing.T) {
tests := []struct {
name string
taints []corev1.Taint
tolerations []corev1.Toleration
wantActual bool
wantActualTolerations []corev1.Toleration
}{
{
name: "taints is nil",
taints: []corev1.Taint{},
tolerations: []corev1.Toleration{
{
Key: "key1",
Value: "value1",
Effect: corev1.TaintEffectNoSchedule,
},
},
wantActual: true,
wantActualTolerations: []corev1.Toleration{},
},
{
name: "tolerations is nil",
taints: []corev1.Taint{
{
Key: "key1",
Value: "value1",
Effect: corev1.TaintEffectNoSchedule,
},
},
tolerations: []corev1.Toleration{},
wantActual: false,
wantActualTolerations: []corev1.Toleration{},
},
{
name: "tolerated is true",
taints: []corev1.Taint{
{
Key: "key1",
Value: "value1",
Effect: corev1.TaintEffectNoSchedule,
},
{
Key: "key2",
Value: "value2",
Effect: corev1.TaintEffectNoSchedule,
},
},
tolerations: []corev1.Toleration{
{
Key: "key1",
Value: "value1",
Effect: corev1.TaintEffectNoSchedule,
},
{
Key: "key2",
Value: "value2",
Effect: corev1.TaintEffectNoSchedule,
},
},
wantActual: true,
wantActualTolerations: []corev1.Toleration{
{
Key: "key1",
Value: "value1",
Effect: corev1.TaintEffectNoSchedule,
},
{
Key: "key2",
Value: "value2",
Effect: corev1.TaintEffectNoSchedule,
},
},
},
{
name: "tolerated is false",
taints: []corev1.Taint{
{
Key: "key1",
Value: "value1",
Effect: corev1.TaintEffectNoSchedule,
},
{
Key: "key2",
Value: "value2",
Effect: corev1.TaintEffectNoSchedule,
},
},
tolerations: []corev1.Toleration{
{
Key: "key1",
Value: "value_1",
Effect: corev1.TaintEffectNoSchedule,
},
{
Key: "key2",
Value: "value_2",
Effect: corev1.TaintEffectNoSchedule,
},
},
wantActual: false,
wantActualTolerations: []corev1.Toleration{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actual, actualTolerations := GetMatchingTolerations(tt.taints, tt.tolerations)
if actual != tt.wantActual || !reflect.DeepEqual(actualTolerations, tt.wantActualTolerations) {
t.Errorf("GetMatchingTolerations(%v, %v) = (%v, %v), expected (%v, %v)", tt.taints, tt.tolerations, actual, actualTolerations, tt.wantActual, tt.wantActualTolerations)
}
})
}
}
func TestNewNotReadyToleration(t *testing.T) {
expectedKey := clusterv1alpha1.TaintClusterNotReady
expectedOperator := corev1.TolerationOpExists
expectedEffect := corev1.TaintEffectNoExecute
expectedSeconds := int64(123)
toleration := NewNotReadyToleration(expectedSeconds)
if toleration.Key != expectedKey {
t.Errorf("Expected key %q but got %q", expectedKey, toleration.Key)
}
if toleration.Operator != expectedOperator {
t.Errorf("Expected operator %q but got %q", expectedOperator, toleration.Operator)
}
if toleration.Effect != expectedEffect {
t.Errorf("Expected effect %q but got %q", expectedEffect, toleration.Effect)
}
if *toleration.TolerationSeconds != expectedSeconds {
t.Errorf("Expected seconds %d but got %d", expectedSeconds, *toleration.TolerationSeconds)
}
}
func TestNewUnreachableToleration(t *testing.T) {
tolerationSeconds := int64(300)
expectedToleration := &corev1.Toleration{
Key: clusterv1alpha1.TaintClusterUnreachable,
Operator: corev1.TolerationOpExists,
Effect: corev1.TaintEffectNoExecute,
TolerationSeconds: &tolerationSeconds,
}
actualToleration := NewUnreachableToleration(tolerationSeconds)
if !reflect.DeepEqual(actualToleration, expectedToleration) {
t.Errorf("NewUnreachableToleration() = %v, want %v", actualToleration, expectedToleration)
}
}

View File

@ -3,11 +3,42 @@ package helper
import (
"testing"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/sets"
workv1alpha1 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha1"
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
)
func TestGenerateFullyAppliedCondition(t *testing.T) {
spec := workv1alpha2.ResourceBindingSpec{
Clusters: []workv1alpha2.TargetCluster{
{Name: "cluster1"},
{Name: "cluster2"},
},
}
statuses := []workv1alpha2.AggregatedStatusItem{
{ClusterName: "cluster1", Applied: true, Health: workv1alpha2.ResourceHealthy},
{ClusterName: "cluster2", Applied: true, Health: workv1alpha2.ResourceUnknown},
}
expectedTrue := metav1.ConditionTrue
expectedFalse := metav1.ConditionFalse
resultTrue := generateFullyAppliedCondition(spec, statuses)
if resultTrue.Status != expectedTrue {
t.Errorf("generateFullyAppliedCondition with fully applied statuses returned %v, expected %v", resultTrue, expectedTrue)
}
resultFalse := generateFullyAppliedCondition(spec, statuses[:1])
if resultFalse.Status != expectedFalse {
t.Errorf("generateFullyAppliedCondition with partially applied statuses returned %v, expected %v", resultFalse, expectedFalse)
}
}
func TestWorksFullyApplied(t *testing.T) {
type args struct {
aggregatedStatuses []workv1alpha2.AggregatedStatusItem
@ -108,3 +139,150 @@ func TestWorksFullyApplied(t *testing.T) {
})
}
}
func TestGetManifestIndex(t *testing.T) {
manifest1 := workv1alpha1.Manifest{
RawExtension: runtime.RawExtension{
Raw: []byte(`{"apiVersion":"v1","kind":"Service","metadata":{"name":"test-service","namespace":"test-namespace"}}`),
},
}
manifest2 := workv1alpha1.Manifest{
RawExtension: runtime.RawExtension{
Raw: []byte(`{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"name":"test-deployment","namespace":"test-namespace"}}`),
},
}
manifests := []workv1alpha1.Manifest{manifest1, manifest2}
service := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "v1",
"kind": "Service",
"metadata": map[string]interface{}{
"name": "test-service",
"namespace": "test-namespace",
},
},
}
deployment := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "test-deployment",
"namespace": "test-namespace",
},
},
}
t.Run("Service", func(t *testing.T) {
index, err := GetManifestIndex(manifests, service)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if index != 0 {
t.Errorf("expected index 0, got %d", index)
}
})
t.Run("Deployment", func(t *testing.T) {
index, err := GetManifestIndex(manifests, deployment)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if index != 1 {
t.Errorf("expected index 1, got %d", index)
}
})
t.Run("No match", func(t *testing.T) {
_, err := GetManifestIndex(manifests, &unstructured.Unstructured{})
if err == nil {
t.Errorf("expected error, got nil")
}
})
}
func TestEqualIdentifier(t *testing.T) {
testCases := []struct {
name string
target *workv1alpha1.ResourceIdentifier
ordinal int
workload *unstructured.Unstructured
expectedOutput bool
}{
{
name: "identifiers are equal",
target: &workv1alpha1.ResourceIdentifier{
Ordinal: 0,
Group: "apps",
Version: "v1",
Kind: "Deployment",
Namespace: "default",
Name: "test-deployment",
},
ordinal: 0,
workload: &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"namespace": "default",
"name": "test-deployment",
},
},
},
expectedOutput: true,
},
{
name: "identifiers are not equal",
target: &workv1alpha1.ResourceIdentifier{
Ordinal: 1,
Group: "apps",
Version: "v1",
Kind: "Deployment",
Namespace: "default",
Name: "test-deployment",
},
ordinal: 0,
workload: &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"namespace": "default",
"name": "test-deployment",
},
},
},
expectedOutput: false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
equal, err := equalIdentifier(tc.target, tc.ordinal, tc.workload)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if equal != tc.expectedOutput {
t.Errorf("expected %v, got %v", tc.expectedOutput, equal)
}
})
}
}
func TestIsResourceApplied(t *testing.T) {
// Create a WorkStatus struct with a WorkApplied condition set to True
workStatus := &workv1alpha1.WorkStatus{
Conditions: []metav1.Condition{
{
Type: workv1alpha1.WorkApplied,
Status: metav1.ConditionTrue,
},
},
}
// Call IsResourceApplied and assert that it returns true
assert.True(t, IsResourceApplied(workStatus))
}

View File

@ -0,0 +1,828 @@
package interpreter
import (
"fmt"
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
)
func TestRetentionRule_Name(t *testing.T) {
r := &retentionRule{}
expected := string(configv1alpha1.InterpreterOperationRetain)
actual := r.Name()
assert.Equal(t, expected, actual, "Name should return %v", expected)
}
func TestRetentionRule_Document(t *testing.T) {
rule := &retentionRule{}
expected := `This rule is used to retain runtime values to the desired specification.
The script should implement a function as follows:
function Retain(desiredObj, observedObj)
desiredObj.spec.fieldFoo = observedObj.spec.fieldFoo
return desiredObj
end`
assert.Equal(t, expected, rule.Document())
}
func TestRetentionRule_GetScript(t *testing.T) {
t.Run("WithScript", func(t *testing.T) {
customization := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
Retention: &configv1alpha1.LocalValueRetention{
LuaScript: "hello world",
},
},
},
}
rule := &retentionRule{}
script := rule.GetScript(customization)
expectedScript := customization.Spec.Customizations.Retention.LuaScript
if script != expectedScript {
t.Errorf("GetScript() returned %q, expected %q", script, expectedScript)
}
})
t.Run("WithoutScript", func(t *testing.T) {
customization := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
Retention: nil,
},
},
}
rule := &retentionRule{}
script := rule.GetScript(customization)
if script != "" {
t.Errorf("GetScript() returned %q, expected an empty string", script)
}
})
}
func TestRetentionRule_SetScript(t *testing.T) {
t.Run("Set non-empty script", func(t *testing.T) {
customization := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
Retention: &configv1alpha1.LocalValueRetention{},
},
},
}
rule := &retentionRule{}
script := "function Retain(desiredObj, observedObj)\n desiredObj.spec.fieldFoo = observedObj.spec.fieldFoo\n return desiredObj\nend"
rule.SetScript(customization, script)
if customization.Spec.Customizations.Retention.LuaScript != script {
t.Errorf("Expected script to be set to %q, but got %q", script, customization.Spec.Customizations.Retention.LuaScript)
}
})
t.Run("Set empty script", func(t *testing.T) {
customization := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
Retention: nil,
},
},
}
rule := &retentionRule{}
script := ""
rule.SetScript(customization, script)
if customization.Spec.Customizations.Retention != nil {
t.Errorf("Expected retention to be nil, but got %v", customization.Spec.Customizations.Retention)
}
})
t.Run("Set empty Retention", func(t *testing.T) {
customization := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
Retention: nil,
},
},
}
rule := &retentionRule{}
script := "function Retain(desiredObj, observedObj)\n desiredObj.spec.fieldFoo = observedObj.spec.fieldFoo\n return desiredObj\nend"
rule.SetScript(customization, script)
if customization.Spec.Customizations.Retention.LuaScript != script {
t.Errorf("Expected script to be set to %q, but got %q", script, customization.Spec.Customizations.Retention.LuaScript)
}
})
}
func TestReplicaResourceRule_Name(t *testing.T) {
r := &replicaResourceRule{}
expected := string(configv1alpha1.InterpreterOperationInterpretReplica)
actual := r.Name()
assert.Equal(t, expected, actual, "Name should return %v", expected)
}
func TestReplicaResourceRule_Document(t *testing.T) {
rule := &replicaResourceRule{}
expected := `This rule is used to discover the resource's replica as well as resource requirements.
The script should implement a function as follows:
function GetReplicas(desiredObj)
replica = desiredObj.spec.replicas
nodeClaim = {}
nodeClaim.hardNodeAffinity = {}
nodeClaim.nodeSelector = {}
nodeClaim.tolerations = {}
return replica, nodeClaim
end`
assert.Equal(t, expected, rule.Document())
}
func TestReplicaResourceRule_GetScript(t *testing.T) {
t.Run("WithScript", func(t *testing.T) {
c := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
ReplicaResource: &configv1alpha1.ReplicaResourceRequirement{
LuaScript: "return 'test script'",
},
},
},
}
r := &replicaResourceRule{}
script := r.GetScript(c)
expectedScript := c.Spec.Customizations.ReplicaResource.LuaScript
if script != expectedScript {
t.Errorf("GetScript() returned %q, expected %q", script, expectedScript)
}
})
t.Run("WithoutScript", func(t *testing.T) {
c := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
ReplicaResource: nil,
},
},
}
rule := &replicaResourceRule{}
script := rule.GetScript(c)
if script != "" {
t.Errorf("GetScript() returned %q, expected an empty string", script)
}
})
}
func TestReplicaResourceRule_SetScript(t *testing.T) {
c := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
ReplicaResource: &configv1alpha1.ReplicaResourceRequirement{},
},
},
}
r := &replicaResourceRule{}
t.Run("Empty Script", func(t *testing.T) {
r.SetScript(c, "")
if c.Spec.Customizations.ReplicaResource != nil {
t.Errorf("Expected ReplicaResource to be nil, but got %v", c.Spec.Customizations.ReplicaResource)
}
})
t.Run("Non-Empty Script", func(t *testing.T) {
c.Spec.Customizations.ReplicaResource = nil
script := "test script"
r.SetScript(c, script)
if c.Spec.Customizations.ReplicaResource == nil {
t.Errorf("Expected ReplicaResource to be non-nil, but got nil")
}
if c.Spec.Customizations.ReplicaResource.LuaScript != "test script" {
t.Errorf("Expected ReplicaResource.LuaScript to be %s, but got %s", script, c.Spec.Customizations.ReplicaResource.LuaScript)
}
})
}
func TestReplicaRevisionRule_Name(t *testing.T) {
r := &replicaRevisionRule{}
expected := string(configv1alpha1.InterpreterOperationReviseReplica)
actual := r.Name()
assert.Equal(t, expected, actual, "Name should return %v", expected)
}
func TestReplicaRevisionRule_Document(t *testing.T) {
rule := &replicaRevisionRule{}
expected := `This rule is used to revise replicas in the desired specification.
The script should implement a function as follows:
function ReviseReplica(desiredObj, desiredReplica)
desiredObj.spec.replicas = desiredReplica
return desiredObj
end`
assert.Equal(t, expected, rule.Document())
}
func TestReplicaRevisionRule_GetScript(t *testing.T) {
t.Run("WithScript", func(t *testing.T) {
c := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
ReplicaRevision: &configv1alpha1.ReplicaRevision{
LuaScript: "return 'test script'",
},
},
},
}
r := &replicaRevisionRule{}
script := r.GetScript(c)
expectedScript := c.Spec.Customizations.ReplicaRevision.LuaScript
if script != expectedScript {
t.Errorf("GetScript() returned %q, expected %q", script, expectedScript)
}
})
t.Run("WithoutScript", func(t *testing.T) {
c := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
ReplicaRevision: nil,
},
},
}
rule := &replicaRevisionRule{}
script := rule.GetScript(c)
if script != "" {
t.Errorf("GetScript() returned %q, expected an empty string", script)
}
})
}
func TestReplicaRevisionRule_SetScript(t *testing.T) {
c := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
ReplicaRevision: &configv1alpha1.ReplicaRevision{},
},
},
}
r := &replicaRevisionRule{}
t.Run("Empty Script", func(t *testing.T) {
r.SetScript(c, "")
if c.Spec.Customizations.ReplicaRevision != nil {
t.Errorf("Expected ReplicaRevision to be nil, but got %v", c.Spec.Customizations.ReplicaRevision)
}
})
t.Run("Non-Empty Script", func(t *testing.T) {
c.Spec.Customizations.ReplicaRevision = nil
script := "test script"
r.SetScript(c, script)
if c.Spec.Customizations.ReplicaRevision == nil {
t.Errorf("Expected ReplicaRevision to be non-nil, but got nil")
}
if c.Spec.Customizations.ReplicaRevision.LuaScript != "test script" {
t.Errorf("Expected ReplicaRevision.LuaScript to be %s, but got %s", script, c.Spec.Customizations.ReplicaRevision.LuaScript)
}
})
}
func TestStatusReflectionRule_Name(t *testing.T) {
r := &statusReflectionRule{}
expected := string(configv1alpha1.InterpreterOperationInterpretStatus)
actual := r.Name()
assert.Equal(t, expected, actual, "Name should return %v", expected)
}
func TestStatusReflectionRule_Document(t *testing.T) {
rule := &statusReflectionRule{}
expected := `This rule is used to get the status from the observed specification.
The script should implement a function as follows:
function ReflectStatus(observedObj)
status = {}
status.readyReplicas = observedObj.status.observedObj
return status
end`
assert.Equal(t, expected, rule.Document())
}
func TestStatusReflectionRule_GetScript(t *testing.T) {
t.Run("WithScript", func(t *testing.T) {
c := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
StatusReflection: &configv1alpha1.StatusReflection{
LuaScript: "return 'test script'",
},
},
},
}
r := &statusReflectionRule{}
script := r.GetScript(c)
expectedScript := c.Spec.Customizations.StatusReflection.LuaScript
if script != expectedScript {
t.Errorf("GetScript() returned %q, expected %q", script, expectedScript)
}
})
t.Run("WithoutScript", func(t *testing.T) {
c := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
StatusReflection: nil,
},
},
}
rule := &statusReflectionRule{}
script := rule.GetScript(c)
if script != "" {
t.Errorf("GetScript() returned %q, expected an empty string", script)
}
})
}
func TestStatusReflectionRule_SetScript(t *testing.T) {
c := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
StatusReflection: &configv1alpha1.StatusReflection{},
},
},
}
r := &statusReflectionRule{}
t.Run("Empty Script", func(t *testing.T) {
r.SetScript(c, "")
if c.Spec.Customizations.StatusReflection != nil {
t.Errorf("Expected StatusReflection to be nil, but got %v", c.Spec.Customizations.StatusReflection)
}
})
t.Run("Non-Empty Script", func(t *testing.T) {
c.Spec.Customizations.StatusReflection = nil
script := "test script"
r.SetScript(c, script)
if c.Spec.Customizations.StatusReflection == nil {
t.Errorf("Expected StatusReflection to be non-nil, but got nil")
}
if c.Spec.Customizations.StatusReflection.LuaScript != "test script" {
t.Errorf("Expected StatusReflection.LuaScript to be %s, but got %s", script, c.Spec.Customizations.StatusReflection.LuaScript)
}
})
}
func TestStatusAggregationRule_Name(t *testing.T) {
r := &statusAggregationRule{}
expected := string(configv1alpha1.InterpreterOperationAggregateStatus)
actual := r.Name()
assert.Equal(t, expected, actual, "Name should return %v", expected)
}
func TestStatusAggregationRule_Document(t *testing.T) {
rule := &statusAggregationRule{}
expected := `This rule is used to aggregate decentralized statuses to the desired specification.
The script should implement a function as follows:
function AggregateStatus(desiredObj, statusItems)
for i = 1, #items do
desiredObj.status.readyReplicas = desiredObj.status.readyReplicas + items[i].readyReplicas
end
return desiredObj
end`
assert.Equal(t, expected, rule.Document())
}
func TestStatusAggregationRule_GetScript(t *testing.T) {
t.Run("WithScript", func(t *testing.T) {
c := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
StatusAggregation: &configv1alpha1.StatusAggregation{
LuaScript: "return 'test script'",
},
},
},
}
r := &statusAggregationRule{}
script := r.GetScript(c)
expectedScript := c.Spec.Customizations.StatusAggregation.LuaScript
if script != expectedScript {
t.Errorf("GetScript() returned %q, expected %q", script, expectedScript)
}
})
t.Run("WithoutScript", func(t *testing.T) {
c := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
StatusAggregation: nil,
},
},
}
rule := &statusAggregationRule{}
script := rule.GetScript(c)
if script != "" {
t.Errorf("GetScript() returned %q, expected an empty string", script)
}
})
}
func TestStatusAggregationRule_SetScript(t *testing.T) {
c := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
StatusAggregation: &configv1alpha1.StatusAggregation{},
},
},
}
r := &statusAggregationRule{}
t.Run("Empty Script", func(t *testing.T) {
r.SetScript(c, "")
if c.Spec.Customizations.StatusAggregation != nil {
t.Errorf("Expected StatusAggregation to be nil, but got %v", c.Spec.Customizations.StatusAggregation)
}
})
t.Run("Non-Empty Script", func(t *testing.T) {
c.Spec.Customizations.StatusAggregation = nil
script := "test script"
r.SetScript(c, script)
if c.Spec.Customizations.StatusAggregation == nil {
t.Errorf("Expected Customizations to be non-nil, but got nil")
}
if c.Spec.Customizations.StatusAggregation.LuaScript != "test script" {
t.Errorf("Expected StatusAggregation.LuaScript to be %s, but got %s", script, c.Spec.Customizations.StatusAggregation.LuaScript)
}
})
}
func TestHealthInterpretationRule_Name(t *testing.T) {
r := &healthInterpretationRule{}
expected := string(configv1alpha1.InterpreterOperationInterpretHealth)
actual := r.Name()
assert.Equal(t, expected, actual, "Name should return %v", expected)
}
func TestHealthInterpretationRule_Document(t *testing.T) {
rule := &healthInterpretationRule{}
expected := `This rule is used to assess the health state of a specific resource.
The script should implement a function as follows:
luaScript: >
function InterpretHealth(observedObj)
if observedObj.status.readyReplicas == observedObj.spec.replicas then
return true
end
end`
assert.Equal(t, expected, rule.Document())
}
func TestHealthInterpretationRule_GetScript(t *testing.T) {
t.Run("WithScript", func(t *testing.T) {
c := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
HealthInterpretation: &configv1alpha1.HealthInterpretation{
LuaScript: "return 'test script'",
},
},
},
}
r := &healthInterpretationRule{}
script := r.GetScript(c)
expectedScript := c.Spec.Customizations.HealthInterpretation.LuaScript
if script != expectedScript {
t.Errorf("GetScript() returned %q, expected %q", script, expectedScript)
}
})
t.Run("WithoutScript", func(t *testing.T) {
c := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
HealthInterpretation: nil,
},
},
}
rule := &healthInterpretationRule{}
script := rule.GetScript(c)
if script != "" {
t.Errorf("GetScript() returned %q, expected an empty string", script)
}
})
}
func TestHealthInterpretationRule_SetScript(t *testing.T) {
c := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
HealthInterpretation: &configv1alpha1.HealthInterpretation{},
},
},
}
r := &healthInterpretationRule{}
t.Run("Empty Script", func(t *testing.T) {
r.SetScript(c, "")
if c.Spec.Customizations.HealthInterpretation != nil {
t.Errorf("Expected HealthInterpretation to be nil, but got %v", c.Spec.Customizations.HealthInterpretation)
}
})
t.Run("Non-Empty Script", func(t *testing.T) {
c.Spec.Customizations.HealthInterpretation = nil
script := "test script"
r.SetScript(c, script)
if c.Spec.Customizations.HealthInterpretation == nil {
t.Errorf("Expected HealthInterpretation to be non-nil, but got nil")
}
if c.Spec.Customizations.HealthInterpretation.LuaScript != "test script" {
t.Errorf("Expected HealthInterpretation.LuaScript to be %s, but got %s", script, c.Spec.Customizations.HealthInterpretation.LuaScript)
}
})
}
func TestDependencyInterpretationRule_Name(t *testing.T) {
r := &dependencyInterpretationRule{}
expected := string(configv1alpha1.InterpreterOperationInterpretDependency)
actual := r.Name()
assert.Equal(t, expected, actual, "Name should return %v", expected)
}
func TestDependencyInterpretationRule_Document(t *testing.T) {
rule := &dependencyInterpretationRule{}
expected := ` This rule is used to interpret the dependencies of a specific resource.
The script should implement a function as follows:
function GetDependencies(desiredObj)
dependencies = {}
if desiredObj.spec.serviceAccountName ~= "" and desiredObj.spec.serviceAccountName ~= "default" then
dependency = {}
dependency.apiVersion = "v1"
dependency.kind = "ServiceAccount"
dependency.name = desiredObj.spec.serviceAccountName
dependency.namespace = desiredObj.namespace
dependencies[0] = {}
dependencies[0] = dependency
end
return dependencies
end`
assert.Equal(t, expected, rule.Document())
}
func TestDependencyInterpretationRule_GetScript(t *testing.T) {
t.Run("WithScript", func(t *testing.T) {
c := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
DependencyInterpretation: &configv1alpha1.DependencyInterpretation{
LuaScript: "return 'test script'",
},
},
},
}
r := &dependencyInterpretationRule{}
script := r.GetScript(c)
expectedScript := c.Spec.Customizations.DependencyInterpretation.LuaScript
if script != expectedScript {
t.Errorf("GetScript() returned %q, expected %q", script, expectedScript)
}
})
t.Run("WithoutScript", func(t *testing.T) {
c := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
DependencyInterpretation: nil,
},
},
}
rule := &dependencyInterpretationRule{}
script := rule.GetScript(c)
if script != "" {
t.Errorf("GetScript() returned %q, expected an empty string", script)
}
})
}
func TestDependencyInterpretationRule_SetScript(t *testing.T) {
c := &configv1alpha1.ResourceInterpreterCustomization{
Spec: configv1alpha1.ResourceInterpreterCustomizationSpec{
Customizations: configv1alpha1.CustomizationRules{
DependencyInterpretation: &configv1alpha1.DependencyInterpretation{},
},
},
}
r := &dependencyInterpretationRule{}
t.Run("Empty Script", func(t *testing.T) {
r.SetScript(c, "")
if c.Spec.Customizations.DependencyInterpretation != nil {
t.Errorf("Expected DependencyInterpretation to be nil, but got %v", c.Spec.Customizations.DependencyInterpretation)
}
})
t.Run("Non-Empty Script", func(t *testing.T) {
c.Spec.Customizations.DependencyInterpretation = nil
script := "test script"
r.SetScript(c, script)
if c.Spec.Customizations.DependencyInterpretation == nil {
t.Errorf("Expected DependencyInterpretation to be non-nil, but got nil")
}
if c.Spec.Customizations.DependencyInterpretation.LuaScript != "test script" {
t.Errorf("Expected DependencyInterpretation.LuaScript to be %s, but got %s", script, c.Spec.Customizations.DependencyInterpretation.LuaScript)
}
})
}
func TestRulesNames(t *testing.T) {
rule1 := &healthInterpretationRule{}
rule2 := &dependencyInterpretationRule{}
rules := Rules{rule1, rule2}
expectedNames := []string{rule1.Name(), rule2.Name()}
actualNames := rules.Names()
if !reflect.DeepEqual(actualNames, expectedNames) {
t.Errorf("Expected names %v, but got %v", expectedNames, actualNames)
}
}
func TestGetByOperation(t *testing.T) {
rules := Rules{&healthInterpretationRule{}, &dependencyInterpretationRule{}}
tests := []struct {
name string
operation string
expectedRule Rule
}{
{
name: "valid operation name",
operation: "InterpretHealth",
expectedRule: &healthInterpretationRule{},
},
{
name: "invalid operation name",
operation: "invalid",
expectedRule: nil,
},
{
name: "empty operation name",
operation: "",
expectedRule: nil,
},
{
name: "case-insensitive operation namee",
operation: "InterpretDEPendency",
expectedRule: &dependencyInterpretationRule{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actualRule := rules.GetByOperation(tt.operation)
if actualRule != tt.expectedRule {
t.Errorf("Expected rule %v, but got %v", tt.expectedRule, actualRule)
}
})
}
}
func TestRules_Get(t *testing.T) {
rule1 := &healthInterpretationRule{}
rule2 := &dependencyInterpretationRule{}
rules := Rules{rule1, rule2}
// Test getting a rule that exists
result := rules.Get("InterpretHealth")
if result != rule1 {
t.Errorf("Expected rule1, but got %v", result)
}
// Test getting a rule that does not exist
result = rules.Get("NonexistentRule")
if result != nil {
t.Errorf("Expected nil, but got %v", result)
}
}
func TestGetDesiredObjectOrError(t *testing.T) {
args := RuleArgs{
Desired: nil,
}
_, err := args.getDesiredObjectOrError()
expectedErr := "desired, desired-file options are not set"
if err == nil || err.Error() != expectedErr {
t.Errorf("getDesiredObjectOrError() returned unexpected error: %v", err)
}
}
func TestGetObservedObjectOrError(t *testing.T) {
args := RuleArgs{}
_, err := args.getObservedObjectOrError()
if err == nil {
t.Errorf("Expected error, but got nil")
}
obj := &unstructured.Unstructured{}
args.Observed = obj
result, err := args.getObservedObjectOrError()
if err != nil {
t.Errorf("Expected nil error, but got %v", err)
}
if result != obj {
t.Errorf("Expected %v, but got %v", obj, result)
}
}
func TestGetObjectOrError(t *testing.T) {
desired := &unstructured.Unstructured{}
observed := &unstructured.Unstructured{}
t.Run("Both desired and observed objects are nil", func(t *testing.T) {
args := RuleArgs{}
_, err := args.getObjectOrError()
if err == nil {
t.Errorf("Expected error, but got nil")
}
})
t.Run("Both desired and observed objects are set", func(t *testing.T) {
args := RuleArgs{Desired: desired, Observed: observed}
_, err := args.getObjectOrError()
if err == nil {
t.Errorf("Expected error, but got nil")
}
})
t.Run("Only desired object is set", func(t *testing.T) {
args := RuleArgs{Desired: desired}
obj, err := args.getObjectOrError()
if err != nil {
t.Errorf("Expected nil error, but got %v", err)
}
if obj != desired {
t.Errorf("Expected %v, but got %v", desired, obj)
}
})
t.Run("Only observed object is set", func(t *testing.T) {
args := RuleArgs{Observed: observed}
obj, err := args.getObjectOrError()
if err != nil {
t.Errorf("Expected nil error, but got %v", err)
}
if obj != observed {
t.Errorf("Expected %v, but got %v", observed, obj)
}
})
}
func TestNewRuleResult(t *testing.T) {
result := newRuleResult()
if result.Err != nil {
t.Errorf("Expected error to be nil, but got %v", result.Err)
}
if len(result.Results) != 0 {
t.Errorf("Expected results to be empty, but got %v", result.Results)
}
}
func TestNewRuleResultWithError(t *testing.T) {
err := fmt.Errorf("test error")
result := newRuleResultWithError(err)
if result.Err != err {
t.Errorf("expected error %v, but got %v", err, result.Err)
}
}
func TestRuleResultAdd(t *testing.T) {
r := newRuleResult()
r.add("test1", "value1")
r.add("test2", 2)
if len(r.Results) != 2 {
t.Errorf("Expected 2 results, but got %d", len(r.Results))
}
if r.Results[0].Name != "test1" || r.Results[0].Value != "value1" {
t.Errorf("Unexpected result at index 0: %v", r.Results[0])
}
if r.Results[1].Name != "test2" || r.Results[1].Value != 2 {
t.Errorf("Unexpected result at index 1: %v", r.Results[1])
}
}