Skip to content

Commit 37177d9

Browse files
committed
Add test cases to cover config migration
Signed-off-by: Angel Misevski <[email protected]>
1 parent b653207 commit 37177d9

File tree

3 files changed

+368
-37
lines changed

3 files changed

+368
-37
lines changed

pkg/config/common_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//
2+
// Copyright (c) 2019-2021 Red Hat, Inc.
3+
// This program and the accompanying materials are made
4+
// available under the terms of the Eclipse Public License 2.0
5+
// which is available at https://www.eclipse.org/legal/epl-2.0/
6+
//
7+
// SPDX-License-Identifier: EPL-2.0
8+
//
9+
// Contributors:
10+
// Red Hat, Inc. - initial API and implementation
11+
//
12+
13+
package config
14+
15+
import (
16+
"os"
17+
"testing"
18+
19+
dw "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
20+
routev1 "github.com/openshift/api/route/v1"
21+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
22+
"k8s.io/apimachinery/pkg/runtime"
23+
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
24+
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
25+
26+
"github.com/devfile/devworkspace-operator/apis/controller/v1alpha1"
27+
"github.com/devfile/devworkspace-operator/pkg/infrastructure"
28+
)
29+
30+
const testNamespace = "test-namespace"
31+
32+
var (
33+
scheme = runtime.NewScheme()
34+
trueBool = true
35+
)
36+
37+
func init() {
38+
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
39+
utilruntime.Must(v1alpha1.AddToScheme(scheme))
40+
utilruntime.Must(dw.AddToScheme(scheme))
41+
utilruntime.Must(routev1.Install(scheme))
42+
}
43+
44+
func setupForTest(t *testing.T) {
45+
if err := os.Setenv("WATCH_NAMESPACE", testNamespace); err != nil {
46+
t.Fatalf("failed to set up for test: %s", err)
47+
}
48+
infrastructure.InitializeForTesting(infrastructure.Kubernetes)
49+
configNamespace = testNamespace
50+
t.Cleanup(func() { internalConfig = nil })
51+
}
52+
53+
func buildConfig(config *v1alpha1.OperatorConfiguration) *v1alpha1.DevWorkspaceOperatorConfig {
54+
return &v1alpha1.DevWorkspaceOperatorConfig{
55+
ObjectMeta: metav1.ObjectMeta{
56+
Name: OperatorConfigName,
57+
Namespace: testNamespace,
58+
},
59+
Config: config,
60+
}
61+
}

pkg/config/migrate_test.go

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
//
2+
// Copyright (c) 2019-2021 Red Hat, Inc.
3+
// This program and the accompanying materials are made
4+
// available under the terms of the Eclipse Public License 2.0
5+
// which is available at https://www.eclipse.org/legal/epl-2.0/
6+
//
7+
// SPDX-License-Identifier: EPL-2.0
8+
//
9+
// Contributors:
10+
// Red Hat, Inc. - initial API and implementation
11+
//
12+
13+
package config
14+
15+
import (
16+
"context"
17+
"testing"
18+
19+
"github.com/stretchr/testify/assert"
20+
corev1 "k8s.io/api/core/v1"
21+
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
22+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23+
"k8s.io/apimachinery/pkg/types"
24+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
25+
26+
"github.com/devfile/devworkspace-operator/apis/controller/v1alpha1"
27+
"github.com/devfile/devworkspace-operator/pkg/config/configmap"
28+
)
29+
30+
func TestMigrateConfigDoesNothingWhenNoConfigMap(t *testing.T) {
31+
setupForTest(t)
32+
client := fake.NewClientBuilder().WithScheme(scheme).Build()
33+
err := MigrateConfigFromConfigMap(client)
34+
assert.NoError(t, err, "Should not return error when there is no configmap")
35+
36+
clusterConfig := &v1alpha1.DevWorkspaceOperatorConfig{}
37+
err = client.Get(context.Background(), types.NamespacedName{
38+
Name: OperatorConfigName,
39+
Namespace: testNamespace,
40+
}, clusterConfig)
41+
if assert.Error(t, err, "test client should return error when trying to get nonexistent clusterConfig") {
42+
assert.True(t, k8sErrors.IsNotFound(err), "expect error to be NotFound")
43+
}
44+
}
45+
46+
func TestMigrateConfigErrorWhenConfigAndConfigMapPresent(t *testing.T) {
47+
setupForTest(t)
48+
existingConfig := buildConfig(&v1alpha1.OperatorConfiguration{
49+
Workspace: &v1alpha1.WorkspaceConfig{
50+
ImagePullPolicy: "testImagePullPolicy",
51+
},
52+
})
53+
existingCM := &corev1.ConfigMap{
54+
ObjectMeta: metav1.ObjectMeta{
55+
Name: configmap.ConfigMapReference.Name,
56+
Namespace: testNamespace,
57+
},
58+
Data: map[string]string{
59+
"devworkspace.default_routing_class": "testRoutingClass",
60+
},
61+
}
62+
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(existingCM, existingConfig).Build()
63+
err := MigrateConfigFromConfigMap(client)
64+
assert.Error(t, err, "Should return error")
65+
assert.Equal(t, "found both DevWorkspaceOperatorConfig and configmap on cluster -- cannot migrate", err.Error())
66+
}
67+
68+
func TestMigrateConfigDeletesConfigMapWhenAlreadyMigrated(t *testing.T) {
69+
setupForTest(t)
70+
existingConfig := buildConfig(&v1alpha1.OperatorConfiguration{
71+
Routing: &v1alpha1.RoutingConfig{
72+
DefaultRoutingClass: "testRoutingClass",
73+
},
74+
})
75+
existingCM := &corev1.ConfigMap{
76+
ObjectMeta: metav1.ObjectMeta{
77+
Name: configmap.ConfigMapReference.Name,
78+
Namespace: testNamespace,
79+
},
80+
Data: map[string]string{
81+
"devworkspace.default_routing_class": "testRoutingClass",
82+
},
83+
}
84+
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(existingCM, existingConfig).Build()
85+
err := MigrateConfigFromConfigMap(client)
86+
if !assert.NoError(t, err, "Should not error") {
87+
return
88+
}
89+
clusterCM := &corev1.ConfigMap{}
90+
err = client.Get(context.Background(), types.NamespacedName{
91+
Name: configmap.ConfigMapReference.Name,
92+
Namespace: testNamespace,
93+
}, clusterCM)
94+
assert.Error(t, err, "Expect error on trying to find configmap as it is deleted")
95+
assert.True(t, k8sErrors.IsNotFound(err), "Expect error to be IsNotFound")
96+
}
97+
98+
func TestMigrateConfigCreatesCRFromConfigMap(t *testing.T) {
99+
setupForTest(t)
100+
existingCM := &corev1.ConfigMap{
101+
ObjectMeta: metav1.ObjectMeta{
102+
Name: configmap.ConfigMapReference.Name,
103+
Namespace: testNamespace,
104+
},
105+
Data: map[string]string{
106+
"devworkspace.default_routing_class": "testRoutingClass",
107+
"devworkspace.routing.cluster_host_suffix": "testHostSuffix",
108+
"devworkspace.sidecar.image_pull_policy": "testImagePullPolicy",
109+
"devworkspace.pvc.name": "testPVCName",
110+
"devworkspace.idle_timeout": "testIdleTimeout",
111+
"devworkspace.experimental_features_enabled": "true",
112+
},
113+
}
114+
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(existingCM).Build()
115+
116+
expectedConfig := buildConfig(&v1alpha1.OperatorConfiguration{
117+
Routing: &v1alpha1.RoutingConfig{
118+
DefaultRoutingClass: "testRoutingClass",
119+
ClusterHostSuffix: "testHostSuffix",
120+
},
121+
Workspace: &v1alpha1.WorkspaceConfig{
122+
ImagePullPolicy: "testImagePullPolicy",
123+
PVCName: "testPVCName",
124+
IdleTimeout: "testIdleTimeout",
125+
},
126+
EnableExperimentalFeatures: &trueBool,
127+
})
128+
129+
err := MigrateConfigFromConfigMap(client)
130+
if !assert.NoError(t, err, "Should not error") {
131+
return
132+
}
133+
clusterConfig := &v1alpha1.DevWorkspaceOperatorConfig{}
134+
err = client.Get(context.Background(), types.NamespacedName{
135+
Name: OperatorConfigName,
136+
Namespace: testNamespace,
137+
}, clusterConfig)
138+
if !assert.NoError(t, err, "Should create config CRD on cluster from configmap") {
139+
return
140+
}
141+
assert.Equal(t, expectedConfig.Config, clusterConfig.Config, "Expect configmap to be converted to config CRD")
142+
clusterCM := &corev1.ConfigMap{}
143+
err = client.Get(context.Background(), types.NamespacedName{
144+
Name: configmap.ConfigMapReference.Name,
145+
Namespace: testNamespace,
146+
}, clusterCM)
147+
assert.Error(t, err, "Expect error on trying to find configmap as it is deleted")
148+
assert.True(t, k8sErrors.IsNotFound(err), "Expect error to be IsNotFound")
149+
}
150+
151+
func TestMigrateConfigSucceedsWhenCRDHasAllValuesFromConfigMap(t *testing.T) {
152+
setupForTest(t)
153+
existingCM := &corev1.ConfigMap{
154+
ObjectMeta: metav1.ObjectMeta{
155+
Name: configmap.ConfigMapReference.Name,
156+
Namespace: testNamespace,
157+
},
158+
Data: map[string]string{
159+
"devworkspace.default_routing_class": "testRoutingClass",
160+
"devworkspace.routing.cluster_host_suffix": "testHostSuffix",
161+
},
162+
}
163+
existingConfig := buildConfig(&v1alpha1.OperatorConfiguration{
164+
Routing: &v1alpha1.RoutingConfig{
165+
DefaultRoutingClass: "testRoutingClass",
166+
ClusterHostSuffix: "testHostSuffix",
167+
},
168+
Workspace: &v1alpha1.WorkspaceConfig{
169+
ImagePullPolicy: "testImagePullPolicy",
170+
PVCName: "testPVCName",
171+
IdleTimeout: "testIdleTimeout",
172+
},
173+
})
174+
175+
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(existingConfig, existingCM).Build()
176+
177+
expectedConfig := existingConfig.DeepCopy()
178+
179+
err := MigrateConfigFromConfigMap(client)
180+
if !assert.NoError(t, err, "Should not error") {
181+
return
182+
}
183+
clusterConfig := &v1alpha1.DevWorkspaceOperatorConfig{}
184+
err = client.Get(context.Background(), types.NamespacedName{
185+
Name: OperatorConfigName,
186+
Namespace: testNamespace,
187+
}, clusterConfig)
188+
if !assert.NoError(t, err, "Config CRD should exist on cluster after successful migration") {
189+
return
190+
}
191+
assert.Equal(t, expectedConfig.Config, clusterConfig.Config, "Expect config CRD to be unchanged")
192+
clusterCM := &corev1.ConfigMap{}
193+
err = client.Get(context.Background(), types.NamespacedName{
194+
Name: configmap.ConfigMapReference.Name,
195+
Namespace: testNamespace,
196+
}, clusterCM)
197+
assert.Error(t, err, "Expect error on trying to find configmap as it is deleted")
198+
assert.True(t, k8sErrors.IsNotFound(err), "Expect error to be IsNotFound")
199+
}
200+
201+
func TestConvertConfigMapDoesNothingWhenNoConfigmap(t *testing.T) {
202+
setupForTest(t)
203+
client := fake.NewClientBuilder().WithScheme(scheme).Build()
204+
migratedConfig, err := convertConfigMapToConfigCRD(client)
205+
assert.NoError(t, err, "Should not return error when there is no configmap")
206+
assert.Nil(t, migratedConfig, "Should not create migrated config object when there is no configmap")
207+
}
208+
209+
func TestConvertConfigMapGetsAllOldConfigValues(t *testing.T) {
210+
setupForTest(t)
211+
cm := &corev1.ConfigMap{
212+
ObjectMeta: metav1.ObjectMeta{
213+
Name: configmap.ConfigMapReference.Name,
214+
Namespace: testNamespace,
215+
},
216+
Data: map[string]string{
217+
"devworkspace.default_routing_class": "testRoutingClass",
218+
"devworkspace.routing.cluster_host_suffix": "testHostSuffix",
219+
"devworkspace.sidecar.image_pull_policy": "testImagePullPolicy",
220+
"devworkspace.pvc.name": "testPVCName",
221+
"devworkspace.pvc.storage_class.name": "testStorageClassName",
222+
"devworkspace.idle_timeout": "testIdleTimeout",
223+
"devworkspace.experimental_features_enabled": "true",
224+
},
225+
}
226+
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(cm).Build()
227+
228+
testStorageClassName := "testStorageClassName"
229+
expectedConfig := buildConfig(&v1alpha1.OperatorConfiguration{
230+
Routing: &v1alpha1.RoutingConfig{
231+
DefaultRoutingClass: "testRoutingClass",
232+
ClusterHostSuffix: "testHostSuffix",
233+
},
234+
Workspace: &v1alpha1.WorkspaceConfig{
235+
ImagePullPolicy: "testImagePullPolicy",
236+
PVCName: "testPVCName",
237+
StorageClassName: &testStorageClassName,
238+
IdleTimeout: "testIdleTimeout",
239+
},
240+
EnableExperimentalFeatures: &trueBool,
241+
})
242+
243+
migratedConfig, err := convertConfigMapToConfigCRD(client)
244+
if !assert.NoError(t, err, "Should not return error when there is no configmap") {
245+
return
246+
}
247+
assert.Equal(t, expectedConfig, migratedConfig, "Should pick up all values in config")
248+
}
249+
250+
func TestConvertConfigMapIgnoresValuesThatAreDefault(t *testing.T) {
251+
setupForTest(t)
252+
cm := &corev1.ConfigMap{
253+
ObjectMeta: metav1.ObjectMeta{
254+
Name: configmap.ConfigMapReference.Name,
255+
Namespace: testNamespace,
256+
},
257+
Data: map[string]string{
258+
"devworkspace.default_routing_class": "basic",
259+
"devworkspace.routing.cluster_host_suffix": "testHostSuffix",
260+
"devworkspace.sidecar.image_pull_policy": "Always",
261+
"devworkspace.pvc.name": "testPVCName",
262+
"devworkspace.idle_timeout": "testIdleTimeout",
263+
"devworkspace.experimental_features_enabled": "false",
264+
},
265+
}
266+
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(cm).Build()
267+
268+
expectedConfig := buildConfig(&v1alpha1.OperatorConfiguration{
269+
Routing: &v1alpha1.RoutingConfig{
270+
ClusterHostSuffix: "testHostSuffix",
271+
},
272+
Workspace: &v1alpha1.WorkspaceConfig{
273+
PVCName: "testPVCName",
274+
IdleTimeout: "testIdleTimeout",
275+
},
276+
})
277+
278+
migratedConfig, err := convertConfigMapToConfigCRD(client)
279+
if !assert.NoError(t, err, "Should not return error when there is no configmap") {
280+
return
281+
}
282+
assert.Equal(t, expectedConfig, migratedConfig, "Should drop default values in configmap")
283+
}
284+
285+
func TestConvertConfigMapReturnsNilWhenAllDefault(t *testing.T) {
286+
setupForTest(t)
287+
cm := &corev1.ConfigMap{
288+
ObjectMeta: metav1.ObjectMeta{
289+
Name: configmap.ConfigMapReference.Name,
290+
Namespace: testNamespace,
291+
},
292+
Data: map[string]string{
293+
"devworkspace.default_routing_class": "basic",
294+
"devworkspace.sidecar.image_pull_policy": "Always",
295+
"devworkspace.pvc.name": "claim-devworkspace",
296+
"devworkspace.idle_timeout": "15m",
297+
"devworkspace.experimental_features_enabled": "false",
298+
},
299+
}
300+
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(cm).Build()
301+
302+
migratedConfig, err := convertConfigMapToConfigCRD(client)
303+
if !assert.NoError(t, err, "Should not return error when there is no configmap") {
304+
return
305+
}
306+
assert.Nil(t, migratedConfig, "Should return (nil, nil) when configmap is all default")
307+
}

0 commit comments

Comments
 (0)