-
Notifications
You must be signed in to change notification settings - Fork 271
Expand file tree
/
Copy pathcontroller_test.go
More file actions
141 lines (132 loc) · 3.47 KB
/
controller_test.go
File metadata and controls
141 lines (132 loc) · 3.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package service
import (
"testing"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
servicehelper "k8s.io/cloud-provider/service/helpers"
)
// TestNeedsCleanup verifies that services with deletionTimestamp set are
// correctly identified as needing cleanup, regardless of finalizer state.
// This prevents a race condition where node updates trigger reconciliation
// after the finalizer is removed but before the service is deleted from etcd.
func TestNeedsCleanup(t *testing.T) {
now := metav1.Now()
testCases := []struct {
name string
service *v1.Service
expected bool
}{
{
name: "service with deletionTimestamp and finalizer should need cleanup",
service: &v1.Service{
ObjectMeta: metav1.ObjectMeta{
DeletionTimestamp: &now,
Finalizers: []string{servicehelper.LoadBalancerCleanupFinalizer},
},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeLoadBalancer,
},
},
expected: true,
},
{
name: "service with deletionTimestamp but no finalizer should need cleanup",
service: &v1.Service{
ObjectMeta: metav1.ObjectMeta{
DeletionTimestamp: &now,
Finalizers: []string{},
},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeLoadBalancer,
},
},
expected: true,
},
{
name: "service without deletionTimestamp and without finalizer should not need cleanup",
service: &v1.Service{
ObjectMeta: metav1.ObjectMeta{
Finalizers: []string{},
},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeLoadBalancer,
},
},
expected: false,
},
{
name: "service without deletionTimestamp but with finalizer should not need cleanup",
service: &v1.Service{
ObjectMeta: metav1.ObjectMeta{
Finalizers: []string{servicehelper.LoadBalancerCleanupFinalizer},
},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeLoadBalancer,
},
},
expected: false,
},
{
name: "non-LoadBalancer service with finalizer should need cleanup",
service: &v1.Service{
ObjectMeta: metav1.ObjectMeta{
Finalizers: []string{servicehelper.LoadBalancerCleanupFinalizer},
},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeClusterIP,
},
},
expected: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := needsCleanup(tc.service)
if result != tc.expected {
t.Errorf("needsCleanup() = %v, expected %v", result, tc.expected)
}
})
}
}
// TestNodeSyncService_DeletionTimestamp verifies that nodeSyncService returns
// success (false) without attempting to sync when a service has deletionTimestamp set.
func TestNodeSyncService_DeletionTimestamp(t *testing.T) {
now := metav1.Now()
testCases := []struct {
name string
service *v1.Service
}{
{
name: "nil service should return success",
service: nil,
},
{
name: "service with deletionTimestamp should return success without syncing",
service: &v1.Service{
ObjectMeta: metav1.ObjectMeta{
DeletionTimestamp: &now,
},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeLoadBalancer,
},
},
},
{
name: "non-LoadBalancer service should return success",
service: &v1.Service{
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeClusterIP,
},
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
c := &Controller{}
result := c.nodeSyncService(tc.service)
if result != false {
t.Errorf("nodeSyncService() returned needRetry=true, expected success (false)")
}
})
}
}