Skip to content

Commit 656fb79

Browse files
committed
feat: use label-based selection for workspace type patching
Replace hardcoded workspace type name matching (-org, -acc suffixes) with label-based selection using core.platform-mesh.io/org label. This makes the workspace authorization more flexible and able to handle any number of workspace types per organization. Depends on: platform-mesh/account-operator#118 Signed-off-by: Bastian Echterhölter <bastian.echterhoelter@sap.com> On-behalf-of: @SAP <bastian.echterhoelter@sap.com>
1 parent 4e0929e commit 656fb79

File tree

2 files changed

+69
-145
lines changed

2 files changed

+69
-145
lines changed

internal/subroutine/workspace_authorization.go

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -149,42 +149,38 @@ func (r *workspaceAuthSubroutine) Process(ctx context.Context, instance runtimeo
149149
return reconcile.Result{}, errors.NewOperatorError(fmt.Errorf("failed to create WorkspaceAuthConfiguration resource: %w", err), true, true)
150150
}
151151

152-
err = r.patchWorkspaceType(ctx, r.orgClient, fmt.Sprintf("%s-org", workspaceName), workspaceName)
152+
err = r.patchWorkspaceTypes(ctx, r.orgClient, workspaceName)
153153
if err != nil {
154-
return reconcile.Result{}, errors.NewOperatorError(fmt.Errorf("failed to patch workspace type: %w", err), true, true)
155-
}
156-
157-
err = r.patchWorkspaceType(ctx, r.orgClient, fmt.Sprintf("%s-acc", workspaceName), workspaceName)
158-
if err != nil {
159-
return reconcile.Result{}, errors.NewOperatorError(fmt.Errorf("failed to patch workspace type: %w", err), true, true)
154+
return reconcile.Result{}, errors.NewOperatorError(fmt.Errorf("failed to patch workspace types: %w", err), true, true)
160155
}
161156

162157
return ctrl.Result{}, nil
163158
}
164159

165-
func (r *workspaceAuthSubroutine) patchWorkspaceType(ctx context.Context, cl client.Client, workspaceTypeName, authConfigurationRefName string) error {
166-
wsType := &kcptenancyv1alphav1.WorkspaceType{
167-
ObjectMeta: metav1.ObjectMeta{Name: workspaceTypeName},
168-
}
169-
170-
if err := cl.Get(ctx, client.ObjectKey{Name: workspaceTypeName}, wsType); err != nil {
171-
return fmt.Errorf("failed to get WorkspaceType: %w", err)
160+
func (r *workspaceAuthSubroutine) patchWorkspaceTypes(ctx context.Context, cl client.Client, workspaceName string) error {
161+
wsTypeList := &kcptenancyv1alphav1.WorkspaceTypeList{}
162+
if err := cl.List(ctx, wsTypeList, client.MatchingLabels{"core.platform-mesh.io/org": workspaceName}); err != nil {
163+
return fmt.Errorf("failed to list WorkspaceTypes: %w", err)
172164
}
173165

174166
desiredAuthConfig := []kcptenancyv1alphav1.AuthenticationConfigurationReference{
175-
{Name: authConfigurationRefName},
167+
{Name: workspaceName},
176168
}
177169

178-
if equality.Semantic.DeepEqual(wsType.Spec.AuthenticationConfigurations, desiredAuthConfig) {
179-
log.Debug().Msg(fmt.Sprintf("workspaceType %s already has authentication configuration, skip patching", workspaceTypeName))
180-
return nil
181-
}
170+
for _, wsType := range wsTypeList.Items {
171+
if equality.Semantic.DeepEqual(wsType.Spec.AuthenticationConfigurations, desiredAuthConfig) {
172+
log.Debug().Msg(fmt.Sprintf("workspaceType %s already has authentication configuration, skip patching", wsType.Name))
173+
continue
174+
}
182175

183-
original := wsType.DeepCopy()
184-
wsType.Spec.AuthenticationConfigurations = desiredAuthConfig
176+
original := wsType.DeepCopy()
177+
wsType.Spec.AuthenticationConfigurations = desiredAuthConfig
185178

186-
if err := cl.Patch(ctx, wsType, client.MergeFrom(original)); err != nil {
187-
return fmt.Errorf("failed to patch WorkspaceType: %w", err)
179+
if err := cl.Patch(ctx, &wsType, client.MergeFrom(original)); err != nil {
180+
return fmt.Errorf("failed to patch WorkspaceType %s: %w", wsType.Name, err)
181+
}
182+
log.Debug().Msg(fmt.Sprintf("patched workspaceType %s with authentication configuration", wsType.Name))
188183
}
184+
189185
return nil
190186
}

internal/subroutine/workspace_authorization_test.go

Lines changed: 50 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -75,33 +75,21 @@ func TestWorkspaceAuthSubroutine_Process(t *testing.T) {
7575
return nil
7676
}).Once()
7777

78-
m.EXPECT().Get(mock.Anything, types.NamespacedName{Name: "test-workspace-org"}, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
79-
RunAndReturn(func(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption) error {
80-
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
81-
wt.Name = "test-workspace-org"
82-
return nil
83-
}).Once()
84-
m.EXPECT().Patch(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
85-
RunAndReturn(func(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
86-
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
87-
assert.Equal(t, "test-workspace-org", wt.Name)
88-
assert.Equal(t, "test-workspace", wt.Spec.AuthenticationConfigurations[0].Name)
89-
return nil
90-
}).Once()
91-
92-
m.EXPECT().Get(mock.Anything, types.NamespacedName{Name: "test-workspace-acc"}, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
93-
RunAndReturn(func(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption) error {
94-
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
95-
wt.Name = "test-workspace-acc"
78+
m.EXPECT().List(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceTypeList"), mock.Anything).
79+
RunAndReturn(func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
80+
wtList := list.(*kcptenancyv1alphav1.WorkspaceTypeList)
81+
wtList.Items = []kcptenancyv1alphav1.WorkspaceType{
82+
{ObjectMeta: metav1.ObjectMeta{Name: "test-workspace-org", Labels: map[string]string{"core.platform-mesh.io/org": "test-workspace"}}},
83+
{ObjectMeta: metav1.ObjectMeta{Name: "test-workspace-acc", Labels: map[string]string{"core.platform-mesh.io/org": "test-workspace"}}},
84+
}
9685
return nil
9786
}).Once()
9887
m.EXPECT().Patch(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
9988
RunAndReturn(func(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
10089
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
101-
assert.Equal(t, "test-workspace-acc", wt.Name)
10290
assert.Equal(t, "test-workspace", wt.Spec.AuthenticationConfigurations[0].Name)
10391
return nil
104-
}).Once()
92+
}).Times(2)
10593
},
10694
expectError: false,
10795
expectedResult: ctrl.Result{},
@@ -159,33 +147,21 @@ func TestWorkspaceAuthSubroutine_Process(t *testing.T) {
159147
return nil
160148
}).Once()
161149

162-
m.EXPECT().Get(mock.Anything, types.NamespacedName{Name: "existing-workspace-org"}, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
163-
RunAndReturn(func(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption) error {
164-
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
165-
wt.Name = "existing-workspace-org"
166-
return nil
167-
}).Once()
168-
m.EXPECT().Patch(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
169-
RunAndReturn(func(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
170-
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
171-
assert.Equal(t, "existing-workspace-org", wt.Name)
172-
assert.Equal(t, "existing-workspace", wt.Spec.AuthenticationConfigurations[0].Name)
173-
return nil
174-
}).Once()
175-
176-
m.EXPECT().Get(mock.Anything, types.NamespacedName{Name: "existing-workspace-acc"}, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
177-
RunAndReturn(func(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption) error {
178-
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
179-
wt.Name = "existing-workspace-acc"
150+
m.EXPECT().List(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceTypeList"), mock.Anything).
151+
RunAndReturn(func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
152+
wtList := list.(*kcptenancyv1alphav1.WorkspaceTypeList)
153+
wtList.Items = []kcptenancyv1alphav1.WorkspaceType{
154+
{ObjectMeta: metav1.ObjectMeta{Name: "existing-workspace-org", Labels: map[string]string{"core.platform-mesh.io/org": "existing-workspace"}}},
155+
{ObjectMeta: metav1.ObjectMeta{Name: "existing-workspace-acc", Labels: map[string]string{"core.platform-mesh.io/org": "existing-workspace"}}},
156+
}
180157
return nil
181158
}).Once()
182159
m.EXPECT().Patch(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
183160
RunAndReturn(func(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
184161
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
185-
assert.Equal(t, "existing-workspace-acc", wt.Name)
186162
assert.Equal(t, "existing-workspace", wt.Spec.AuthenticationConfigurations[0].Name)
187163
return nil
188-
}).Once()
164+
}).Times(2)
189165
},
190166
expectError: false,
191167
expectedResult: ctrl.Result{},
@@ -372,33 +348,21 @@ func TestWorkspaceAuthSubroutine_Process(t *testing.T) {
372348
return nil
373349
}).Once()
374350

375-
m.EXPECT().Get(mock.Anything, types.NamespacedName{Name: "single-workspace-org"}, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
376-
RunAndReturn(func(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption) error {
377-
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
378-
wt.Name = "single-workspace-org"
379-
return nil
380-
}).Once()
381-
m.EXPECT().Patch(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
382-
RunAndReturn(func(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
383-
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
384-
assert.Equal(t, "single-workspace-org", wt.Name)
385-
assert.Equal(t, "single-workspace", wt.Spec.AuthenticationConfigurations[0].Name)
386-
return nil
387-
}).Once()
388-
389-
m.EXPECT().Get(mock.Anything, types.NamespacedName{Name: "single-workspace-acc"}, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
390-
RunAndReturn(func(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption) error {
391-
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
392-
wt.Name = "single-workspace-acc"
351+
m.EXPECT().List(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceTypeList"), mock.Anything).
352+
RunAndReturn(func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
353+
wtList := list.(*kcptenancyv1alphav1.WorkspaceTypeList)
354+
wtList.Items = []kcptenancyv1alphav1.WorkspaceType{
355+
{ObjectMeta: metav1.ObjectMeta{Name: "single-workspace-org", Labels: map[string]string{"core.platform-mesh.io/org": "single-workspace"}}},
356+
{ObjectMeta: metav1.ObjectMeta{Name: "single-workspace-acc", Labels: map[string]string{"core.platform-mesh.io/org": "single-workspace"}}},
357+
}
393358
return nil
394359
}).Once()
395360
m.EXPECT().Patch(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
396361
RunAndReturn(func(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
397362
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
398-
assert.Equal(t, "single-workspace-acc", wt.Name)
399363
assert.Equal(t, "single-workspace", wt.Spec.AuthenticationConfigurations[0].Name)
400364
return nil
401-
}).Once()
365+
}).Times(2)
402366
},
403367
expectError: false,
404368
expectedResult: ctrl.Result{},
@@ -457,39 +421,27 @@ func TestWorkspaceAuthSubroutine_Process(t *testing.T) {
457421
return nil
458422
}).Once()
459423

460-
m.EXPECT().Get(mock.Anything, types.NamespacedName{Name: "single-workspace-org"}, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
461-
RunAndReturn(func(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption) error {
462-
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
463-
wt.Name = "single-workspace-org"
464-
return nil
465-
}).Once()
466-
m.EXPECT().Patch(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
467-
RunAndReturn(func(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
468-
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
469-
assert.Equal(t, "single-workspace-org", wt.Name)
470-
assert.Equal(t, "single-workspace", wt.Spec.AuthenticationConfigurations[0].Name)
471-
return nil
472-
}).Once()
473-
474-
m.EXPECT().Get(mock.Anything, types.NamespacedName{Name: "single-workspace-acc"}, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
475-
RunAndReturn(func(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption) error {
476-
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
477-
wt.Name = "single-workspace-acc"
424+
m.EXPECT().List(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceTypeList"), mock.Anything).
425+
RunAndReturn(func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
426+
wtList := list.(*kcptenancyv1alphav1.WorkspaceTypeList)
427+
wtList.Items = []kcptenancyv1alphav1.WorkspaceType{
428+
{ObjectMeta: metav1.ObjectMeta{Name: "single-workspace-org", Labels: map[string]string{"core.platform-mesh.io/org": "single-workspace"}}},
429+
{ObjectMeta: metav1.ObjectMeta{Name: "single-workspace-acc", Labels: map[string]string{"core.platform-mesh.io/org": "single-workspace"}}},
430+
}
478431
return nil
479432
}).Once()
480433
m.EXPECT().Patch(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
481434
RunAndReturn(func(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
482435
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
483-
assert.Equal(t, "single-workspace-acc", wt.Name)
484436
assert.Equal(t, "single-workspace", wt.Spec.AuthenticationConfigurations[0].Name)
485437
return nil
486-
}).Once()
438+
}).Times(2)
487439
},
488440
expectError: false,
489441
expectedResult: ctrl.Result{},
490442
},
491443
{
492-
name: "error - patchWorkspaceType fails for -org",
444+
name: "error - patchWorkspaceTypes fails on list",
493445
logicalCluster: &kcpcorev1alpha1.LogicalCluster{
494446
ObjectMeta: metav1.ObjectMeta{
495447
Annotations: map[string]string{
@@ -522,20 +474,14 @@ func TestWorkspaceAuthSubroutine_Process(t *testing.T) {
522474
Return(apierrors.NewNotFound(kcptenancyv1alphav1.Resource("workspaceauthenticationconfigurations"), "test-workspace")).Once()
523475
m.EXPECT().Create(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceAuthenticationConfiguration"), mock.Anything).Return(nil).Once()
524476

525-
m.EXPECT().Get(mock.Anything, types.NamespacedName{Name: "test-workspace-org"}, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
526-
RunAndReturn(func(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption) error {
527-
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
528-
wt.Name = "test-workspace-org"
529-
return nil
530-
}).Once()
531-
m.EXPECT().Patch(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
532-
Return(errors.New("failed to patch workspace type")).Once()
477+
m.EXPECT().List(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceTypeList"), mock.Anything).
478+
Return(errors.New("failed to list workspace types")).Once()
533479
},
534480
expectError: true,
535481
expectedResult: ctrl.Result{},
536482
},
537483
{
538-
name: "error - patchWorkspaceType fails for -acc",
484+
name: "error - patchWorkspaceTypes fails on patch",
539485
logicalCluster: &kcpcorev1alpha1.LogicalCluster{
540486
ObjectMeta: metav1.ObjectMeta{
541487
Annotations: map[string]string{
@@ -568,18 +514,12 @@ func TestWorkspaceAuthSubroutine_Process(t *testing.T) {
568514
Return(apierrors.NewNotFound(kcptenancyv1alphav1.Resource("workspaceauthenticationconfigurations"), "test-workspace")).Once()
569515
m.EXPECT().Create(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceAuthenticationConfiguration"), mock.Anything).Return(nil).Once()
570516

571-
m.EXPECT().Get(mock.Anything, types.NamespacedName{Name: "test-workspace-org"}, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
572-
RunAndReturn(func(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption) error {
573-
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
574-
wt.Name = "test-workspace-org"
575-
return nil
576-
}).Once()
577-
m.EXPECT().Patch(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).Return(nil).Once()
578-
579-
m.EXPECT().Get(mock.Anything, types.NamespacedName{Name: "test-workspace-acc"}, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
580-
RunAndReturn(func(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption) error {
581-
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
582-
wt.Name = "test-workspace-acc"
517+
m.EXPECT().List(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceTypeList"), mock.Anything).
518+
RunAndReturn(func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
519+
wtList := list.(*kcptenancyv1alphav1.WorkspaceTypeList)
520+
wtList.Items = []kcptenancyv1alphav1.WorkspaceType{
521+
{ObjectMeta: metav1.ObjectMeta{Name: "test-workspace-org", Labels: map[string]string{"core.platform-mesh.io/org": "test-workspace"}}},
522+
}
583523
return nil
584524
}).Once()
585525
m.EXPECT().Patch(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
@@ -663,33 +603,21 @@ func TestWorkspaceAuthSubroutine_Process(t *testing.T) {
663603
return nil
664604
}).Once()
665605

666-
m.EXPECT().Get(mock.Anything, types.NamespacedName{Name: "dev-workspace-org"}, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
667-
RunAndReturn(func(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption) error {
668-
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
669-
wt.Name = "dev-workspace-org"
670-
return nil
671-
}).Once()
672-
m.EXPECT().Patch(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
673-
RunAndReturn(func(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
674-
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
675-
assert.Equal(t, "dev-workspace-org", wt.Name)
676-
assert.Equal(t, "dev-workspace", wt.Spec.AuthenticationConfigurations[0].Name)
677-
return nil
678-
}).Once()
679-
680-
m.EXPECT().Get(mock.Anything, types.NamespacedName{Name: "dev-workspace-acc"}, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
681-
RunAndReturn(func(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption) error {
682-
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
683-
wt.Name = "dev-workspace-acc"
606+
m.EXPECT().List(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceTypeList"), mock.Anything).
607+
RunAndReturn(func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
608+
wtList := list.(*kcptenancyv1alphav1.WorkspaceTypeList)
609+
wtList.Items = []kcptenancyv1alphav1.WorkspaceType{
610+
{ObjectMeta: metav1.ObjectMeta{Name: "dev-workspace-org", Labels: map[string]string{"core.platform-mesh.io/org": "dev-workspace"}}},
611+
{ObjectMeta: metav1.ObjectMeta{Name: "dev-workspace-acc", Labels: map[string]string{"core.platform-mesh.io/org": "dev-workspace"}}},
612+
}
684613
return nil
685614
}).Once()
686615
m.EXPECT().Patch(mock.Anything, mock.AnythingOfType("*v1alpha1.WorkspaceType"), mock.Anything).
687616
RunAndReturn(func(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
688617
wt := obj.(*kcptenancyv1alphav1.WorkspaceType)
689-
assert.Equal(t, "dev-workspace-acc", wt.Name)
690618
assert.Equal(t, "dev-workspace", wt.Spec.AuthenticationConfigurations[0].Name)
691619
return nil
692-
}).Once()
620+
}).Times(2)
693621
},
694622
expectError: false,
695623
expectedResult: ctrl.Result{},

0 commit comments

Comments
 (0)