@@ -49,31 +49,47 @@ func TestVariableVKsDiscoveryAndResolution(t *testing.T) {
49
49
if err != nil {
50
50
t .Fatal (err )
51
51
}
52
- crdFile , err := os .CreateTemp ("" , "crd.yaml" )
52
+ initCrdFile , err := os .CreateTemp ("" , "crd.yaml" )
53
53
if err != nil {
54
54
t .Fatal (err )
55
55
}
56
- crFile , err := os .CreateTemp ("" , "cr.yaml" )
56
+ initCrFile , err := os .CreateTemp ("" , "cr.yaml" )
57
57
if err != nil {
58
58
t .Fatal (err )
59
59
}
60
- klog .InfoS ("testdata" , "crConfigFile" , crConfigFile .Name (), "crdFile" , crdFile .Name (), "crFile" , crFile .Name ())
60
+ newCrdFile , err := os .CreateTemp ("" , "new-crd.yaml" )
61
+ if err != nil {
62
+ t .Fatal (err )
63
+ }
64
+ newCrFile , err := os .CreateTemp ("" , "new-cr.yaml" )
65
+ if err != nil {
66
+ t .Fatal (err )
67
+ }
68
+ klog .InfoS ("testdata" , "crConfigFile" , crConfigFile .Name (), "initCrdFile" , initCrdFile .Name (), "initCrFile" , initCrFile .Name (), "newCrdFile" , newCrdFile .Name (), "newCrFile" , newCrFile .Name ())
61
69
62
70
// Delete artefacts.
63
71
defer func () {
64
72
err := os .Remove (crConfigFile .Name ())
65
73
if err != nil {
66
74
t .Fatalf ("failed to remove CR config: %v" , err )
67
75
}
68
- err = os .Remove (crdFile .Name ())
76
+ err = os .Remove (initCrdFile .Name ())
77
+ if err != nil {
78
+ t .Fatalf ("failed to remove initial CRD manifest: %v" , err )
79
+ }
80
+ err = os .Remove (initCrFile .Name ())
81
+ if err != nil {
82
+ t .Fatalf ("failed to remove initial CR manifest: %v" , err )
83
+ }
84
+ err = os .Remove (newCrdFile .Name ())
69
85
if err != nil {
70
- t .Fatalf ("failed to remove CRD manifest: %v" , err )
86
+ t .Fatalf ("failed to remove new CRD manifest: %v" , err )
71
87
}
72
- err = os .Remove (crFile .Name ())
88
+ err = os .Remove (newCrFile .Name ())
73
89
if err != nil {
74
- t .Fatalf ("failed to remove CR manifest: %v" , err )
90
+ t .Fatalf ("failed to remove new CR manifest: %v" , err )
75
91
}
76
- klog .InfoS ("deleted artefacts" , "crConfigFile" , crConfigFile .Name (), "crdFile " , crdFile .Name (), "crFile " , crFile .Name ())
92
+ klog .InfoS ("deleted artefacts" , "crConfigFile" , crConfigFile .Name (), "initCrdFile " , initCrdFile .Name (), "initCrFile " , initCrFile . Name (), "newCrdFile" , newCrdFile . Name (), "newCrFile" , newCrFile .Name ())
77
93
}()
78
94
79
95
// Populate options, and parse them.
@@ -114,32 +130,92 @@ func TestVariableVKsDiscoveryAndResolution(t *testing.T) {
114
130
klog .InfoS ("port 8080 up" )
115
131
116
132
// Create CRD and CR files.
117
- crd := getCRD ()
118
- cr := getCR ()
119
- err = os .WriteFile (crdFile .Name (), []byte (crd ), 0600 /* rw------- */ )
133
+ initCr := getCR ()
134
+ initCrd := getCRD ()
135
+
136
+ newCr := getNewCR ()
137
+ newCrd := getNewCRD ()
138
+ err = os .WriteFile (initCrdFile .Name (), []byte (initCrd ), 0600 /* rw------- */ )
120
139
if err != nil {
121
- t .Fatalf ("cannot write to crd file: %v" , err )
140
+ t .Fatalf ("cannot write to initial crd file: %v" , err )
122
141
}
123
- err = os .WriteFile (crFile .Name (), []byte (cr ), 0600 /* rw------- */ )
142
+ err = os .WriteFile (initCrFile .Name (), []byte (initCr ), 0600 /* rw------- */ )
124
143
if err != nil {
125
- t .Fatalf ("cannot write to cr file: %v" , err )
144
+ t .Fatalf ("cannot write to initial cr file: %v" , err )
126
145
}
127
- klog .InfoS ("created CR and CRD manifests" )
146
+ err = os .WriteFile (newCrdFile .Name (), []byte (newCrd ), 0600 /* rw------- */ )
147
+ if err != nil {
148
+ t .Fatalf ("cannot write to new crd file: %v" , err )
149
+ }
150
+ err = os .WriteFile (newCrFile .Name (), []byte (newCr ), 0600 /* rw------- */ )
151
+ if err != nil {
152
+ t .Fatalf ("cannot write to new cr file: %v" , err )
153
+ }
154
+ klog .InfoS ("created initial and new CR and CRD manifests" )
128
155
129
- // Apply CRD and CR to the cluster.
130
- err = exec .Command ("kubectl" , "apply" , "-f" , crdFile .Name ()).Run () //nolint:gosec
156
+ // Apply initial CRD and CR to the cluster.
157
+ err = exec .Command ("kubectl" , "apply" , "-f" , initCrdFile .Name ()).Run () //nolint:gosec
131
158
if err != nil {
132
- t .Fatalf ("failed to apply crd: %v" , err )
159
+ t .Fatalf ("failed to apply initial crd: %v" , err )
133
160
}
134
- err = exec .Command ("kubectl" , "apply" , "-f" , crFile .Name ()).Run () //nolint:gosec
161
+ err = exec .Command ("kubectl" , "apply" , "-f" , initCrFile .Name ()).Run () //nolint:gosec
135
162
if err != nil {
136
- t .Fatalf ("failed to apply cr: %v" , err )
163
+ t .Fatalf ("failed to apply initial cr: %v" , err )
137
164
}
138
- klog .InfoS ("applied CR and CRD manifests" )
165
+ klog .InfoS ("applied initial CR and CRD manifests" )
139
166
140
167
// Wait for the metric to be available.
141
168
ch := make (chan bool , 1 )
142
- klog .InfoS ("waiting for metrics to become available" )
169
+ klog .InfoS ("waiting for first metrics to become available" )
170
+ testMetric := `kube_customresource_test_metric{customresource_group="contoso.com",customresource_kind="MyPlatform",customresource_version="v1alpha1",name="test-dotnet-app"}`
171
+ err = wait .PollUntilContextTimeout (context .TODO (), discovery .Interval , PopulateTimeout , true , func (_ context.Context ) (bool , error ) {
172
+ out , err := exec .Command ("curl" , "localhost:8080/metrics" ).Output ()
173
+ if err != nil {
174
+ return false , err
175
+ }
176
+ if string (out ) == "" {
177
+ return false , nil
178
+ }
179
+ // Note: we use count to make sure that only one metrics handler is running
180
+ if strings .Count (string (out ), testMetric ) == 1 {
181
+ // klog.InfoS("metrics available", "metric", string(out))
182
+ // Signal the process to exit, since we know the metrics are being generated as expected.
183
+ ch <- true
184
+ return true , nil
185
+ }
186
+ return false , nil
187
+ })
188
+ if err != nil {
189
+ t .Fatalf ("failed while waiting for initial metrics to be available: %v" , err )
190
+ }
191
+
192
+ // Wait for process to exit.
193
+ select {
194
+ case <- ch :
195
+ t .Log ("initial metrics are available" )
196
+ case <- time .After (PopulateTimeout * 2 ):
197
+ t .Fatal ("timed out waiting for test to pass, check the logs for more info" )
198
+ }
199
+
200
+ // Apply new CRD and CR to the cluster.
201
+ err = exec .Command ("kubectl" , "apply" , "-f" , newCrdFile .Name ()).Run () //nolint:gosec
202
+ if err != nil {
203
+ t .Fatalf ("failed to apply new crd: %v" , err )
204
+ }
205
+ err = exec .Command ("kubectl" , "apply" , "-f" , newCrFile .Name ()).Run () //nolint:gosec
206
+ if err != nil {
207
+ t .Fatalf ("failed to apply new cr: %v" , err )
208
+ }
209
+ err = exec .Command ("kubectl" , "delete" , "myplatform" , "test-dotnet-app" ).Run () //nolint:gosec
210
+ if err != nil {
211
+ t .Fatalf ("failed to delete myplatform resource: %v" , err )
212
+ }
213
+ klog .InfoS ("applied new CR and CRD manifests" )
214
+
215
+ // Wait for the the new metric to be available
216
+ ch = make (chan bool , 1 )
217
+ klog .InfoS ("waiting for new metrics to become available" )
218
+ testUpdateCRDMetric := `kube_customresource_test_update_crd_metric{customresource_group="contoso.com",customresource_kind="Update",customresource_version="v1",name="test-dotnet-app-update"}`
143
219
err = wait .PollUntilContextTimeout (context .TODO (), discovery .Interval , PopulateTimeout , true , func (_ context.Context ) (bool , error ) {
144
220
out , err := exec .Command ("curl" , "localhost:8080/metrics" ).Output ()
145
221
if err != nil {
@@ -148,17 +224,20 @@ func TestVariableVKsDiscoveryAndResolution(t *testing.T) {
148
224
if string (out ) == "" {
149
225
return false , nil
150
226
}
151
- // Note the "{" below. This is to ensure that the metric is not in a comment.
152
- if strings .Contains (string (out ), "kube_customresource_test_metric{" ) {
227
+ // Note: we use count to make sure that only one metrics handler is running, and we also want to validate that the
228
+ // new metric is available and the old one was removed, otherwise, the response could come from the
229
+ // previous handler before its context was cancelled, or maybe because it failed to be cancelled.
230
+ if strings .Count (string (out ), testUpdateCRDMetric ) == 1 && ! strings .Contains (string (out ), testMetric ) {
153
231
klog .InfoS ("metrics available" , "metric" , string (out ))
154
232
// Signal the process to exit, since we know the metrics are being generated as expected.
155
233
ch <- true
156
234
return true , nil
157
235
}
236
+ klog .InfoS ("metrics available" , "metric" , string (out ))
158
237
return false , nil
159
238
})
160
239
if err != nil {
161
- t .Fatalf ("failed while waiting for metrics to be available: %v" , err )
240
+ t .Fatalf ("failed while waiting for new metrics to be available: %v" , err )
162
241
}
163
242
164
243
// Wait for process to exit.
@@ -252,8 +331,8 @@ spec:
252
331
resources:
253
332
- groupVersionKind:
254
333
group: "contoso.com"
255
- version: "* "
256
- kind: "* "
334
+ version: "v1alpha1 "
335
+ kind: "MyPlatform "
257
336
metrics:
258
337
- name: "test_metric"
259
338
help: "foo baz"
@@ -263,5 +342,61 @@ spec:
263
342
path: [metadata]
264
343
labelsFromPath:
265
344
name: [name]
345
+ - groupVersionKind:
346
+ group: "contoso.com"
347
+ version: "v1"
348
+ kind: "Update"
349
+ metrics:
350
+ - name: "test_update_crd_metric"
351
+ help: "foo baz"
352
+ each:
353
+ type: Info
354
+ info:
355
+ path: [metadata]
356
+ labelsFromPath:
357
+ name: [name]
358
+ `
359
+ }
360
+
361
+ func getNewCR () string {
362
+ return `
363
+ apiVersion: contoso.com/v1
364
+ kind: Update
365
+ metadata:
366
+ name: test-dotnet-app-update
367
+ spec:
368
+ new: just-added
369
+ `
370
+ }
371
+
372
+ func getNewCRD () string {
373
+ return `
374
+ apiVersion: apiextensions.k8s.io/v1
375
+ kind: CustomResourceDefinition
376
+ metadata:
377
+ name: updates.contoso.com
378
+ spec:
379
+ group: contoso.com
380
+ names:
381
+ plural: updates
382
+ singular: update
383
+ kind: Update
384
+ shortNames:
385
+ - updt
386
+ scope: Namespaced
387
+ versions:
388
+ - name: v1
389
+ served: true
390
+ storage: true
391
+ schema:
392
+ openAPIV3Schema:
393
+ type: object
394
+ properties:
395
+ spec:
396
+ type: object
397
+ properties:
398
+ new:
399
+ type: string
400
+ required: ["spec"]
266
401
`
267
402
}
0 commit comments