Skip to content
This repository was archived by the owner on Dec 16, 2025. It is now read-only.

Commit da71737

Browse files
Add missing unit tests for openstackclusterstackrelease controller (#61)
Signed-off-by: michal.gubricky <[email protected]>
1 parent 34837b6 commit da71737

File tree

24 files changed

+5567
-1
lines changed

24 files changed

+5567
-1
lines changed

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.21
44

55
require (
66
github.com/SovereignCloudStack/cluster-stack-operator v0.1.0-alpha.2
7+
github.com/google/go-github/v52 v52.0.0
78
github.com/gophercloud/gophercloud v1.8.0
89
github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56
910
github.com/onsi/ginkgo/v2 v2.15.0
@@ -41,7 +42,6 @@ require (
4142
github.com/golang/protobuf v1.5.3 // indirect
4243
github.com/google/gnostic-models v0.6.8 // indirect
4344
github.com/google/go-cmp v0.6.0 // indirect
44-
github.com/google/go-github/v52 v52.0.0 // indirect
4545
github.com/google/go-querystring v1.1.0 // indirect
4646
github.com/google/gofuzz v1.2.0 // indirect
4747
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
@@ -63,6 +63,7 @@ require (
6363
github.com/prometheus/common v0.44.0 // indirect
6464
github.com/prometheus/procfs v0.11.1 // indirect
6565
github.com/spf13/pflag v1.0.5 // indirect
66+
github.com/stretchr/objx v0.5.1 // indirect
6667
go.uber.org/goleak v1.3.0 // indirect
6768
go.uber.org/multierr v1.11.0 // indirect
6869
go.uber.org/zap v1.25.0 // indirect

go.sum

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,15 @@ github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8w
169169
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
170170
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
171171
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
172+
github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0=
173+
github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0=
172174
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
173175
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
174176
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
175177
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
176178
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
177179
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
180+
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
178181
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
179182
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
180183
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=

internal/controller/openstackclusterstackrelease_controller_test.go

Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,14 @@ package controller
1818

1919
import (
2020
"context"
21+
"errors"
2122
"fmt"
23+
"net/http"
2224
"testing"
2325
"time"
2426

27+
githubmocks "github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/mocks"
28+
"github.com/google/go-github/v52/github"
2529
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
2630
. "github.com/onsi/ginkgo/v2"
2731
. "github.com/onsi/gomega"
@@ -30,8 +34,10 @@ import (
3034
corev1 "k8s.io/api/core/v1"
3135
apierrors "k8s.io/apimachinery/pkg/api/errors"
3236
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
37+
"k8s.io/apimachinery/pkg/runtime"
3338
"k8s.io/apimachinery/pkg/types"
3439
capoapiv1alpha7 "sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha7"
40+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
3541
)
3642

3743
const (
@@ -168,6 +174,305 @@ func TestGetNodeImagesFromLocal(t *testing.T) {
168174
})
169175
}
170176

177+
func TestDownloadReleaseAssets(t *testing.T) {
178+
ctx := context.TODO()
179+
releaseTag := "v1.0.0"
180+
downloadPath := "/tmp/download"
181+
assetlist := []string{metadataFileName, nodeImagesFileName}
182+
mockGitHubClient := githubmocks.NewClient(t)
183+
mockHTTPResponse := &http.Response{
184+
StatusCode: http.StatusOK,
185+
}
186+
mockResponse := &github.Response{
187+
Response: mockHTTPResponse,
188+
}
189+
mockRepoRelease := &github.RepositoryRelease{
190+
Name: github.String("test-release-name"),
191+
}
192+
193+
mockGitHubClient.On("GetReleaseByTag", ctx, releaseTag).Return(mockRepoRelease, mockResponse, nil)
194+
repoRelease, resp, err := mockGitHubClient.GetReleaseByTag(ctx, releaseTag)
195+
assert.NoError(t, err)
196+
assert.Equal(t, resp.StatusCode, http.StatusOK)
197+
198+
mockGitHubClient.On("DownloadReleaseAssets", ctx, repoRelease, downloadPath, assetlist).Return(nil)
199+
200+
err = downloadReleaseAssets(ctx, releaseTag, downloadPath, mockGitHubClient)
201+
202+
assert.NoError(t, err)
203+
}
204+
205+
func TestDownloadReleaseAssetsFailedToDownload(t *testing.T) {
206+
ctx := context.TODO()
207+
releaseTag := "v1.0.0"
208+
mockGitHubClient := githubmocks.NewClient(t)
209+
downloadPath := "/tmp/download"
210+
assetlist := []string{metadataFileName, nodeImagesFileName}
211+
mockHTTPResponse := &http.Response{
212+
StatusCode: http.StatusOK,
213+
}
214+
mockResponse := &github.Response{
215+
Response: mockHTTPResponse,
216+
}
217+
mockRepoRelease := &github.RepositoryRelease{
218+
Name: github.String("test-release-name"),
219+
}
220+
221+
mockGitHubClient.On("GetReleaseByTag", ctx, releaseTag).Return(mockRepoRelease, mockResponse, nil)
222+
repoRelease, resp, err := mockGitHubClient.GetReleaseByTag(ctx, releaseTag)
223+
assert.NoError(t, err)
224+
assert.Equal(t, resp.StatusCode, http.StatusOK)
225+
226+
mockGitHubClient.On("DownloadReleaseAssets", ctx, repoRelease, downloadPath, assetlist).Return(errors.New("failed to download release assets"))
227+
err = downloadReleaseAssets(ctx, releaseTag, downloadPath, mockGitHubClient)
228+
229+
assert.ErrorContains(t, err, "failed to download release assets")
230+
}
231+
232+
func TestGetOwnedOpenStackNodeImageReleases(t *testing.T) {
233+
scheme := runtime.NewScheme()
234+
err := apiv1alpha1.AddToScheme(scheme)
235+
assert.NoError(t, err)
236+
client := fake.NewClientBuilder().WithScheme(scheme).Build()
237+
238+
openstackclusterstackrelease := &apiv1alpha1.OpenStackClusterStackRelease{
239+
TypeMeta: metav1.TypeMeta{
240+
APIVersion: "clusterstack.x-k8s.io/v1alpha1",
241+
Kind: "OpenStackClusterStackRelease",
242+
},
243+
ObjectMeta: metav1.ObjectMeta{
244+
Name: "test-release",
245+
Namespace: "test-namespace",
246+
},
247+
Spec: apiv1alpha1.OpenStackClusterStackReleaseSpec{
248+
CloudName: "test-cloudname",
249+
IdentityRef: &capoapiv1alpha7.OpenStackIdentityReference{
250+
Kind: "Secret",
251+
Name: "supersecret",
252+
},
253+
},
254+
}
255+
assert.NoError(t, client.Create(context.TODO(), openstackclusterstackrelease))
256+
257+
openstackNodeImageRelease := &apiv1alpha1.OpenStackNodeImageRelease{
258+
TypeMeta: metav1.TypeMeta{
259+
APIVersion: "clusterstack.x-k8s.io/v1alpha1",
260+
Kind: "OpenStackNodeImageRelease",
261+
},
262+
ObjectMeta: metav1.ObjectMeta{
263+
Name: "test-node-image-release",
264+
Namespace: "test-namespace",
265+
OwnerReferences: []metav1.OwnerReference{
266+
{
267+
APIVersion: openstackclusterstackrelease.APIVersion,
268+
Kind: openstackclusterstackrelease.Kind,
269+
Name: openstackclusterstackrelease.Name,
270+
UID: openstackclusterstackrelease.UID,
271+
},
272+
},
273+
},
274+
}
275+
276+
assert.NoError(t, client.Create(context.TODO(), openstackNodeImageRelease))
277+
278+
r := &OpenStackClusterStackReleaseReconciler{
279+
Client: client,
280+
}
281+
282+
ownedOpenStackNodeImageReleases, err := r.getOwnedOpenStackNodeImageReleases(context.TODO(), openstackclusterstackrelease)
283+
284+
assert.NoError(t, err)
285+
assert.NotEmpty(t, ownedOpenStackNodeImageReleases)
286+
assert.Contains(t, ownedOpenStackNodeImageReleases, openstackNodeImageRelease)
287+
}
288+
289+
func TestCreateOpenStackNodeImageRelease(t *testing.T) {
290+
scheme := runtime.NewScheme()
291+
err := apiv1alpha1.AddToScheme(scheme)
292+
assert.NoError(t, err)
293+
client := fake.NewClientBuilder().WithScheme(scheme).Build()
294+
295+
openstackclusterstackrelease := &apiv1alpha1.OpenStackClusterStackRelease{
296+
TypeMeta: metav1.TypeMeta{
297+
APIVersion: "clusterstack.x-k8s.io/v1alpha1",
298+
Kind: "OpenStackClusterStackRelease",
299+
},
300+
ObjectMeta: metav1.ObjectMeta{
301+
Name: "test-release",
302+
Namespace: "test-namespace",
303+
},
304+
Spec: apiv1alpha1.OpenStackClusterStackReleaseSpec{
305+
CloudName: "test-cloudname",
306+
IdentityRef: &capoapiv1alpha7.OpenStackIdentityReference{
307+
Kind: "Secret",
308+
Name: "supersecret",
309+
},
310+
},
311+
}
312+
assert.NoError(t, client.Create(context.TODO(), openstackclusterstackrelease))
313+
314+
openStackNodeImage := &apiv1alpha1.OpenStackNodeImage{
315+
URL: "test-url",
316+
CreateOpts: &apiv1alpha1.CreateOpts{
317+
Name: "test-image",
318+
ID: "testID",
319+
ContainerFormat: "bare",
320+
DiskFormat: "qcow2",
321+
},
322+
}
323+
324+
ownerRef := &metav1.OwnerReference{
325+
APIVersion: openstackclusterstackrelease.APIVersion,
326+
Kind: openstackclusterstackrelease.Kind,
327+
Name: openstackclusterstackrelease.Name,
328+
UID: openstackclusterstackrelease.UID,
329+
}
330+
331+
r := &OpenStackClusterStackReleaseReconciler{
332+
Client: client,
333+
}
334+
335+
err = r.createOrUpdateOpenStackNodeImageRelease(context.TODO(), openstackclusterstackrelease, "test-osnir", openStackNodeImage, ownerRef)
336+
337+
assert.NoError(t, err)
338+
osnir := &apiv1alpha1.OpenStackNodeImageRelease{}
339+
err = client.Get(context.TODO(), types.NamespacedName{Name: "test-osnir", Namespace: "test-namespace"}, osnir)
340+
assert.NoError(t, err)
341+
assert.NotNil(t, osnir)
342+
343+
expectedosnir := &apiv1alpha1.OpenStackNodeImageRelease{
344+
TypeMeta: metav1.TypeMeta{
345+
Kind: "OpenStackNodeImageRelease",
346+
APIVersion: apiv1alpha1.GroupVersion.String(),
347+
},
348+
Spec: apiv1alpha1.OpenStackNodeImageReleaseSpec{
349+
CloudName: "test-cloudname",
350+
IdentityRef: &capoapiv1alpha7.OpenStackIdentityReference{
351+
Kind: "Secret",
352+
Name: "supersecret",
353+
},
354+
Image: &apiv1alpha1.OpenStackNodeImage{
355+
URL: "test-url",
356+
CreateOpts: &apiv1alpha1.CreateOpts{
357+
Name: "test-image",
358+
ID: "testID",
359+
ContainerFormat: "bare",
360+
DiskFormat: "qcow2",
361+
},
362+
},
363+
},
364+
}
365+
assert.Equal(t, expectedosnir.Spec, osnir.Spec)
366+
assert.Equal(t, expectedosnir.TypeMeta, osnir.TypeMeta)
367+
368+
// Test cleanup
369+
err = client.Delete(context.TODO(), osnir)
370+
assert.NoError(t, err)
371+
err = client.Delete(context.TODO(), openstackclusterstackrelease)
372+
assert.NoError(t, err)
373+
}
374+
375+
func TestUpdateOpenStackNodeImageRelease(t *testing.T) {
376+
scheme := runtime.NewScheme()
377+
err := apiv1alpha1.AddToScheme(scheme)
378+
assert.NoError(t, err)
379+
client := fake.NewClientBuilder().WithScheme(scheme).Build()
380+
381+
openstackclusterstackrelease := &apiv1alpha1.OpenStackClusterStackRelease{
382+
TypeMeta: metav1.TypeMeta{
383+
APIVersion: "clusterstack.x-k8s.io/v1alpha1",
384+
Kind: "OpenStackClusterStackRelease",
385+
},
386+
ObjectMeta: metav1.ObjectMeta{
387+
Name: "test-release",
388+
Namespace: "test-namespace",
389+
},
390+
Spec: apiv1alpha1.OpenStackClusterStackReleaseSpec{
391+
CloudName: "test-cloudname",
392+
IdentityRef: &capoapiv1alpha7.OpenStackIdentityReference{
393+
Kind: "Secret",
394+
Name: "supersecret",
395+
},
396+
},
397+
}
398+
assert.NoError(t, client.Create(context.TODO(), openstackclusterstackrelease))
399+
400+
openStackNodeImage := &apiv1alpha1.OpenStackNodeImage{
401+
URL: "test-url",
402+
CreateOpts: &apiv1alpha1.CreateOpts{
403+
Name: "test-image",
404+
ID: "testID",
405+
ContainerFormat: "bare",
406+
DiskFormat: "qcow2",
407+
},
408+
}
409+
410+
ownerRef := &metav1.OwnerReference{
411+
APIVersion: openstackclusterstackrelease.APIVersion,
412+
Kind: openstackclusterstackrelease.Kind,
413+
Name: openstackclusterstackrelease.Name,
414+
UID: "test-uid",
415+
}
416+
417+
r := &OpenStackClusterStackReleaseReconciler{
418+
Client: client,
419+
}
420+
421+
osnir := &apiv1alpha1.OpenStackNodeImageRelease{
422+
TypeMeta: metav1.TypeMeta{
423+
Kind: "OpenStackNodeImageRelease",
424+
APIVersion: apiv1alpha1.GroupVersion.String(),
425+
},
426+
ObjectMeta: metav1.ObjectMeta{
427+
Name: "test-update-osnir",
428+
Namespace: "test-namespace",
429+
},
430+
Spec: apiv1alpha1.OpenStackNodeImageReleaseSpec{
431+
CloudName: "test-cloudname",
432+
IdentityRef: &capoapiv1alpha7.OpenStackIdentityReference{
433+
Kind: "Secret",
434+
Name: "supersecret",
435+
},
436+
Image: &apiv1alpha1.OpenStackNodeImage{
437+
URL: "test-url",
438+
CreateOpts: &apiv1alpha1.CreateOpts{
439+
Name: "test-image",
440+
ID: "testID",
441+
ContainerFormat: "bare",
442+
DiskFormat: "qcow2",
443+
},
444+
},
445+
},
446+
}
447+
osnir.SetOwnerReferences([]metav1.OwnerReference{*ownerRef})
448+
assert.NoError(t, client.Create(context.TODO(), osnir))
449+
450+
newOwnerRef := &metav1.OwnerReference{
451+
APIVersion: openstackclusterstackrelease.APIVersion,
452+
Kind: openstackclusterstackrelease.Kind,
453+
Name: openstackclusterstackrelease.Name,
454+
UID: "test-new-uid",
455+
}
456+
457+
err = client.Get(context.TODO(), types.NamespacedName{Name: "test-update-osnir", Namespace: "test-namespace"}, &apiv1alpha1.OpenStackNodeImageRelease{})
458+
assert.NoError(t, err)
459+
assert.Equal(t, ownerRef.UID, osnir.OwnerReferences[0].UID)
460+
461+
err = r.createOrUpdateOpenStackNodeImageRelease(context.TODO(), openstackclusterstackrelease, "test-update-osnir", openStackNodeImage, newOwnerRef)
462+
assert.NoError(t, err)
463+
464+
err = client.Get(context.TODO(), types.NamespacedName{Name: "test-update-osnir", Namespace: "test-namespace"}, osnir)
465+
assert.NoError(t, err)
466+
assert.NotNil(t, osnir)
467+
assert.Equal(t, *newOwnerRef, osnir.OwnerReferences[0])
468+
469+
// Test cleanup
470+
err = client.Delete(context.TODO(), osnir)
471+
assert.NoError(t, err)
472+
err = client.Delete(context.TODO(), openstackclusterstackrelease)
473+
assert.NoError(t, err)
474+
}
475+
171476
var _ = Describe("OpenStackClusterStackRelease controller", func() {
172477
Context("OpenStackClusterStackRelease controller test", func() {
173478
const openstackclusterstackreleasename = "test-ocsr"

0 commit comments

Comments
 (0)