This is an automated email from the ASF dual-hosted git repository.
jimin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-seata-k8s.git
The following commit(s) were added to refs/heads/master by this push:
new e944657 optimize: add some UT for pkg (#50)
e944657 is described below
commit e944657c37f958542beb4d70ada8487c9b891583
Author: jimin <[email protected]>
AuthorDate: Sat Jan 10 18:00:20 2026 +0800
optimize: add some UT for pkg (#50)
---
pkg/finalizer/finalizer_manager_test.go | 239 ++++++++++++++++++++++++++++++--
pkg/seata/generators_test.go | 131 +++++++++++++++++
pkg/seata/synchronizers_test.go | 107 ++++++++++++++
pkg/webhook/validating_webhook_test.go | 110 +++++++++++++++
4 files changed, 578 insertions(+), 9 deletions(-)
diff --git a/pkg/finalizer/finalizer_manager_test.go
b/pkg/finalizer/finalizer_manager_test.go
index 8e8f290..90af00c 100644
--- a/pkg/finalizer/finalizer_manager_test.go
+++ b/pkg/finalizer/finalizer_manager_test.go
@@ -19,16 +19,33 @@ package finalizer
import (
"context"
+ "testing"
+ "time"
+
seatav1 "github.com/apache/seata-k8s/api/v1"
+ seatav1alpha1 "github.com/apache/seata-k8s/api/v1alpha1"
"github.com/go-logr/logr"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
- "testing"
- "time"
)
+func TestNewFinalizerManager(t *testing.T) {
+ scheme := createTestScheme()
+ fakeClient := fake.NewClientBuilder().WithScheme(scheme).Build()
+ logger := logr.Discard()
+
+ fm := NewFinalizerManager(fakeClient, logger)
+
+ if fm == nil {
+ t.Fatal("NewFinalizerManager should not return nil")
+ }
+ if fm.Client == nil {
+ t.Error("FinalizerManager.Client should not be nil")
+ }
+}
+
func TestFinalizerManager_AddFinalizer(t *testing.T) {
testCases := []struct {
name string
@@ -285,23 +302,227 @@ func TestFinalizerManager_IsBeingDeleted(t *testing.T) {
}
func TestFinalizerManager_GetNamespacedName(t *testing.T) {
- seataServer := &seatav1.SeataServer{
+ testCases := []struct {
+ name string
+ server interface{}
+ expected types.NamespacedName
+ }{
+ {
+ name: "v1 SeataServer",
+ server: &seatav1.SeataServer{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-seata",
+ Namespace: "default",
+ },
+ },
+ expected: types.NamespacedName{Name: "test-seata",
Namespace: "default"},
+ },
+ {
+ name: "v1alpha1 SeataServer",
+ server: &seatav1alpha1.SeataServer{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-alpha",
+ Namespace: "test-ns",
+ },
+ },
+ expected: types.NamespacedName{Name: "test-alpha",
Namespace: "test-ns"},
+ },
+ {
+ name: "unsupported type",
+ server: "invalid",
+ expected: types.NamespacedName{},
+ },
+ }
+
+ fm := &FinalizerManager{
+ Client: nil,
+ Log: logr.Discard(),
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ result := fm.GetNamespacedName(tc.server)
+ if result != tc.expected {
+ t.Errorf("expected %v, got %v", tc.expected,
result)
+ }
+ })
+ }
+}
+
+func TestFinalizerManager_GetDeletionTimestamp(t *testing.T) {
+ now := metav1.Now()
+
+ testCases := []struct {
+ name string
+ server interface{}
+ expected interface{}
+ }{
+ {
+ name: "v1 SeataServer with deletion timestamp",
+ server: &seatav1.SeataServer{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-seata",
+ Namespace: "default",
+ DeletionTimestamp: &now,
+ },
+ },
+ expected: &now,
+ },
+ {
+ name: "v1alpha1 SeataServer with deletion timestamp",
+ server: &seatav1alpha1.SeataServer{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-alpha",
+ Namespace: "default",
+ DeletionTimestamp: &now,
+ },
+ },
+ expected: &now,
+ },
+ {
+ name: "unsupported type",
+ server: "invalid",
+ expected: nil,
+ },
+ }
+
+ fm := &FinalizerManager{
+ Client: nil,
+ Log: logr.Discard(),
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ result := fm.GetDeletionTimestamp(tc.server)
+ if result != tc.expected {
+ t.Errorf("expected %v, got %v", tc.expected,
result)
+ }
+ })
+ }
+}
+
+func TestFinalizerManager_AddFinalizer_V1Alpha1(t *testing.T) {
+ scheme := runtime.NewScheme()
+ _ = seatav1.AddToScheme(scheme)
+ _ = seatav1alpha1.AddToScheme(scheme)
+
+ seataServer := &seatav1alpha1.SeataServer{
ObjectMeta: metav1.ObjectMeta{
- Name: "test-seata",
- Namespace: "default",
+ Name: "test-seata-alpha",
+ Namespace: "default",
+ Finalizers: []string{},
},
}
+ fakeClient := fake.NewClientBuilder().
+ WithScheme(scheme).
+ WithObjects(seataServer).
+ Build()
+
+ fm := &FinalizerManager{
+ Client: fakeClient,
+ Log: logr.Discard(),
+ }
+
+ ctx := context.Background()
+ err := fm.AddFinalizer(ctx, seataServer, SeataFinalizerName)
+
+ if err != nil {
+ t.Errorf("AddFinalizer for v1alpha1 failed: %v", err)
+ }
+
+ if !fm.HasFinalizer(seataServer, SeataFinalizerName) {
+ t.Errorf("finalizer %s not found after adding",
SeataFinalizerName)
+ }
+}
+
+func TestFinalizerManager_RemoveFinalizer_V1Alpha1(t *testing.T) {
+ scheme := runtime.NewScheme()
+ _ = seatav1.AddToScheme(scheme)
+ _ = seatav1alpha1.AddToScheme(scheme)
+
+ seataServer := &seatav1alpha1.SeataServer{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-seata-alpha",
+ Namespace: "default",
+ Finalizers: []string{SeataFinalizerName,
"other-finalizer"},
+ },
+ }
+
+ fakeClient := fake.NewClientBuilder().
+ WithScheme(scheme).
+ WithObjects(seataServer).
+ Build()
+
+ fm := &FinalizerManager{
+ Client: fakeClient,
+ Log: logr.Discard(),
+ }
+
+ ctx := context.Background()
+ err := fm.RemoveFinalizer(ctx, seataServer, SeataFinalizerName)
+
+ if err != nil {
+ t.Errorf("RemoveFinalizer for v1alpha1 failed: %v", err)
+ }
+
+ hasFinalizer := fm.HasFinalizer(seataServer, SeataFinalizerName)
+ if hasFinalizer {
+ t.Errorf("expected finalizer to be removed")
+ }
+}
+
+func TestFinalizerManager_AddFinalizer_UnsupportedType(t *testing.T) {
+ scheme := createTestScheme()
+ fakeClient := fake.NewClientBuilder().WithScheme(scheme).Build()
+
+ fm := &FinalizerManager{
+ Client: fakeClient,
+ Log: logr.Discard(),
+ }
+
+ err := fm.AddFinalizer(context.Background(), "invalid-type",
SeataFinalizerName)
+ if err == nil {
+ t.Error("Expected error for unsupported type, got nil")
+ }
+}
+
+func TestFinalizerManager_RemoveFinalizer_UnsupportedType(t *testing.T) {
+ scheme := createTestScheme()
+ fakeClient := fake.NewClientBuilder().WithScheme(scheme).Build()
+
+ fm := &FinalizerManager{
+ Client: fakeClient,
+ Log: logr.Discard(),
+ }
+
+ err := fm.RemoveFinalizer(context.Background(), "invalid-type",
SeataFinalizerName)
+ if err == nil {
+ t.Error("Expected error for unsupported type, got nil")
+ }
+}
+
+func TestFinalizerManager_HasFinalizer_UnsupportedType(t *testing.T) {
fm := &FinalizerManager{
Client: nil,
Log: logr.Discard(),
}
- result := fm.GetNamespacedName(seataServer)
- expected := types.NamespacedName{Name: "test-seata", Namespace:
"default"}
+ result := fm.HasFinalizer("invalid-type", SeataFinalizerName)
+ if result {
+ t.Error("Expected false for unsupported type")
+ }
+}
+
+func TestFinalizerManager_IsBeingDeleted_UnsupportedType(t *testing.T) {
+ fm := &FinalizerManager{
+ Client: nil,
+ Log: logr.Discard(),
+ }
- if result != expected {
- t.Errorf("expected %v, got %v", expected, result)
+ result := fm.IsBeingDeleted("invalid-type")
+ if result {
+ t.Error("Expected false for unsupported type")
}
}
diff --git a/pkg/seata/generators_test.go b/pkg/seata/generators_test.go
index 3abfb6d..c9dbc12 100644
--- a/pkg/seata/generators_test.go
+++ b/pkg/seata/generators_test.go
@@ -340,3 +340,134 @@ func TestBuildEnvVars_WithMultipleReplicas(t *testing.T) {
}
}
+func TestMakeStatefulSet_WithEmptyLabelsAndAnnotations(t *testing.T) {
+ seataServer := &seatav1alpha1.SeataServer{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-seata",
+ Namespace: "default",
+ UID: types.UID("test-uid"),
+ },
+ Spec: seatav1alpha1.SeataServerSpec{
+ ContainerSpec: seatav1alpha1.ContainerSpec{
+ ContainerName: "seata",
+ Image: "seata:latest",
+ },
+ ServiceName: "seata-svc",
+ Replicas: 1,
+ Ports: seatav1alpha1.Ports{
+ ServicePort: 8091,
+ ConsolePort: 7091,
+ RaftPort: 9091,
+ },
+ Persistence: seatav1alpha1.Persistence{
+ PersistentVolumeClaimSpec:
apiv1.PersistentVolumeClaimSpec{
+ Resources: apiv1.ResourceRequirements{
+ Requests: apiv1.ResourceList{
+ apiv1.ResourceStorage:
resource.MustParse("1Gi"),
+ },
+ },
+ },
+ },
+ },
+ }
+
+ sts := MakeStatefulSet(seataServer)
+
+ if sts == nil {
+ t.Fatal("MakeStatefulSet returned nil")
+ }
+
+ if sts.Name != "test-seata" {
+ t.Errorf("Expected name 'test-seata', got '%s'", sts.Name)
+ }
+}
+
+func TestMakeHeadlessService_WithDifferentPorts(t *testing.T) {
+ seataServer := &seatav1alpha1.SeataServer{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "custom-seata",
+ Namespace: "custom-ns",
+ },
+ Spec: seatav1alpha1.SeataServerSpec{
+ ServiceName: "custom-service",
+ Ports: seatav1alpha1.Ports{
+ ServicePort: 8888,
+ ConsolePort: 7777,
+ RaftPort: 9999,
+ },
+ },
+ }
+
+ svc := MakeHeadlessService(seataServer)
+
+ if svc.Name != "custom-service" {
+ t.Errorf("Expected service name 'custom-service', got '%s'",
svc.Name)
+ }
+
+ if svc.Namespace != "custom-ns" {
+ t.Errorf("Expected namespace 'custom-ns', got '%s'",
svc.Namespace)
+ }
+
+ portMap := make(map[string]int32)
+ for _, port := range svc.Spec.Ports {
+ portMap[port.Name] = port.Port
+ }
+
+ if portMap["service-port"] != 8888 {
+ t.Errorf("Expected service-port 8888, got %d",
portMap["service-port"])
+ }
+ if portMap["console-port"] != 7777 {
+ t.Errorf("Expected console-port 7777, got %d",
portMap["console-port"])
+ }
+ if portMap["raft-port"] != 9999 {
+ t.Errorf("Expected raft-port 9999, got %d",
portMap["raft-port"])
+ }
+}
+
+func TestBuildEntrypointScript_WithDifferentServiceName(t *testing.T) {
+ seataServer := &seatav1alpha1.SeataServer{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "my-seata",
+ Namespace: "production",
+ },
+ Spec: seatav1alpha1.SeataServerSpec{
+ ServiceName: "my-custom-service",
+ },
+ }
+
+ script := buildEntrypointScript(seataServer)
+
+ if !strings.Contains(script, "my-custom-service") {
+ t.Errorf("Script should contain service name
'my-custom-service', got: %s", script)
+ }
+
+ if !strings.Contains(script, "export SEATA_IP") {
+ t.Error("Script should contain SEATA_IP export")
+ }
+}
+
+func TestBuildEnvVars_EmptyEnv(t *testing.T) {
+ seataServer := &seatav1alpha1.SeataServer{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "test-seata",
+ Namespace: "default",
+ },
+ Spec: seatav1alpha1.SeataServerSpec{
+ ContainerSpec: seatav1alpha1.ContainerSpec{
+ Env: []apiv1.EnvVar{},
+ },
+ Ports: seatav1alpha1.Ports{
+ ServicePort: 8091,
+ ConsolePort: 7091,
+ RaftPort: 9091,
+ },
+ },
+ }
+
+ envs := buildEnvVars(seataServer)
+
+ // Should still have base environment variables
+ if len(envs) < 5 {
+ t.Errorf("Expected at least 5 base env vars, got %d", len(envs))
+ }
+}
diff --git a/pkg/seata/synchronizers_test.go b/pkg/seata/synchronizers_test.go
index bcae8d2..545bd6b 100644
--- a/pkg/seata/synchronizers_test.go
+++ b/pkg/seata/synchronizers_test.go
@@ -262,3 +262,110 @@ func TestSyncStatefulSet_WithMultipleContainers(t
*testing.T) {
}
}
+func TestSyncService_WithSinglePort(t *testing.T) {
+ curr := &apiv1.Service{
+ Spec: apiv1.ServiceSpec{
+ Ports: []apiv1.ServicePort{
+ {Name: "old-port", Port: 8080},
+ {Name: "another-port", Port: 9090},
+ },
+ },
+ }
+
+ next := &apiv1.Service{
+ Spec: apiv1.ServiceSpec{
+ Ports: []apiv1.ServicePort{
+ {Name: "new-port", Port: 8091},
+ },
+ },
+ }
+
+ SyncService(curr, next)
+
+ if len(curr.Spec.Ports) != 1 {
+ t.Errorf("Expected 1 port after sync, got %d",
len(curr.Spec.Ports))
+ }
+
+ if curr.Spec.Ports[0].Name != "new-port" {
+ t.Errorf("Expected port name 'new-port', got '%s'",
curr.Spec.Ports[0].Name)
+ }
+
+ if curr.Spec.Ports[0].Port != 8091 {
+ t.Errorf("Expected port 8091, got %d", curr.Spec.Ports[0].Port)
+ }
+}
+
+func TestSyncStatefulSet_ReplicasScaleUp(t *testing.T) {
+ replicas1 := int32(1)
+ replicas5 := int32(5)
+
+ curr := &appsv1.StatefulSet{
+ Spec: appsv1.StatefulSetSpec{
+ Replicas: &replicas1,
+ Template: apiv1.PodTemplateSpec{
+ Spec: apiv1.PodSpec{
+ Containers: []apiv1.Container{
+ {Name: "app", Image: "app:v1"},
+ },
+ },
+ },
+ },
+ }
+
+ next := &appsv1.StatefulSet{
+ Spec: appsv1.StatefulSetSpec{
+ Replicas: &replicas5,
+ Template: apiv1.PodTemplateSpec{
+ Spec: apiv1.PodSpec{
+ Containers: []apiv1.Container{
+ {Name: "app", Image: "app:v1"},
+ },
+ },
+ },
+ },
+ }
+
+ SyncStatefulSet(curr, next)
+
+ if *curr.Spec.Replicas != 5 {
+ t.Errorf("Expected 5 replicas after scale up, got %d",
*curr.Spec.Replicas)
+ }
+}
+
+func TestSyncStatefulSet_ReplicasScaleDown(t *testing.T) {
+ replicas5 := int32(5)
+ replicas2 := int32(2)
+
+ curr := &appsv1.StatefulSet{
+ Spec: appsv1.StatefulSetSpec{
+ Replicas: &replicas5,
+ Template: apiv1.PodTemplateSpec{
+ Spec: apiv1.PodSpec{
+ Containers: []apiv1.Container{
+ {Name: "app", Image: "app:v1"},
+ },
+ },
+ },
+ },
+ }
+
+ next := &appsv1.StatefulSet{
+ Spec: appsv1.StatefulSetSpec{
+ Replicas: &replicas2,
+ Template: apiv1.PodTemplateSpec{
+ Spec: apiv1.PodSpec{
+ Containers: []apiv1.Container{
+ {Name: "app", Image: "app:v1"},
+ },
+ },
+ },
+ },
+ }
+
+ SyncStatefulSet(curr, next)
+
+ if *curr.Spec.Replicas != 2 {
+ t.Errorf("Expected 2 replicas after scale down, got %d",
*curr.Spec.Replicas)
+ }
+}
+
diff --git a/pkg/webhook/validating_webhook_test.go
b/pkg/webhook/validating_webhook_test.go
index 12ff24d..9cffb35 100644
--- a/pkg/webhook/validating_webhook_test.go
+++ b/pkg/webhook/validating_webhook_test.go
@@ -344,6 +344,13 @@ func TestValidateEnvironmentVariables(t *testing.T) {
},
valid: false,
},
+ {
+ name: "invalid too long name",
+ envs: []apiv1.EnvVar{
+ {Name: "VAR_" + string(make([]byte, 250)),
Value: "value"},
+ },
+ valid: false,
+ },
}
for _, tc := range testCases {
@@ -356,6 +363,43 @@ func TestValidateEnvironmentVariables(t *testing.T) {
}
}
+func TestValidateResourceQuantity(t *testing.T) {
+ testCases := []struct {
+ name string
+ resourceName string
+ quantity resource.Quantity
+ valid bool
+ }{
+ {
+ name: "valid positive quantity",
+ resourceName: "cpu",
+ quantity: resource.MustParse("100m"),
+ valid: true,
+ },
+ {
+ name: "valid zero quantity",
+ resourceName: "memory",
+ quantity: resource.MustParse("0"),
+ valid: true,
+ },
+ {
+ name: "invalid negative quantity",
+ resourceName: "cpu",
+ quantity: resource.MustParse("-100m"),
+ valid: false,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ err := validateResourceQuantity(tc.resourceName,
tc.quantity)
+ if (err == nil) != tc.valid {
+ t.Errorf("expected valid=%v, got error=%v",
tc.valid, err)
+ }
+ })
+ }
+}
+
func TestValidateSeataServer(t *testing.T) {
testCases := []struct {
name string
@@ -411,6 +455,11 @@ func TestValidateSeataServer(t *testing.T) {
},
valid: false,
},
+ {
+ name: "nil SeataServer",
+ server: nil,
+ valid: false,
+ },
}
for _, tc := range testCases {
@@ -422,3 +471,64 @@ func TestValidateSeataServer(t *testing.T) {
})
}
}
+
+func TestValidateResourceRequirements(t *testing.T) {
+ testCases := []struct {
+ name string
+ requirements apiv1.ResourceRequirements
+ valid bool
+ }{
+ {
+ name: "valid resource requirements",
+ requirements: apiv1.ResourceRequirements{
+ Requests: apiv1.ResourceList{
+ apiv1.ResourceCPU:
resource.MustParse("100m"),
+ apiv1.ResourceMemory:
resource.MustParse("128Mi"),
+ },
+ Limits: apiv1.ResourceList{
+ apiv1.ResourceCPU:
resource.MustParse("1000m"),
+ apiv1.ResourceMemory:
resource.MustParse("1Gi"),
+ },
+ },
+ valid: true,
+ },
+ {
+ name: "CPU limit less than request",
+ requirements: apiv1.ResourceRequirements{
+ Requests: apiv1.ResourceList{
+ apiv1.ResourceCPU:
resource.MustParse("1000m"),
+ },
+ Limits: apiv1.ResourceList{
+ apiv1.ResourceCPU:
resource.MustParse("500m"),
+ },
+ },
+ valid: false,
+ },
+ {
+ name: "Memory limit less than request",
+ requirements: apiv1.ResourceRequirements{
+ Requests: apiv1.ResourceList{
+ apiv1.ResourceMemory:
resource.MustParse("2Gi"),
+ },
+ Limits: apiv1.ResourceList{
+ apiv1.ResourceMemory:
resource.MustParse("1Gi"),
+ },
+ },
+ valid: false,
+ },
+ {
+ name: "empty resource requirements",
+ requirements: apiv1.ResourceRequirements{},
+ valid: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ err := validateResourceRequirements(tc.requirements)
+ if (err == nil) != tc.valid {
+ t.Errorf("expected valid=%v, got error=%v",
tc.valid, err)
+ }
+ })
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]