@@ -4,18 +4,200 @@ import (
4
4
"context"
5
5
"encoding/json"
6
6
"errors"
7
+ "testing"
7
8
9
+ "github.com/google/go-cmp/cmp"
10
+ "github.com/google/go-cmp/cmp/cmpopts"
8
11
. "github.com/onsi/ginkgo/v2"
9
12
. "github.com/onsi/gomega"
10
13
"github.com/operator-framework/deppy/pkg/deppy"
14
+ "github.com/operator-framework/deppy/pkg/deppy/constraint"
15
+ "github.com/operator-framework/deppy/pkg/deppy/input"
11
16
"github.com/operator-framework/operator-registry/alpha/declcfg"
12
17
"github.com/operator-framework/operator-registry/alpha/property"
18
+ "github.com/stretchr/testify/assert"
19
+ "github.com/stretchr/testify/require"
13
20
14
21
"github.com/operator-framework/operator-controller/internal/catalogmetadata"
15
22
olmvariables "github.com/operator-framework/operator-controller/internal/resolution/variables"
16
23
"github.com/operator-framework/operator-controller/internal/resolution/variablesources"
17
24
)
18
25
26
+ func TestMakeBundleVariables_ValidDepedencies (t * testing.T ) {
27
+ const fakeCatalogName = "fake-catalog"
28
+ fakeChannel := catalogmetadata.Channel {Channel : declcfg.Channel {Name : "stable" }}
29
+ bundleSet := map [string ]* catalogmetadata.Bundle {
30
+ // Test package which we will be using as input into
31
+ // the testable function
32
+ "test-package.v1.0.0" : {
33
+ Bundle : declcfg.Bundle {
34
+ Name : "test-package.v1.0.0" ,
35
+ Package : "test-package" ,
36
+ Properties : []property.Property {
37
+ {Type : property .TypePackage , Value : json .RawMessage (`{"packageName": "test-package", "version": "1.0.0"}` )},
38
+ {Type : property .TypePackageRequired , Value : json .RawMessage (`{"packageName": "first-level-dependency", "versionRange": ">=1.0.0 <2.0.0"}` )},
39
+ },
40
+ },
41
+ CatalogName : fakeCatalogName ,
42
+ InChannels : []* catalogmetadata.Channel {& fakeChannel },
43
+ },
44
+
45
+ // First level dependency of test-package. Will be explicitly
46
+ // provided into the testable function as part of variable.
47
+ // This package must have at least one dependency with a version
48
+ // range so we can test that result has correct ordering:
49
+ // the testable function must give priority to newer versions.
50
+ "first-level-dependency.v1.0.0" : {
51
+ Bundle : declcfg.Bundle {
52
+ Name : "first-level-dependency.v1.0.0" ,
53
+ Package : "first-level-dependency" ,
54
+ Properties : []property.Property {
55
+ {Type : property .TypePackage , Value : json .RawMessage (`{"packageName": "first-level-dependency", "version": "1.0.0"}` )},
56
+ {Type : property .TypePackageRequired , Value : json .RawMessage (`{"packageName": "second-level-dependency", "versionRange": ">=1.0.0 <2.0.0"}` )},
57
+ },
58
+ },
59
+ CatalogName : fakeCatalogName ,
60
+ InChannels : []* catalogmetadata.Channel {& fakeChannel },
61
+ },
62
+
63
+ // Second level dependency that matches requirements of the first level dependency.
64
+ "second-level-dependency.v1.0.0" : {
65
+ Bundle : declcfg.Bundle {
66
+ Name : "second-level-dependency.v1.0.0" ,
67
+ Package : "second-level-dependency" ,
68
+ Properties : []property.Property {
69
+ {Type : property .TypePackage , Value : json .RawMessage (`{"packageName": "second-level-dependency", "version": "1.0.0"}` )},
70
+ },
71
+ },
72
+ CatalogName : fakeCatalogName ,
73
+ InChannels : []* catalogmetadata.Channel {& fakeChannel },
74
+ },
75
+
76
+ // Second level dependency that matches requirements of the first level dependency.
77
+ "second-level-dependency.v1.0.1" : {
78
+ Bundle : declcfg.Bundle {
79
+ Name : "second-level-dependency.v1.0.1" ,
80
+ Package : "second-level-dependency" ,
81
+ Properties : []property.Property {
82
+ {Type : property .TypePackage , Value : json .RawMessage (`{"packageName": "second-level-dependency", "version": "1.0.1"}` )},
83
+ },
84
+ },
85
+ CatalogName : fakeCatalogName ,
86
+ InChannels : []* catalogmetadata.Channel {& fakeChannel },
87
+ },
88
+
89
+ // Second level dependency that does not match requirements of the first level dependency.
90
+ "second-level-dependency.v2.0.0" : {
91
+ Bundle : declcfg.Bundle {
92
+ Name : "second-level-dependency.v2.0.0" ,
93
+ Package : "second-level-dependency" ,
94
+ Properties : []property.Property {
95
+ {Type : property .TypePackage , Value : json .RawMessage (`{"packageName": "second-level-dependency", "version": "2.0.0"}` )},
96
+ },
97
+ },
98
+ CatalogName : fakeCatalogName ,
99
+ InChannels : []* catalogmetadata.Channel {& fakeChannel },
100
+ },
101
+
102
+ // Package that is in a our fake catalog, but is not involved
103
+ // in this dependency chain. We need this to make sure that
104
+ // the testable function filters out unrelated bundles.
105
+ "uninvolved-package.v1.0.0" : {
106
+ Bundle : declcfg.Bundle {
107
+ Name : "uninvolved-package.v1.0.0" ,
108
+ Package : "uninvolved-package" ,
109
+ Properties : []property.Property {
110
+ {Type : property .TypePackage , Value : json .RawMessage (`{"packageName": "uninvolved-package", "version": "1.0.0"}` )},
111
+ },
112
+ },
113
+ CatalogName : fakeCatalogName ,
114
+ InChannels : []* catalogmetadata.Channel {& fakeChannel },
115
+ },
116
+ }
117
+
118
+ allBundles := make ([]* catalogmetadata.Bundle , 0 , len (bundleSet ))
119
+ for _ , bundle := range bundleSet {
120
+ allBundles = append (allBundles , bundle )
121
+ }
122
+ requiredPackages := []* olmvariables.RequiredPackageVariable {
123
+ olmvariables .NewRequiredPackageVariable ("test-package" , []* catalogmetadata.Bundle {
124
+ bundleSet ["first-level-dependency.v1.0.0" ],
125
+ }),
126
+ }
127
+ installedPackages := []* olmvariables.InstalledPackageVariable {
128
+ olmvariables .NewInstalledPackageVariable ("test-package" , []* catalogmetadata.Bundle {
129
+ bundleSet ["first-level-dependency.v1.0.0" ],
130
+ }),
131
+ }
132
+
133
+ bundles , err := variablesources .MakeBundleVariables (allBundles , requiredPackages , installedPackages )
134
+ require .NoError (t , err )
135
+
136
+ // Each dependency must have a variable.
137
+ // Dependencies from the same package must be sorted by version
138
+ // with higher versions first.
139
+ expectedVariables := []* olmvariables.BundleVariable {
140
+ olmvariables .NewBundleVariable (
141
+ bundleSet ["first-level-dependency.v1.0.0" ],
142
+ []* catalogmetadata.Bundle {
143
+ bundleSet ["second-level-dependency.v1.0.1" ],
144
+ bundleSet ["second-level-dependency.v1.0.0" ],
145
+ },
146
+ ),
147
+ olmvariables .NewBundleVariable (
148
+ bundleSet ["second-level-dependency.v1.0.1" ],
149
+ nil ,
150
+ ),
151
+ olmvariables .NewBundleVariable (
152
+ bundleSet ["second-level-dependency.v1.0.0" ],
153
+ nil ,
154
+ ),
155
+ }
156
+ gocmpopts := []cmp.Option {
157
+ cmpopts .IgnoreUnexported (catalogmetadata.Bundle {}),
158
+ cmp .AllowUnexported (
159
+ olmvariables.BundleVariable {},
160
+ input.SimpleVariable {},
161
+ constraint.DependencyConstraint {},
162
+ ),
163
+ }
164
+ require .Empty (t , cmp .Diff (bundles , expectedVariables , gocmpopts ... ))
165
+ }
166
+
167
+ func TestMakeBundleVariables_NonExistentDepedencies (t * testing.T ) {
168
+ const fakeCatalogName = "fake-catalog"
169
+ fakeChannel := catalogmetadata.Channel {Channel : declcfg.Channel {Name : "stable" }}
170
+ bundleSet := map [string ]* catalogmetadata.Bundle {
171
+ "test-package.v1.0.0" : {
172
+ Bundle : declcfg.Bundle {
173
+ Name : "test-package.v1.0.0" ,
174
+ Package : "test-package" ,
175
+ Properties : []property.Property {
176
+ {Type : property .TypePackage , Value : json .RawMessage (`{"packageName": "test-package", "version": "1.0.0"}` )},
177
+ {Type : property .TypePackageRequired , Value : json .RawMessage (`{"packageName": "first-level-dependency", "versionRange": ">=1.0.0 <2.0.0"}` )},
178
+ },
179
+ },
180
+ CatalogName : fakeCatalogName ,
181
+ InChannels : []* catalogmetadata.Channel {& fakeChannel },
182
+ },
183
+ }
184
+
185
+ allBundles := make ([]* catalogmetadata.Bundle , 0 , len (bundleSet ))
186
+ for _ , bundle := range bundleSet {
187
+ allBundles = append (allBundles , bundle )
188
+ }
189
+ requiredPackages := []* olmvariables.RequiredPackageVariable {
190
+ olmvariables .NewRequiredPackageVariable ("test-package" , []* catalogmetadata.Bundle {
191
+ bundleSet ["test-package.v1.0.0" ],
192
+ }),
193
+ }
194
+ installedPackages := []* olmvariables.InstalledPackageVariable {}
195
+
196
+ bundles , err := variablesources .MakeBundleVariables (allBundles , requiredPackages , installedPackages )
197
+ assert .ErrorContains (t , err , `could not determine dependencies for bundle with id "fake-catalog-test-package-test-package.v1.0.0"` )
198
+ assert .Nil (t , bundles )
199
+ }
200
+
19
201
var _ = Describe ("BundlesAndDepsVariableSource" , func () {
20
202
var (
21
203
bdvs * variablesources.BundlesAndDepsVariableSource
@@ -368,7 +550,7 @@ var _ = Describe("BundlesAndDepsVariableSource", func() {
368
550
)
369
551
_ , err := bdvs .GetVariables (context .TODO ())
370
552
Expect (err ).To (HaveOccurred ())
371
- Expect (err .Error ()).To (ContainSubstring (" could not determine dependencies for bundle with id ' fake-catalog-test-package-bundle-2' : could not find package dependencies for bundle ' bundle-2'" ))
553
+ Expect (err .Error ()).To (ContainSubstring (` could not determine dependencies for bundle with id " fake-catalog-test-package-bundle-2" : could not find package dependencies for bundle " bundle-2"` ))
372
554
})
373
555
374
556
It ("should return error if an inner variable source returns an error" , func () {
0 commit comments