Skip to content

Commit ffc7bfa

Browse files
author
Per Goncalves da Silva
committed
Update NewBundleFS test utility to builder pattern
Signed-off-by: Per Goncalves da Silva <[email protected]>
1 parent 55d9dfb commit ffc7bfa

File tree

5 files changed

+282
-68
lines changed

5 files changed

+282
-68
lines changed

internal/operator-controller/applier/boxcutter_test.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import (
2424
"sigs.k8s.io/controller-runtime/pkg/client"
2525
"sigs.k8s.io/controller-runtime/pkg/client/fake"
2626

27+
"github.com/operator-framework/api/pkg/operators/v1alpha1"
28+
2729
ocv1 "github.com/operator-framework/operator-controller/api/v1"
2830
"github.com/operator-framework/operator-controller/internal/operator-controller/applier"
2931
"github.com/operator-framework/operator-controller/internal/operator-controller/controllers"
@@ -52,7 +54,10 @@ func Test_RegistryV1BundleRenderer_Render_Success(t *testing.T) {
5254
},
5355
},
5456
}
55-
bundleFS := testutils.NewBundleFS()
57+
58+
bundleFS := testutils.BundleFSBuilder().
59+
WithPackageName("some-package").
60+
WithCSV(testutils.MakeCSV(testutils.WithInstallModeSupportFor(v1alpha1.InstallModeTypeAllNamespaces))).Build()
5661

5762
objs, err := r.Render(bundleFS, &ocv1.ClusterExtension{
5863
Spec: ocv1.ClusterExtensionSpec{
@@ -74,7 +79,9 @@ func Test_RegistryV1BundleRenderer_Render_Failure(t *testing.T) {
7479
},
7580
},
7681
}
77-
bundleFS := testutils.NewBundleFS()
82+
bundleFS := testutils.BundleFSBuilder().
83+
WithPackageName("some-package").
84+
WithCSV(testutils.MakeCSV(testutils.WithInstallModeSupportFor(v1alpha1.InstallModeTypeAllNamespaces))).Build()
7885

7986
objs, err := r.Render(bundleFS, &ocv1.ClusterExtension{
8087
Spec: ocv1.ClusterExtensionSpec{

internal/operator-controller/rukpak/bundle/source/source.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ type BundleSource interface {
2424
GetBundle() (bundle.RegistryV1, error)
2525
}
2626

27+
type RegistryV1Properties struct {
28+
Properties []property.Property `json:"properties"`
29+
}
30+
2731
// identitySource is a bundle source that returns itself
2832
type identitySource bundle.RegistryV1
2933

@@ -158,11 +162,7 @@ func copyMetadataPropertiesToCSV(csv *v1alpha1.ClusterServiceVersion, fsys fs.FS
158162

159163
// Otherwise, we need to parse the properties.yaml file and
160164
// append its properties into the CSV annotation.
161-
type registryV1Properties struct {
162-
Properties []property.Property `json:"properties"`
163-
}
164-
165-
var metadataProperties registryV1Properties
165+
var metadataProperties RegistryV1Properties
166166
if err := yaml.Unmarshal(metadataPropertiesJSON, &metadataProperties); err != nil {
167167
return fmt.Errorf("failed to unmarshal metadata/properties.yaml: %w", err)
168168
}

internal/operator-controller/rukpak/bundle/source/source_test.go

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,18 @@ package source_test
22

33
import (
44
"io/fs"
5-
"strings"
65
"testing"
7-
"testing/fstest"
86

97
"github.com/stretchr/testify/require"
8+
corev1 "k8s.io/api/core/v1"
9+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
"k8s.io/utils/ptr"
11+
12+
"github.com/operator-framework/api/pkg/operators/v1alpha1"
1013

1114
"github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/bundle"
1215
"github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/bundle/source"
13-
. "github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/util/testing"
16+
testutils "github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/util/testing"
1417
)
1518

1619
const (
@@ -27,7 +30,18 @@ func Test_FromBundle_Success(t *testing.T) {
2730
}
2831

2932
func Test_FromFS_Success(t *testing.T) {
30-
rv1, err := source.FromFS(NewBundleFS()).GetBundle()
33+
bundleFS := testutils.BundleFSBuilder().
34+
WithPackageName("test").
35+
WithBundleProperty("from-file-key", "from-file-value").
36+
WithBundleResource("csv.yaml", ptr.To(testutils.MakeCSV(
37+
testutils.WithName("test.v1.0.0"),
38+
testutils.WithAnnotations(map[string]string{
39+
"olm.properties": `[{"type":"from-csv-annotations-key", "value":"from-csv-annotations-value"}]`,
40+
}),
41+
testutils.WithInstallModeSupportFor(v1alpha1.InstallModeTypeAllNamespaces)),
42+
)).Build()
43+
44+
rv1, err := source.FromFS(bundleFS).GetBundle()
3145
require.NoError(t, err)
3246

3347
t.Log("Check package name is correctly taken from metadata/annotations.yaml")
@@ -44,16 +58,30 @@ func Test_FromFS_Fails(t *testing.T) {
4458
}{
4559
{
4660
name: "bundle missing ClusterServiceVersion manifest",
47-
FS: removePaths(NewBundleFS(), BundlePathCSV),
61+
FS: testutils.BundleFSBuilder().
62+
WithPackageName("test").
63+
WithBundleProperty("foo", "bar").
64+
WithBundleResource("service.yaml", &corev1.Service{
65+
TypeMeta: metav1.TypeMeta{
66+
Kind: "Service",
67+
APIVersion: corev1.SchemeGroupVersion.String(),
68+
},
69+
}).Build(),
4870
}, {
4971
name: "bundle missing metadata/annotations.yaml",
50-
FS: removePaths(NewBundleFS(), BundlePathAnnotations),
72+
FS: testutils.BundleFSBuilder().
73+
WithBundleProperty("foo", "bar").
74+
WithBundleResource("csv.yaml", ptr.To(testutils.MakeCSV())).Build(),
5175
}, {
52-
name: "bundle missing metadata/ directory",
53-
FS: removePaths(NewBundleFS(), "metadata/"),
76+
name: "metadata/annotations.yaml missing package name annotation",
77+
FS: testutils.BundleFSBuilder().
78+
WithBundleProperty("foo", "bar").
79+
WithBundleResource("csv.yaml", ptr.To(testutils.MakeCSV())).Build(),
5480
}, {
55-
name: "bundle missing manifests/ directory",
56-
FS: removePaths(NewBundleFS(), "manifests/"),
81+
name: "bundle missing manifests directory",
82+
FS: testutils.BundleFSBuilder().
83+
WithPackageName("test").
84+
WithBundleProperty("foo", "bar").Build(),
5785
},
5886
} {
5987
t.Run(tt.name, func(t *testing.T) {
@@ -62,14 +90,3 @@ func Test_FromFS_Fails(t *testing.T) {
6290
})
6391
}
6492
}
65-
66-
func removePaths(mapFs fstest.MapFS, paths ...string) fstest.MapFS {
67-
for k := range mapFs {
68-
for _, path := range paths {
69-
if strings.HasPrefix(k, path) {
70-
delete(mapFs, k)
71-
}
72-
}
73-
}
74-
return mapFs
75-
}

internal/operator-controller/rukpak/util/testing/bundlefs.go

Lines changed: 121 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,57 +8,138 @@ import (
88

99
"sigs.k8s.io/controller-runtime/pkg/client"
1010
"sigs.k8s.io/yaml"
11+
12+
"github.com/operator-framework/api/pkg/operators/v1alpha1"
13+
"github.com/operator-framework/operator-registry/alpha/property"
14+
15+
"github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/bundle/source"
16+
registry "github.com/operator-framework/operator-controller/internal/operator-controller/rukpak/operator-registry"
1117
)
1218

1319
const (
1420
BundlePathAnnotations = "metadata/annotations.yaml"
1521
BundlePathProperties = "metadata/properties.yaml"
1622
BundlePathManifests = "manifests"
17-
BundlePathCSV = BundlePathManifests + "/csv.yaml"
1823
)
1924

20-
func NewBundleFS() fstest.MapFS {
21-
annotationsYml := `
22-
annotations:
23-
operators.operatorframework.io.bundle.mediatype.v1: registry+v1
24-
operators.operatorframework.io.bundle.package.v1: test
25-
`
26-
27-
propertiesYml := `
28-
properties:
29-
- type: "from-file-key"
30-
value: "from-file-value"
31-
`
32-
33-
csvYml := `
34-
apiVersion: operators.operatorframework.io/v1alpha1
35-
kind: ClusterServiceVersion
36-
metadata:
37-
name: test.v1.0.0
38-
annotations:
39-
olm.properties: '[{"type":"from-csv-annotations-key", "value":"from-csv-annotations-value"}]'
40-
spec:
41-
installModes:
42-
- type: AllNamespaces
43-
supported: true
44-
`
45-
46-
return fstest.MapFS{
47-
BundlePathAnnotations: &fstest.MapFile{Data: []byte(strings.Trim(annotationsYml, "\n"))},
48-
BundlePathProperties: &fstest.MapFile{Data: []byte(strings.Trim(propertiesYml, "\n"))},
49-
BundlePathCSV: &fstest.MapFile{Data: []byte(strings.Trim(csvYml, "\n"))},
25+
// Builder builds a registry+v1 bundle filesystem
26+
type Builder interface {
27+
WithPackageName(packageName string) Builder
28+
WithChannels(channels ...string) Builder
29+
WithDefaultChannel(channel string) Builder
30+
WithBundleProperty(propertyType string, value string) Builder
31+
WithBundleResource(resourceName string, resource client.Object) Builder
32+
WithCSV(csv v1alpha1.ClusterServiceVersion) Builder
33+
Build() fstest.MapFS
34+
}
35+
36+
// bundleFSBuilder builds a registry+v1 bundle filesystem
37+
type bundleFSBuilder struct {
38+
annotations *registry.Annotations
39+
properties []property.Property
40+
resources map[string]client.Object
41+
}
42+
43+
func BundleFSBuilder() Builder {
44+
return &bundleFSBuilder{}
45+
}
46+
47+
// WithPackageName is an option for NewBundleFS used to set the package name annotation in the
48+
// bundle filesystem metadata/annotations.yaml file
49+
func (b *bundleFSBuilder) WithPackageName(packageName string) Builder {
50+
if b.annotations == nil {
51+
b.annotations = &registry.Annotations{}
5052
}
53+
b.annotations.PackageName = packageName
54+
return b
5155
}
5256

53-
func AddManifest(bundleFS fstest.MapFS, obj client.Object) error {
54-
gvk := obj.GetObjectKind().GroupVersionKind()
55-
manifestName := fmt.Sprintf("%s%s_%s_%s%s.yaml", gvk.Group, gvk.Version, gvk.Kind, obj.GetNamespace(), obj.GetName())
56-
bytes, err := yaml.Marshal(obj)
57-
if err != nil {
58-
return err
57+
// WithChannels is an option for NewBundleFS used to set the channels annotation in the
58+
// bundle filesystem metadata/annotations.yaml file
59+
func (b *bundleFSBuilder) WithChannels(channels ...string) Builder {
60+
if b.annotations == nil {
61+
b.annotations = &registry.Annotations{}
5962
}
60-
bundleFS[filepath.Join(BundlePathManifests, manifestName)] = &fstest.MapFile{
61-
Data: bytes,
63+
b.annotations.Channels = strings.Join(channels, ",")
64+
return b
65+
}
66+
67+
// WithDefaultChannel is an option for NewBundleFS used to set the channel annotation in the
68+
// bundle filesystem metadata/annotations.yaml file
69+
func (b *bundleFSBuilder) WithDefaultChannel(channel string) Builder {
70+
if b.annotations == nil {
71+
b.annotations = &registry.Annotations{}
6272
}
63-
return nil
73+
b.annotations.DefaultChannelName = channel
74+
return b
75+
}
76+
77+
// WithBundleProperty is an options for NewBundleFS used to add a property to the list of properties
78+
// in the bundle filesystem metadata/properties.yaml file
79+
func (b *bundleFSBuilder) WithBundleProperty(propertyType string, value string) Builder {
80+
b.properties = append(b.properties, property.Property{
81+
Type: propertyType,
82+
Value: []byte(`"` + value + `"`),
83+
})
84+
return b
85+
}
86+
87+
// WithBundleResource is an option for NewBundleFS use to add the yaml representation of resource to the
88+
// path manifests/<resourceName>.yaml on the bundles filesystem
89+
func (b *bundleFSBuilder) WithBundleResource(resourceName string, resource client.Object) Builder {
90+
if b.resources == nil {
91+
b.resources = make(map[string]client.Object)
92+
}
93+
b.resources[resourceName] = resource
94+
return b
95+
}
96+
97+
// WithCSV is an optiona for NewBundleFS used to add the yaml representation of csv to the
98+
// path manifests/csv.yaml on the bundle filesystem
99+
func (b *bundleFSBuilder) WithCSV(csv v1alpha1.ClusterServiceVersion) Builder {
100+
if b.resources == nil {
101+
b.resources = make(map[string]client.Object)
102+
}
103+
b.resources["csv.yaml"] = &csv
104+
return b
105+
}
106+
107+
// Build creates a registry+v1 bundle filesystem with the applied options
108+
// By default, an empty registry+v1 bundle filesystem will be returned
109+
func (b *bundleFSBuilder) Build() fstest.MapFS {
110+
bundleFS := fstest.MapFS{}
111+
112+
// Add annotations metadata
113+
if b.annotations != nil {
114+
annotationsYml, err := yaml.Marshal(registry.AnnotationsFile{
115+
Annotations: *b.annotations,
116+
})
117+
if err != nil {
118+
panic(fmt.Errorf("error building bundle fs: %w", err))
119+
}
120+
bundleFS[BundlePathAnnotations] = &fstest.MapFile{Data: annotationsYml}
121+
}
122+
123+
// Add property metadata
124+
if len(b.properties) > 0 {
125+
propertiesYml, err := yaml.Marshal(source.RegistryV1Properties{
126+
Properties: b.properties,
127+
})
128+
if err != nil {
129+
panic(fmt.Errorf("error building bundle fs: %w", err))
130+
}
131+
bundleFS[BundlePathProperties] = &fstest.MapFile{Data: propertiesYml}
132+
}
133+
134+
// Add resources
135+
for name, obj := range b.resources {
136+
resourcePath := filepath.Join(BundlePathManifests, name)
137+
resourceYml, err := yaml.Marshal(obj)
138+
if err != nil {
139+
panic(fmt.Errorf("error building bundle fs: %w", err))
140+
}
141+
bundleFS[resourcePath] = &fstest.MapFile{Data: resourceYml}
142+
}
143+
144+
return bundleFS
64145
}

0 commit comments

Comments
 (0)