Skip to content

Commit 3cd6e3e

Browse files
authored
Refactor job name handling and phase check (#31)
* refactor: Simplify phase check using slices.Contains and update job name handling * refactor: Remove duplicate import of slices package
1 parent 58bc008 commit 3cd6e3e

File tree

6 files changed

+107
-89
lines changed

6 files changed

+107
-89
lines changed

internal/handler/operation.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package handler
33
import (
44
"context"
55
"fmt"
6+
"slices"
67
"time"
78

89
"github.com/Azure/operation-cache-controller/internal/utils/reconciler"
@@ -57,13 +58,7 @@ func NewOperationHandler(ctx context.Context, operation *v1alpha1.Operation, log
5758
}
5859

5960
func (o *OperationHandler) phaseIn(phases ...string) bool {
60-
61-
for _, phase := range phases {
62-
if phase == o.operation.Status.Phase {
63-
return true
64-
}
65-
}
66-
return false
61+
return slices.Contains(phases, o.operation.Status.Phase)
6762
}
6863

6964
func (o *OperationHandler) EnsureNotExpired(ctx context.Context) (reconciler.OperationResult, error) {

internal/handler/operation_test.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,17 @@ var (
4242
},
4343
},
4444
},
45+
Status: v1alpha1.OperationStatus{
46+
OperationID: "test-operation",
47+
},
4548
}
4649
emptyAppDeploymentList = &v1alpha1.AppDeploymentList{}
4750

4851
validAppDeploymentList = &v1alpha1.AppDeploymentList{
4952
Items: []v1alpha1.AppDeployment{
5053
{
5154
ObjectMeta: metav1.ObjectMeta{
52-
Name: "test-app1",
55+
Name: "test-operation-test-app1",
5356
Namespace: "default",
5457
},
5558
Spec: v1alpha1.AppDeploymentSpec{
@@ -64,7 +67,7 @@ var (
6467
},
6568
{
6669
ObjectMeta: metav1.ObjectMeta{
67-
Name: "test-app2",
70+
Name: "test-operation-test-app2",
6871
Namespace: "default",
6972
},
7073
Spec: v1alpha1.AppDeploymentSpec{
@@ -83,7 +86,7 @@ var (
8386
Items: []v1alpha1.AppDeployment{
8487
{
8588
ObjectMeta: metav1.ObjectMeta{
86-
Name: "test-app2",
89+
Name: "test-operation-test-app2",
8790
Namespace: "default",
8891
},
8992
Spec: v1alpha1.AppDeploymentSpec{
@@ -115,7 +118,7 @@ var (
115118
},
116119
{
117120
ObjectMeta: metav1.ObjectMeta{
118-
Name: "test-app3",
121+
Name: "test-operation-test-app3",
119122
Namespace: "default",
120123
},
121124
Spec: v1alpha1.AppDeploymentSpec{
@@ -277,14 +280,14 @@ func TestOperationHandler_EnsureAllAppsAreReady(t *testing.T) {
277280
operation.Status.Phase = v1alpha1.OperationPhaseReconciling
278281

279282
appList := emptyAppDeploymentList.DeepCopy()
280-
mockClient.EXPECT().List(ctx, appList, gomock.Any()).DoAndReturn(func(ctx context.Context, list *v1alpha1.AppDeploymentList, opts ...interface{}) error {
283+
mockClient.EXPECT().List(ctx, appList, gomock.Any()).DoAndReturn(func(ctx context.Context, list *v1alpha1.AppDeploymentList, opts ...any) error {
281284
*list = *changedValidAppDeploymentList
282285
return nil
283286
})
284287
scheme := runtime.NewScheme()
285288
utilruntime.Must(v1alpha1.AddToScheme(scheme))
286289
mockClient.EXPECT().Scheme().Return(scheme).AnyTimes()
287-
mockClient.EXPECT().Get(ctx, gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, key client.ObjectKey, obj runtime.Object, opt ...interface{}) error {
290+
mockClient.EXPECT().Get(ctx, gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, key client.ObjectKey, obj runtime.Object, opt ...any) error {
288291
*obj.(*v1alpha1.AppDeployment) = v1alpha1.AppDeployment{}
289292
return nil
290293
}).AnyTimes()

internal/handler/requirement.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ func (r *RequirementHandler) EnsureOperationReady(ctx context.Context) (reconcil
286286
}
287287
if r.rqutils.IsCacheMissed(r.requirement) {
288288
r.logger.V(1).Info("cache missed, creating operation")
289-
r.requirement.Status.OperationName = r.requirement.Name + "-" + "operation"
289+
r.requirement.Status.OperationName = r.requirement.Name // reset operation name to requirement name
290290
}
291291
// check operation status
292292
if op, err := r.getOperation(); err == nil {

internal/utils/controller/appdeployment_job.go

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,20 @@ import (
1313
const (
1414
JobTypeProvision = "provision"
1515
JobTypeTeardown = "teardown"
16+
JobNamePattern = "%s-%s-%s" // jobType-appName-operationId
1617
)
1718

1819
var (
1920
backOffLimit int32 = 10
2021
ttlSecondsAfterFinished int32 = 3600
2122
MaxAppNameLength int = 36
22-
MaxOpIdLength int = 18
2323
)
2424

25-
func validJName(appName, operationId, jobType string) string {
26-
if len(appName) > MaxAppNameLength {
27-
appName = appName[:MaxAppNameLength]
28-
}
29-
if len(operationId) > MaxOpIdLength {
30-
operationId = operationId[:MaxOpIdLength]
25+
func validJobName(appName, jobType string) string {
26+
originName := jobType + "-" + appName
27+
if len(originName) > MaxResourceNameLength {
28+
return originName[:MaxResourceNameLength]
3129
}
32-
originName := jobType + "-" + appName + "-" + operationId
3330
return originName
3431
}
3532

@@ -42,16 +39,16 @@ func TeardownJobFromAppDeploymentSpec(appDeployment *v1alpha1.AppDeployment) *ba
4239
}
4340

4441
func GetProvisionJobName(appDeployment *v1alpha1.AppDeployment) string {
45-
return validJName(appDeployment.Name, appDeployment.Spec.OpId, JobTypeProvision)
42+
return validJobName(appDeployment.Name, JobTypeProvision)
4643
}
4744

4845
func GetTeardownJobName(appDeployment *v1alpha1.AppDeployment) string {
49-
return validJName(appDeployment.Name, appDeployment.Spec.OpId, JobTypeTeardown)
46+
return validJobName(appDeployment.Name, JobTypeTeardown)
5047
}
5148

5249
func jobFromAppDeploymentSpec(appDeployment *v1alpha1.AppDeployment, suffix string) *batchv1.Job {
5350
ops := jobOptions{
54-
name: validJName(appDeployment.Name, appDeployment.Spec.OpId, suffix),
51+
name: validJobName(appDeployment.Name, suffix),
5552
namespace: appDeployment.Namespace,
5653
labels: appDeployment.Labels,
5754
jobSpec: appDeployment.Spec.Provision,
@@ -117,14 +114,16 @@ func CheckJobStatus(ctx context.Context, job *batchv1.Job) JobStatus {
117114
}
118115

119116
func OperationScopedAppDeployment(appName, opId string) string {
117+
originalName := opId + "-" + appName
118+
if len(originalName) < MaxResourceNameLength {
119+
return originalName
120+
}
120121
if len(appName) > MaxAppNameLength {
121122
appName = appName[:MaxAppNameLength]
122123
}
123-
if len(opId) > MaxOpIdLength {
124-
opId = opId[:MaxOpIdLength]
125-
}
126-
if opId == "" {
127-
return appName
124+
resisualLength := MaxResourceNameLength - len(appName) - 1 // -1 for the hyphen
125+
if len(opId) > resisualLength {
126+
opId = opId[:resisualLength]
128127
}
129128
return opId + "-" + appName
130129
}

internal/utils/controller/appdeployment_job_test.go

Lines changed: 78 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package controller
22

33
import (
44
"context"
5+
"strings"
56
"testing"
67

78
"github.com/Azure/operation-cache-controller/api/v1alpha1"
@@ -94,21 +95,18 @@ func TestGetProvisionJobName(t *testing.T) {
9495
}{
9596
{
9697
name: "Valid app name and operation ID",
97-
appName: "my-app",
98-
opId: "op123",
99-
expected: "provision-my-app-op123",
98+
appName: "op123-my-app",
99+
expected: "provision-op123-my-app",
100100
},
101101
{
102102
name: "App name exceeds max length",
103-
appName: "a-very-long-application-name-exceeding-limit",
104-
opId: "op123",
105-
expected: "provision-a-very-long-application-name-exceedi-op123",
103+
appName: "op1234567890-a-very-long-application-name-exceeding-limit",
104+
expected: "provision-op1234567890-a-very-long-application-name-exceeding-l",
106105
},
107106
{
108107
name: "Operation ID exceeds max length",
109-
appName: "my-app",
110-
opId: "operation-id-exceeding-length",
111-
expected: "provision-my-app-operation-id-excee",
108+
appName: "operationid1234567890123456789012345678901234567890-my-application",
109+
expected: "provision-operationid1234567890123456789012345678901234567890-m",
112110
},
113111
}
114112

@@ -118,9 +116,6 @@ func TestGetProvisionJobName(t *testing.T) {
118116
ObjectMeta: metav1.ObjectMeta{
119117
Name: tt.appName,
120118
},
121-
Spec: v1alpha1.AppDeploymentSpec{
122-
OpId: tt.opId,
123-
},
124119
}
125120
res := GetProvisionJobName(appDeployment)
126121
assert.Equal(t, tt.expected, res)
@@ -138,20 +133,17 @@ func TestGetTeardownJobName(t *testing.T) {
138133
{
139134
name: "Valid app name and operation ID",
140135
appName: "my-app",
141-
opId: "op123",
142-
expected: "teardown-my-app-op123",
136+
expected: "teardown-my-app",
143137
},
144138
{
145139
name: "App name exceeds max length",
146-
appName: "a-very-long-application-name-exceeding-limit",
147-
opId: "op123",
148-
expected: "teardown-a-very-long-application-name-exceedi-op123",
140+
appName: "op1234567890-a-very-long-application-name-exceeding-limit",
141+
expected: "teardown-op1234567890-a-very-long-application-name-exceeding-li",
149142
},
150143
{
151144
name: "Operation ID exceeds max length",
152-
appName: "my-app",
153-
opId: "operation-id-exceeding-length",
154-
expected: "teardown-my-app-operation-id-excee",
145+
appName: "operationid1234567890123456789012345678901234567890-my-application",
146+
expected: "teardown-operationid1234567890123456789012345678901234567890-my",
155147
},
156148
}
157149

@@ -161,9 +153,6 @@ func TestGetTeardownJobName(t *testing.T) {
161153
ObjectMeta: metav1.ObjectMeta{
162154
Name: tt.appName,
163155
},
164-
Spec: v1alpha1.AppDeploymentSpec{
165-
OpId: tt.opId,
166-
},
167156
}
168157
res := GetTeardownJobName(appDeployment)
169158
assert.Equal(t, tt.expected, res)
@@ -172,59 +161,91 @@ func TestGetTeardownJobName(t *testing.T) {
172161
}
173162
func TestOperationScopedAppDeployment(t *testing.T) {
174163
tests := []struct {
175-
name string
176-
appName string
177-
opId string
178-
expected string
164+
name string
165+
appName string
166+
opId string
167+
want string
179168
}{
180169
{
181-
name: "Both appName and opId within limits",
182-
appName: "my-app",
183-
opId: "op123",
184-
expected: "op123-my-app",
170+
name: "normal case - combined length within limit",
171+
appName: "my-app",
172+
opId: "op-12345",
173+
want: "op-12345-my-app",
185174
},
186175
{
187-
name: "appName exceeds max length",
188-
appName: "a-very-long-application-name-exceeding-limit",
189-
opId: "op123",
190-
expected: "op123-a-very-long-application-name-exceedi",
176+
name: "app name truncated when too long",
177+
appName: strings.Repeat("a", 60), // 60 chars, exceeds MaxAppNameLength
178+
opId: "op-12345",
179+
want: "op-12345-" + strings.Repeat("a", MaxAppNameLength),
191180
},
192181
{
193-
name: "opId exceeds max length",
194-
appName: "my-app",
195-
opId: "operation-id-exceeding-length",
196-
expected: "operation-id-excee-my-app",
182+
name: "operation ID truncated when combined length exceeds limit",
183+
appName: strings.Repeat("a", MaxAppNameLength),
184+
opId: strings.Repeat("b", 30), // This will exceed when combined
185+
want: strings.Repeat("b", MaxResourceNameLength-MaxAppNameLength-1) + "-" + strings.Repeat("a", MaxAppNameLength),
197186
},
198187
{
199-
name: "Both appName and opId exceed max length",
200-
appName: "another-very-long-application-name-exceeding-limit",
201-
opId: "another-operation-id-exceeding-length",
202-
expected: "another-operation--another-very-long-application-name-e",
188+
name: "both truncated for very long inputs",
189+
appName: strings.Repeat("a", 100),
190+
opId: strings.Repeat("b", 100),
191+
want: strings.Repeat("b", MaxResourceNameLength-MaxAppNameLength-1) + "-" + strings.Repeat("a", MaxAppNameLength),
203192
},
204193
{
205-
name: "Empty appName and opId",
206-
appName: "",
207-
opId: "",
208-
expected: "",
194+
name: "empty app name",
195+
appName: "",
196+
opId: "op-12345",
197+
want: "op-12345-",
209198
},
210199
{
211-
name: "Empty appName",
212-
appName: "",
213-
opId: "op123",
214-
expected: "op123-",
200+
name: "empty operation ID",
201+
appName: "my-app",
202+
opId: "",
203+
want: "-my-app",
215204
},
216205
{
217-
name: "Empty opId",
218-
appName: "my-app",
219-
opId: "",
220-
expected: "my-app",
206+
name: "both empty",
207+
appName: "",
208+
opId: "",
209+
want: "-",
210+
},
211+
{
212+
name: "exact max length",
213+
appName: "app",
214+
opId: strings.Repeat("x", MaxResourceNameLength-4), // -4 for "-app"
215+
want: strings.Repeat("x", MaxResourceNameLength-4) + "-app",
221216
},
222217
}
223218

224219
for _, tt := range tests {
225220
t.Run(tt.name, func(t *testing.T) {
226-
res := OperationScopedAppDeployment(tt.appName, tt.opId)
227-
assert.Equal(t, tt.expected, res)
221+
got := OperationScopedAppDeployment(tt.appName, tt.opId)
222+
assert.Equal(t, tt.want, got, "OperationScopedAppDeployment() mismatch for %s", tt.name)
228223
})
229224
}
230225
}
226+
227+
func TestOperationScopedAppDeployment_LengthConstraints(t *testing.T) {
228+
// Test that the function always respects the maximum length constraint
229+
testCases := []struct {
230+
appNameLen int
231+
opIdLen int
232+
}{
233+
{10, 10},
234+
{MaxAppNameLength, 10},
235+
{50, 50},
236+
{100, 100},
237+
{MaxResourceNameLength, MaxResourceNameLength},
238+
}
239+
240+
for _, tc := range testCases {
241+
appName := strings.Repeat("a", tc.appNameLen)
242+
opId := strings.Repeat("b", tc.opIdLen)
243+
244+
result := OperationScopedAppDeployment(appName, opId)
245+
246+
if len(result) > MaxResourceNameLength {
247+
t.Errorf("Result length %d exceeds MaxResourceNameLength %d for appName length %d and opId length %d",
248+
len(result), MaxResourceNameLength, tc.appNameLen, tc.opIdLen)
249+
}
250+
}
251+
}

internal/utils/controller/const.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ package controller
22

33
const (
44
LabelNameCacheKey = "operation-cache-controller.azure.github.com/cache-key"
5-
)
65

7-
const (
86
AnnotationNameCacheMode = "operation-cache-controller.azure.github.com/cache-mode"
97
AnnotationNameCacheKey = "operation-cache-controller.azure.github.com/cache-key"
108
AnnotationValueTrue = "true"
119
AnnotationValueFalse = "false"
10+
11+
MaxResourceNameLength int = 63
1212
)

0 commit comments

Comments
 (0)