Skip to content

Commit febde70

Browse files
committed
Smaller refactoring, add tests
1 parent 16885fc commit febde70

2 files changed

Lines changed: 79 additions & 17 deletions

File tree

internal/pkg/handler/pause_deployment.go

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package handler
33
import (
44
"context"
55
"fmt"
6-
"sync"
76
"time"
87

98
"github.com/sirupsen/logrus"
@@ -15,11 +14,8 @@ import (
1514
"k8s.io/apimachinery/pkg/runtime"
1615
)
1716

18-
// Keeps track of currently active timers for paused deployments
19-
var (
20-
activeTimers = make(map[string]*time.Timer)
21-
timerLock = sync.Mutex{}
22-
)
17+
// Keeps track of currently active timers
18+
var activeTimers = make(map[string]*time.Timer)
2319

2420
// Returns unique key for the activeTimers map
2521
func getTimerKey(namespace, deploymentName string) string {
@@ -98,9 +94,7 @@ func PauseDeployment(deployment *app.Deployment, clients kube.Clients, deploymen
9894

9995
// Check if a timer already exists for this deployment
10096
timerKey := getTimerKey(namespace, deploymentName)
101-
timerLock.Lock()
10297
_, timerExists := activeTimers[timerKey]
103-
timerLock.Unlock()
10498

10599
if !timerExists {
106100
logrus.Warnf("Timer does not exist for already paused deployment '%s' in namespace '%s', creating new one",
@@ -121,17 +115,17 @@ func HandleMissingTimer(deployment *app.Deployment, pauseDuration time.Duration,
121115
deploymentName, namespace, err)
122116
ResumeDeployment(deploymentName, namespace, clients)
123117
} else if pauseStartTime != nil {
124-
elapsedTime := time.Since(*pauseStartTime)
125-
remainingTime := pauseDuration - elapsedTime
118+
elapsedPauseTime := time.Since(*pauseStartTime)
119+
remainingPauseTime := pauseDuration - elapsedPauseTime
126120

127-
if remainingTime <= 0 {
121+
if remainingPauseTime <= 0 {
128122
logrus.Infof("Pause period for deployment '%s' in namespace '%s' has expired. Resuming immediately",
129123
deploymentName, namespace)
130124
ResumeDeployment(deploymentName, namespace, clients)
131125
} else {
132126
logrus.Infof("Creating missing timer for already paused deployment '%s' in namespace '%s' with remaining time %s",
133-
deploymentName, namespace, remainingTime)
134-
CreateResumeTimer(deployment, clients, deploymentName, namespace, remainingTime)
127+
deploymentName, namespace, remainingPauseTime)
128+
CreateResumeTimer(deployment, clients, deploymentName, namespace, remainingPauseTime)
135129
}
136130
}
137131
}
@@ -141,7 +135,6 @@ func CreateResumeTimer(deployment *app.Deployment, clients kube.Clients, deploym
141135
timerKey := getTimerKey(namespace, deploymentName)
142136

143137
// Check if there's an existing timer for this deployment
144-
timerLock.Lock()
145138
if _, exists := activeTimers[timerKey]; exists {
146139
logrus.Debugf("Timer already exists for deployment '%s' in namespace '%s', Skipping creation",
147140
deploymentName, namespace)
@@ -155,7 +148,6 @@ func CreateResumeTimer(deployment *app.Deployment, clients kube.Clients, deploym
155148

156149
// Add the new timer to the map
157150
activeTimers[timerKey] = timer
158-
timerLock.Unlock()
159151

160152
logrus.Debugf("Created pause timer for deployment '%s' in namespace '%s' with duration %s",
161153
deploymentName, namespace, pauseDuration)
@@ -176,13 +168,11 @@ func ResumeDeployment(deploymentName, namespace string, clients kube.Clients) {
176168

177169
// Remove the timer itself
178170
timerKey := getTimerKey(namespace, deploymentName)
179-
timerLock.Lock()
180171
if timer, exists := activeTimers[timerKey]; exists {
181172
timer.Stop()
182173
delete(activeTimers, timerKey)
183174
logrus.Debugf("Removed pause timer for deployment '%s' in namespace '%s'", deploymentName, namespace)
184175
}
185-
timerLock.Unlock()
186176

187177
deployment.Spec.Paused = false
188178
delete(deployment.Annotations, options.PauseDeploymentTimeAnnotation)

internal/pkg/handler/pause_deployment_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
package handler
22

33
import (
4+
"context"
45
"testing"
56
"time"
67

78
"github.com/stakater/Reloader/internal/pkg/options"
9+
"github.com/stakater/Reloader/pkg/kube"
810
"github.com/stretchr/testify/assert"
911
appsv1 "k8s.io/api/apps/v1"
1012
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1113
"k8s.io/apimachinery/pkg/runtime"
14+
testclient "k8s.io/client-go/kubernetes/fake"
1215
)
1316

1417
func TestIsPaused(t *testing.T) {
@@ -253,3 +256,72 @@ func TestParsePauseDuration(t *testing.T) {
253256
})
254257
}
255258
}
259+
260+
func TestHandleMissingTimerSimple(t *testing.T) {
261+
tests := []struct {
262+
name string
263+
deployment *appsv1.Deployment
264+
shouldBePaused bool // Should be unpaused after HandleMissingTimer ?
265+
}{
266+
{
267+
name: "deployment paused by reloader, pause period has expired and no timer",
268+
deployment: &appsv1.Deployment{
269+
ObjectMeta: metav1.ObjectMeta{
270+
Name: "test-deployment",
271+
Annotations: map[string]string{
272+
options.PauseDeploymentTimeAnnotation: time.Now().Add(-6 * time.Minute).Format(time.RFC3339),
273+
options.PauseDeploymentAnnotation: "5m",
274+
},
275+
},
276+
Spec: appsv1.DeploymentSpec{
277+
Paused: true,
278+
},
279+
},
280+
shouldBePaused: false,
281+
},
282+
{
283+
name: "deployment paused by reloader, pause period expires in the future and no timer",
284+
deployment: &appsv1.Deployment{
285+
ObjectMeta: metav1.ObjectMeta{
286+
Name: "test-deployment",
287+
Annotations: map[string]string{
288+
options.PauseDeploymentTimeAnnotation: time.Now().Add(1 * time.Minute).Format(time.RFC3339),
289+
options.PauseDeploymentAnnotation: "5m",
290+
},
291+
},
292+
Spec: appsv1.DeploymentSpec{
293+
Paused: true,
294+
},
295+
},
296+
shouldBePaused: true,
297+
},
298+
}
299+
300+
for _, test := range tests {
301+
t.Run(test.name, func(t *testing.T) {
302+
fakeClient := testclient.NewSimpleClientset()
303+
clients := kube.Clients{
304+
KubernetesClient: fakeClient,
305+
}
306+
307+
fakeClient.AppsV1().Deployments("default").Create(
308+
context.TODO(),
309+
test.deployment,
310+
metav1.CreateOptions{})
311+
312+
pauseDuration, _ := ParsePauseDuration(test.deployment.Annotations[options.PauseDeploymentAnnotation])
313+
HandleMissingTimer(test.deployment, pauseDuration, clients, test.deployment.Name, "default")
314+
315+
updatedDeployment, _ := fakeClient.AppsV1().Deployments("default").Get(context.TODO(), test.deployment.Name, metav1.GetOptions{})
316+
317+
assert.Equal(t, test.shouldBePaused, updatedDeployment.Spec.Paused,
318+
"Deployment should have correct paused state after timer expiration")
319+
320+
if test.shouldBePaused {
321+
pausedAtAnnotationValue := updatedDeployment.Annotations[options.PauseDeploymentTimeAnnotation]
322+
assert.NotEmpty(t, pausedAtAnnotationValue,
323+
"Pause annotation should be present and contain a value when deployment is paused")
324+
}
325+
})
326+
}
327+
}

0 commit comments

Comments
 (0)