@@ -56,8 +56,11 @@ type testTiProxyHealthServer struct {
5656 mu sync.Mutex
5757 healthStatus int
5858 markUnhealthyStatus int
59+ metricsStatus int
60+ connectionCount int
5961 healthCalls int
6062 markUnhealthyCalls int
63+ metricsCalls int
6164}
6265
6366func newTestTiProxyHealthServer (t * testing.T , healthStatus , markUnhealthyStatus int ) * testTiProxyHealthServer {
@@ -66,6 +69,8 @@ func newTestTiProxyHealthServer(t *testing.T, healthStatus, markUnhealthyStatus
6669 s := & testTiProxyHealthServer {
6770 healthStatus : healthStatus ,
6871 markUnhealthyStatus : markUnhealthyStatus ,
72+ metricsStatus : http .StatusOK ,
73+ connectionCount : 1 ,
6974 }
7075
7176 mux := http .NewServeMux ()
@@ -84,13 +89,35 @@ func newTestTiProxyHealthServer(t *testing.T, healthStatus, markUnhealthyStatus
8489 w .WriteHeader (s .healthStatus )
8590 _ , _ = w .Write ([]byte (`{"config_checksum":1}` ))
8691 })
92+ mux .HandleFunc ("/metrics" , func (w http.ResponseWriter , r * http.Request ) {
93+ s .mu .Lock ()
94+ defer s .mu .Unlock ()
95+ s .metricsCalls ++
96+ w .WriteHeader (s .metricsStatus )
97+ _ , _ = w .Write ([]byte (`# HELP tiproxy_server_connections Number of connections.
98+ # TYPE tiproxy_server_connections gauge
99+ tiproxy_server_connections ` + strconv .Itoa (s .connectionCount ) + `
100+ ` ))
101+ })
87102 server := httptest .NewServer (mux )
88103 t .Cleanup (server .Close )
89104
90105 s .server = server
91106 return s
92107}
93108
109+ func (s * testTiProxyHealthServer ) setConnectionCount (connectionCount int ) {
110+ s .mu .Lock ()
111+ defer s .mu .Unlock ()
112+ s .connectionCount = connectionCount
113+ }
114+
115+ func (s * testTiProxyHealthServer ) setMetricsStatus (status int ) {
116+ s .mu .Lock ()
117+ defer s .mu .Unlock ()
118+ s .metricsStatus = status
119+ }
120+
94121func (s * testTiProxyHealthServer ) port (t * testing.T ) int32 {
95122 t .Helper ()
96123 u , err := url .Parse (s .server .URL )
@@ -107,6 +134,12 @@ func (s *testTiProxyHealthServer) counts() (health, markUnhealthy int) {
107134 return s .healthCalls , s .markUnhealthyCalls
108135}
109136
137+ func (s * testTiProxyHealthServer ) metricsCount () int {
138+ s .mu .Lock ()
139+ defer s .mu .Unlock ()
140+ return s .metricsCalls
141+ }
142+
110143func runDrainPodForDeleteTask (t * testing.T , ctx context.Context , s State , c client.Client ) (task.Result , bool ) {
111144 t .Helper ()
112145
@@ -261,6 +294,55 @@ func TestTaskDrainPodForDeleteWaitForDeleteDelayAfterGracefulShutdownStarted(t *
261294 assert .True (t , actual .GetDeletionTimestamp ().IsZero ())
262295}
263296
297+ func TestTaskDrainPodForDeleteDeletePodWhenConnectionsDropToZero (t * testing.T ) {
298+ t .Parallel ()
299+
300+ ctx := context .Background ()
301+ server := newTestTiProxyHealthServer (t , http .StatusBadGateway , http .StatusOK )
302+ server .setConnectionCount (0 )
303+ cluster := localTestCluster ()
304+ tiproxy := deletingTiProxyWithAPIAddress ("3600" , server .port (t ))
305+ pod := fakePod (cluster , tiproxy )
306+ pod .Annotations = map [string ]string {
307+ v1alpha1 .AnnoKeyTiProxyGracefulShutdownBeginTime : time .Now ().Add (- 10 * time .Second ).Format (time .RFC3339Nano ),
308+ }
309+
310+ fc := client .NewFakeClient (cluster , tiproxy , pod )
311+ res , done := runDrainPodForDeleteTask (t , ctx , & state {cluster : cluster , tiproxy : tiproxy }, fc )
312+
313+ assert .Equal (t , task .SRetry .String (), res .Status ().String ())
314+ assert .False (t , done )
315+ assert .Equal (t , 1 , server .metricsCount ())
316+
317+ err := fc .Get (ctx , client .ObjectKeyFromObject (pod ), & corev1.Pod {})
318+ assert .True (t , apierrors .IsNotFound (err ))
319+ }
320+
321+ func TestTaskDrainPodForDeleteContinueDeleteDelayWhenConnectionMetricFails (t * testing.T ) {
322+ t .Parallel ()
323+
324+ ctx := context .Background ()
325+ server := newTestTiProxyHealthServer (t , http .StatusBadGateway , http .StatusOK )
326+ server .setMetricsStatus (http .StatusInternalServerError )
327+ cluster := localTestCluster ()
328+ tiproxy := deletingTiProxyWithAPIAddress ("3600" , server .port (t ))
329+ pod := fakePod (cluster , tiproxy )
330+ pod .Annotations = map [string ]string {
331+ v1alpha1 .AnnoKeyTiProxyGracefulShutdownBeginTime : time .Now ().Add (- 10 * time .Second ).Format (time .RFC3339Nano ),
332+ }
333+
334+ fc := client .NewFakeClient (cluster , tiproxy , pod )
335+ res , done := runDrainPodForDeleteTask (t , ctx , & state {cluster : cluster , tiproxy : tiproxy }, fc )
336+
337+ assert .Equal (t , task .SRetry .String (), res .Status ().String ())
338+ assert .False (t , done )
339+ assert .Equal (t , 1 , server .metricsCount ())
340+
341+ actual := & corev1.Pod {}
342+ require .NoError (t , fc .Get (ctx , client .ObjectKeyFromObject (pod ), actual ))
343+ assert .True (t , actual .GetDeletionTimestamp ().IsZero ())
344+ }
345+
264346func TestTaskDrainPodForDeleteDeletePodWithoutExtendingGracePeriodAfterDelay (t * testing.T ) {
265347 t .Parallel ()
266348
0 commit comments