@@ -20,6 +20,7 @@ import (
2020 "testing"
2121
2222 dwv2 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
23+ "github.com/devfile/devworkspace-operator/controllers/controller/devworkspacerouting/solvers"
2324 "github.com/stretchr/testify/assert"
2425 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2526 "k8s.io/apimachinery/pkg/runtime"
@@ -43,151 +44,115 @@ func loadObjectFromFile(objName string, obj client.Object, filename string) erro
4344 return nil
4445}
4546
47+ func setupWorkspace (t * testing.T , name , uid , namespace string ) * dwv2.DevWorkspace {
48+ workspace := & dwv2.DevWorkspace {}
49+ err := loadObjectFromFile (name , workspace , "test-devworkspace.yaml" )
50+ assert .NoError (t , err , "Failed to load workspace" )
51+ workspace .SetUID (types .UID (uid ))
52+ workspace .SetNamespace (namespace )
53+ return workspace
54+ }
55+
4656func TestValidateEndpoints (t * testing.T ) {
4757 scheme := runtime .NewScheme ()
4858 _ = dwv2 .AddToScheme (scheme )
4959
5060 t .Run ("Conflict in same namespace" , func (t * testing.T ) {
5161 // Workspace with a discoverable endpoint in namespace "test-namespace"
52- workspace := & dwv2.DevWorkspace {}
53- err := loadObjectFromFile ("workspace-1" , workspace , "test-devworkspace.yaml" )
54- assert .NoError (t , err , "Failed to load test workspace" )
55- workspace .SetUID (types .UID ("uid-1" ))
56- workspace .SetNamespace ("test-namespace" )
62+ workspace := setupWorkspace (t , "workspace-1" , "uid-1" , "test-namespace" )
5763
5864 // Another workspace with a conflicting discoverable endpoint in the SAME namespace
59- otherWorkspaceSameNS := & dwv2.DevWorkspace {}
60- err = loadObjectFromFile ("workspace-2" , otherWorkspaceSameNS , "test-devworkspace.yaml" )
61- assert .NoError (t , err , "Failed to load other test workspace" )
62- otherWorkspaceSameNS .SetUID (types .UID ("uid-2" ))
63- otherWorkspaceSameNS .SetNamespace ("test-namespace" )
65+ otherWorkspaceSameNS := setupWorkspace (t , "workspace-2" , "uid-2" , "test-namespace" )
6466
6567 // Test for conflict in same namespace
6668 fakeClient := fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (otherWorkspaceSameNS ).Build ()
6769 handler := & WebhookHandler {Client : fakeClient }
68- err = handler .validateEndpoints (context .TODO (), workspace )
70+ err : = handler .validateEndpoints (context .TODO (), workspace )
6971 assert .Error (t , err , "Expected a conflict error for workspaces in the same namespace" )
70- assert .Contains (t , err .Error (), "already in use by workspace" )
71- assert .Contains (t , err .Error (), "test-endpoint" )
72+
73+ var conflictErr * solvers.ServiceConflictError
74+ assert .ErrorAs (t , err , & conflictErr , "Error should be a ServiceConflictError" )
75+ assert .Equal (t , "test-endpoint" , conflictErr .EndpointName , "Conflict should be on 'test-endpoint'" )
76+ assert .Equal (t , "workspace-2" , conflictErr .WorkspaceName , "Conflict should reference 'workspace-2'" )
7277 })
7378
7479 t .Run ("No conflict in different namespace" , func (t * testing.T ) {
7580 // Workspace in "test-namespace"
76- workspace := & dwv2.DevWorkspace {}
77- err := loadObjectFromFile ("workspace-1" , workspace , "test-devworkspace.yaml" )
78- assert .NoError (t , err , "Failed to load test workspace" )
79- workspace .SetUID (types .UID ("uid-1" ))
80- workspace .SetNamespace ("test-namespace" )
81+ workspace := setupWorkspace (t , "workspace-1" , "uid-1" , "test-namespace" )
8182
8283 // Another workspace with the same endpoint name but in a DIFFERENT namespace
83- otherWorkspaceDiffNS := & dwv2.DevWorkspace {}
84- err = loadObjectFromFile ("workspace-3" , otherWorkspaceDiffNS , "test-devworkspace.yaml" )
85- assert .NoError (t , err , "Failed to load third test workspace" )
86- otherWorkspaceDiffNS .SetUID (types .UID ("uid-3" ))
87- otherWorkspaceDiffNS .SetNamespace ("other-namespace" )
84+ otherWorkspaceDiffNS := setupWorkspace (t , "workspace-3" , "uid-3" , "other-namespace" )
8885
8986 // Test no conflict in different namespace (workspace only queries its own namespace)
9087 fakeClient := fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (otherWorkspaceDiffNS ).Build ()
9188 handler := & WebhookHandler {Client : fakeClient }
92- err = handler .validateEndpoints (context .TODO (), workspace )
89+ err : = handler .validateEndpoints (context .TODO (), workspace )
9390 assert .NoError (t , err , "Did not expect an error for workspaces in different namespaces" )
9491 })
9592
9693 t .Run ("No conflict when endpoint name is different" , func (t * testing.T ) {
97- workspace := & dwv2.DevWorkspace {}
98- err := loadObjectFromFile ("workspace-1" , workspace , "test-devworkspace.yaml" )
99- assert .NoError (t , err , "Failed to load test workspace" )
100- workspace .SetUID (types .UID ("uid-1" ))
101- workspace .SetNamespace ("test-namespace" )
94+ workspace := setupWorkspace (t , "workspace-1" , "uid-1" , "test-namespace" )
10295 workspace .Spec .Template .Components [0 ].Container .Endpoints [0 ].Name = "new-endpoint"
10396
104- otherWorkspace := & dwv2.DevWorkspace {}
105- err = loadObjectFromFile ("workspace-2" , otherWorkspace , "test-devworkspace.yaml" )
106- assert .NoError (t , err , "Failed to load other test workspace" )
107- otherWorkspace .SetUID (types .UID ("uid-2" ))
108- otherWorkspace .SetNamespace ("test-namespace" )
97+ otherWorkspace := setupWorkspace (t , "workspace-2" , "uid-2" , "test-namespace" )
10998
11099 fakeClient := fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (otherWorkspace ).Build ()
111100 handler := & WebhookHandler {Client : fakeClient }
112- err = handler .validateEndpoints (context .TODO (), workspace )
101+ err : = handler .validateEndpoints (context .TODO (), workspace )
113102 assert .NoError (t , err , "Did not expect an error for different endpoint names" )
114103 })
115104
116105 t .Run ("Conflict detected even when workspace is being deleted" , func (t * testing.T ) {
117- workspace := & dwv2.DevWorkspace {}
118- err := loadObjectFromFile ("workspace-1" , workspace , "test-devworkspace.yaml" )
119- assert .NoError (t , err , "Failed to load test workspace" )
120- workspace .SetUID (types .UID ("uid-1" ))
121- workspace .SetNamespace ("test-namespace" )
106+ workspace := setupWorkspace (t , "workspace-1" , "uid-1" , "test-namespace" )
122107
123108 // Workspace being deleted with same endpoint name
124- deletingWorkspace := & dwv2.DevWorkspace {}
125- err = loadObjectFromFile ("workspace-deleting" , deletingWorkspace , "test-devworkspace.yaml" )
126- assert .NoError (t , err , "Failed to load deleting workspace" )
127- deletingWorkspace .SetUID (types .UID ("uid-deleting" ))
128- deletingWorkspace .SetNamespace ("test-namespace" )
109+ deletingWorkspace := setupWorkspace (t , "workspace-deleting" , "uid-deleting" , "test-namespace" )
129110 now := metav1 .Now ()
130111 deletingWorkspace .DeletionTimestamp = & now
131112 // Add finalizer - required by fake client when setting deletionTimestamp
132113 deletingWorkspace .Finalizers = []string {"test-finalizer" }
133114
134115 fakeClient := fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (deletingWorkspace ).Build ()
135116 handler := & WebhookHandler {Client : fakeClient }
136- err = handler .validateEndpoints (context .TODO (), workspace )
117+ err : = handler .validateEndpoints (context .TODO (), workspace )
137118 assert .Error (t , err , "Should detect conflict even with workspace being deleted" )
138- assert .Contains (t , err .Error (), "workspace-deleting" )
119+
120+ var conflictErr * solvers.ServiceConflictError
121+ assert .ErrorAs (t , err , & conflictErr , "Error should be a ServiceConflictError" )
122+ assert .Equal (t , "test-endpoint" , conflictErr .EndpointName , "Conflict should be on 'test-endpoint'" )
123+ assert .Equal (t , "workspace-deleting" , conflictErr .WorkspaceName , "Conflict should reference 'workspace-deleting'" )
139124 })
140125
141126 t .Run ("No conflict when workspace has no discoverable endpoints" , func (t * testing.T ) {
142- workspace := & dwv2.DevWorkspace {}
143- err := loadObjectFromFile ("workspace-1" , workspace , "test-devworkspace.yaml" )
144- assert .NoError (t , err , "Failed to load test workspace" )
145- workspace .SetUID (types .UID ("uid-1" ))
146- workspace .SetNamespace ("test-namespace" )
127+ workspace := setupWorkspace (t , "workspace-1" , "uid-1" , "test-namespace" )
147128 // Remove discoverable attribute
148129 workspace .Spec .Template .Components [0 ].Container .Endpoints [0 ].Attributes = nil
149130
150- otherWorkspace := & dwv2.DevWorkspace {}
151- err = loadObjectFromFile ("workspace-2" , otherWorkspace , "test-devworkspace.yaml" )
152- assert .NoError (t , err , "Failed to load other test workspace" )
153- otherWorkspace .SetUID (types .UID ("uid-2" ))
154- otherWorkspace .SetNamespace ("test-namespace" )
131+ otherWorkspace := setupWorkspace (t , "workspace-2" , "uid-2" , "test-namespace" )
155132
156133 fakeClient := fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (otherWorkspace ).Build ()
157134 handler := & WebhookHandler {Client : fakeClient }
158- err = handler .validateEndpoints (context .TODO (), workspace )
135+ err : = handler .validateEndpoints (context .TODO (), workspace )
159136 assert .NoError (t , err , "Did not expect an error when workspace has no discoverable endpoints" )
160137 })
161138
162139 t .Run ("Multiple workspaces in different namespaces can have same endpoint" , func (t * testing.T ) {
163140 // Workspace 1 in namespace-a
164- workspace1 := & dwv2.DevWorkspace {}
165- err := loadObjectFromFile ("workspace-ns-a" , workspace1 , "test-devworkspace.yaml" )
166- assert .NoError (t , err , "Failed to load workspace 1" )
167- workspace1 .SetUID (types .UID ("uid-ns-a" ))
168- workspace1 .SetNamespace ("namespace-a" )
141+ workspace1 := setupWorkspace (t , "workspace-ns-a" , "uid-ns-a" , "namespace-a" )
169142
170143 // Workspace 2 in namespace-b (will be in the fake client as existing)
171- workspace2 := & dwv2.DevWorkspace {}
172- err = loadObjectFromFile ("workspace-ns-b" , workspace2 , "test-devworkspace.yaml" )
173- assert .NoError (t , err , "Failed to load workspace 2" )
174- workspace2 .SetUID (types .UID ("uid-ns-b" ))
175- workspace2 .SetNamespace ("namespace-b" )
144+ workspace2 := setupWorkspace (t , "workspace-ns-b" , "uid-ns-b" , "namespace-b" )
176145
177146 // Workspace 3 in namespace-c (will be in the fake client as existing)
178- workspace3 := & dwv2.DevWorkspace {}
179- err = loadObjectFromFile ("workspace-ns-c" , workspace3 , "test-devworkspace.yaml" )
180- assert .NoError (t , err , "Failed to load workspace 3" )
181- workspace3 .SetUID (types .UID ("uid-ns-c" ))
182- workspace3 .SetNamespace ("namespace-c" )
147+ workspace3 := setupWorkspace (t , "workspace-ns-c" , "uid-ns-c" , "namespace-c" )
183148
184149 // All three workspaces exist, but in different namespaces
185150 fakeClient := fake .NewClientBuilder ().WithScheme (scheme ).
186151 WithObjects (workspace2 , workspace3 ).Build ()
187152 handler := & WebhookHandler {Client : fakeClient }
188153
189154 // Validating workspace1 should succeed (different namespaces)
190- err = handler .validateEndpoints (context .TODO (), workspace1 )
155+ err : = handler .validateEndpoints (context .TODO (), workspace1 )
191156 assert .NoError (t , err , "Should allow same endpoint name in different namespaces" )
192157 })
193158}
0 commit comments