Skip to content

Commit d3dd487

Browse files
committed
Fix tests, bump catalogd, address comments.
Signed-off-by: dtfranz <[email protected]>
1 parent 19bd853 commit d3dd487

20 files changed

+983
-673
lines changed

cmd/resolutioncli/main.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -151,24 +151,24 @@ func resolve(ctx context.Context, resolver *solver.DeppySolver, packageName stri
151151
return "", err
152152
}
153153

154-
bundleEntity, err := getBundleEntityFromSolution(solution, packageName)
154+
bundle, err := bundleFromSolution(solution, packageName)
155155
if err != nil {
156156
return "", err
157157
}
158158

159159
// Get the bundle image reference for the bundle
160-
return bundleEntity.Image, nil
160+
return bundle.Image, nil
161161
}
162162

163-
func getBundleEntityFromSolution(solution *solver.Solution, packageName string) (*catalogmetadata.Bundle, error) {
163+
func bundleFromSolution(solution *solver.Solution, packageName string) (*catalogmetadata.Bundle, error) {
164164
for _, variable := range solution.SelectedVariables() {
165165
switch v := variable.(type) {
166166
case *olmvariables.BundleVariable:
167-
entityPkgName := v.BundleEntity().Package
168-
if packageName == entityPkgName {
169-
return v.BundleEntity(), nil
167+
bundlePkgName := v.Bundle().Package
168+
if packageName == bundlePkgName {
169+
return v.Bundle(), nil
170170
}
171171
}
172172
}
173-
return nil, fmt.Errorf("entity for package %q not found in solution", packageName)
173+
return nil, fmt.Errorf("bundle for package %q not found in solution", packageName)
174174
}

internal/catalogmetadata/types_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,13 @@ func TestBundleRequiredPackages(t *testing.T) {
123123
} {
124124
t.Run(tt.name, func(t *testing.T) {
125125
packages, err := tt.bundle.RequiredPackages()
126-
assert.Equal(t, tt.wantRequiredPackages, packages)
126+
assert.Equal(t, len(tt.wantRequiredPackages), len(packages))
127+
for i, pkg := range packages {
128+
// Must custom compare due to Semver function type
129+
assert.Equal(t, tt.wantRequiredPackages[i].PackageRequired, pkg.PackageRequired)
130+
assert.Equal(t, tt.wantRequiredPackages[i].PackageName, pkg.PackageName)
131+
assert.Equal(t, tt.wantRequiredPackages[i].VersionRange, pkg.VersionRange)
132+
}
127133
if tt.wantErr != "" {
128134
assert.EqualError(t, err, tt.wantErr)
129135
} else {

internal/controllers/operator_controller.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,9 @@ func (r *OperatorReconciler) reconcile(ctx context.Context, op *operatorsv1alpha
154154
return ctrl.Result{}, unsat
155155
}
156156

157-
// lookup the bundle entity in the solution that corresponds to the
157+
// lookup the bundle in the solution that corresponds to the
158158
// Operator's desired package name.
159-
bundleEntity, err := r.getBundleEntityFromSolution(solution, op.Spec.PackageName)
159+
bundle, err := r.bundleFromSolution(solution, op.Spec.PackageName)
160160
if err != nil {
161161
op.Status.InstalledBundleResource = ""
162162
setInstalledStatusConditionUnknown(&op.Status.Conditions, "installation has not been attempted as resolution failed", op.GetGeneration())
@@ -165,11 +165,11 @@ func (r *OperatorReconciler) reconcile(ctx context.Context, op *operatorsv1alpha
165165
return ctrl.Result{}, err
166166
}
167167

168-
// Now we can set the Resolved Condition, and the resolvedBundleSource field to the bundleEntity.Image value.
169-
op.Status.ResolvedBundleResource = bundleEntity.Image
170-
setResolvedStatusConditionSuccess(&op.Status.Conditions, fmt.Sprintf("resolved to %q", bundleEntity.Image), op.GetGeneration())
168+
// Now we can set the Resolved Condition, and the resolvedBundleSource field to the bundle.Image value.
169+
op.Status.ResolvedBundleResource = bundle.Image
170+
setResolvedStatusConditionSuccess(&op.Status.Conditions, fmt.Sprintf("resolved to %q", bundle.Image), op.GetGeneration())
171171

172-
mediaType, err := bundleEntity.MediaType()
172+
mediaType, err := bundle.MediaType()
173173
if err != nil {
174174
setInstalledStatusConditionFailed(&op.Status.Conditions, err.Error(), op.GetGeneration())
175175
return ctrl.Result{}, err
@@ -181,7 +181,7 @@ func (r *OperatorReconciler) reconcile(ctx context.Context, op *operatorsv1alpha
181181
}
182182
// Ensure a BundleDeployment exists with its bundle source from the bundle
183183
// image we just looked up in the solution.
184-
dep := r.generateExpectedBundleDeployment(*op, bundleEntity.Image, bundleProvisioner)
184+
dep := r.generateExpectedBundleDeployment(*op, bundle.Image, bundleProvisioner)
185185
if err := r.ensureBundleDeployment(ctx, dep); err != nil {
186186
// originally Reason: operatorsv1alpha1.ReasonInstallationFailed
187187
op.Status.InstalledBundleResource = ""
@@ -251,17 +251,17 @@ func mapBDStatusToInstalledCondition(existingTypedBundleDeployment *rukpakv1alph
251251
}
252252
}
253253

254-
func (r *OperatorReconciler) getBundleEntityFromSolution(solution *solver.Solution, packageName string) (*catalogmetadata.Bundle, error) {
254+
func (r *OperatorReconciler) bundleFromSolution(solution *solver.Solution, packageName string) (*catalogmetadata.Bundle, error) {
255255
for _, variable := range solution.SelectedVariables() {
256256
switch v := variable.(type) {
257257
case *olmvariables.BundleVariable:
258-
entityPkgName := v.BundleEntity().Package
259-
if packageName == entityPkgName {
260-
return v.BundleEntity(), nil
258+
bundlePkgName := v.Bundle().Package
259+
if packageName == bundlePkgName {
260+
return v.Bundle(), nil
261261
}
262262
}
263263
}
264-
return nil, fmt.Errorf("entity for package %q not found in solution", packageName)
264+
return nil, fmt.Errorf("bundle for package %q not found in solution", packageName)
265265
}
266266

267267
func (r *OperatorReconciler) generateExpectedBundleDeployment(o operatorsv1alpha1.Operator, bundlePath string, bundleProvisioner string) *unstructured.Unstructured {

internal/controllers/operator_controller_test.go

Lines changed: 69 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ package controllers_test
22

33
import (
44
"context"
5+
"encoding/json"
56
"fmt"
67

78
. "github.com/onsi/ginkgo/v2"
89
. "github.com/onsi/gomega"
9-
"github.com/operator-framework/deppy/pkg/deppy"
10-
"github.com/operator-framework/deppy/pkg/deppy/input"
1110
"github.com/operator-framework/deppy/pkg/deppy/solver"
11+
"github.com/operator-framework/operator-registry/alpha/declcfg"
12+
"github.com/operator-framework/operator-registry/alpha/property"
1213
rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1"
1314
apimeta "k8s.io/apimachinery/pkg/api/meta"
1415
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -20,21 +21,25 @@ import (
2021
"sigs.k8s.io/controller-runtime/pkg/client/fake"
2122

2223
operatorsv1alpha1 "github.com/operator-framework/operator-controller/api/v1alpha1"
24+
"github.com/operator-framework/operator-controller/internal/catalogmetadata"
2325
"github.com/operator-framework/operator-controller/internal/conditionsets"
2426
"github.com/operator-framework/operator-controller/internal/controllers"
27+
testutil "github.com/operator-framework/operator-controller/test/util"
2528
)
2629

2730
var _ = Describe("Operator Controller Test", func() {
2831
var (
29-
ctx context.Context
30-
reconciler *controllers.OperatorReconciler
32+
ctx context.Context
33+
fakeCatalogClient testutil.FakeCatalogClient
34+
reconciler *controllers.OperatorReconciler
3135
)
3236
BeforeEach(func() {
3337
ctx = context.Background()
38+
fakeCatalogClient = testutil.NewFakeCatalogClient(testBundleList)
3439
reconciler = &controllers.OperatorReconciler{
3540
Client: cl,
3641
Scheme: sch,
37-
Resolver: solver.NewDeppySolver(testEntitySource, controllers.NewVariableSource(cl)),
42+
Resolver: solver.NewDeppySolver(controllers.NewVariableSource(cl, &fakeCatalogClient)),
3843
}
3944
})
4045
When("the operator does not exist", func() {
@@ -575,43 +580,6 @@ var _ = Describe("Operator Controller Test", func() {
575580
})
576581
})
577582
})
578-
When("the selected bundle's image ref cannot be parsed", func() {
579-
const pkgName = "badimage"
580-
BeforeEach(func() {
581-
By("initializing cluster state")
582-
operator = &operatorsv1alpha1.Operator{
583-
ObjectMeta: metav1.ObjectMeta{Name: opKey.Name},
584-
Spec: operatorsv1alpha1.OperatorSpec{PackageName: pkgName},
585-
}
586-
err := cl.Create(ctx, operator)
587-
Expect(err).NotTo(HaveOccurred())
588-
})
589-
It("sets resolution failure status and returns an error", func() {
590-
By("running reconcile")
591-
res, err := reconciler.Reconcile(ctx, ctrl.Request{NamespacedName: opKey})
592-
Expect(res).To(Equal(ctrl.Result{}))
593-
Expect(err).To(MatchError(ContainSubstring(`error determining bundle path for entity`)))
594-
595-
By("fetching updated operator after reconcile")
596-
Expect(cl.Get(ctx, opKey, operator)).NotTo(HaveOccurred())
597-
598-
By("Checking the status fields")
599-
Expect(operator.Status.ResolvedBundleResource).To(Equal(""))
600-
Expect(operator.Status.InstalledBundleResource).To(Equal(""))
601-
602-
By("checking the expected conditions")
603-
cond := apimeta.FindStatusCondition(operator.Status.Conditions, operatorsv1alpha1.TypeResolved)
604-
Expect(cond).NotTo(BeNil())
605-
Expect(cond.Status).To(Equal(metav1.ConditionFalse))
606-
Expect(cond.Reason).To(Equal(operatorsv1alpha1.ReasonResolutionFailed))
607-
Expect(cond.Message).To(ContainSubstring(`error determining bundle path for entity`))
608-
cond = apimeta.FindStatusCondition(operator.Status.Conditions, operatorsv1alpha1.TypeInstalled)
609-
Expect(cond).NotTo(BeNil())
610-
Expect(cond.Status).To(Equal(metav1.ConditionUnknown))
611-
Expect(cond.Reason).To(Equal(operatorsv1alpha1.ReasonInstallationStatusUnknown))
612-
Expect(cond.Message).To(Equal("installation has not been attempted as resolution failed"))
613-
})
614-
})
615583
When("the operator specifies a duplicate package", func() {
616584
const pkgName = "prometheus"
617585
var dupOperator *operatorsv1alpha1.Operator
@@ -1080,41 +1048,62 @@ func verifyConditionsInvariants(op *operatorsv1alpha1.Operator) {
10801048
}
10811049
}
10821050

1083-
var testEntitySource = input.NewCacheQuerier(map[deppy.Identifier]input.Entity{
1084-
"operatorhub/prometheus/0.37.0": *input.NewEntity("operatorhub/prometheus/0.37.0", map[string]string{
1085-
"olm.bundle.path": `"quay.io/operatorhubio/prometheus@sha256:3e281e587de3d03011440685fc4fb782672beab044c1ebadc42788ce05a21c35"`,
1086-
"olm.bundle.channelEntry": `{"name":"prometheus.0.37.0"}`,
1087-
"olm.channel": `{"channelName":"beta","priority":0}`,
1088-
"olm.package": `{"packageName":"prometheus","version":"0.37.0"}`,
1089-
"olm.gvk": `[]`,
1090-
}),
1091-
"operatorhub/prometheus/0.47.0": *input.NewEntity("operatorhub/prometheus/0.47.0", map[string]string{
1092-
"olm.bundle.path": `"quay.io/operatorhubio/prometheus@sha256:5b04c49d8d3eff6a338b56ec90bdf491d501fe301c9cdfb740e5bff6769a21ed"`,
1093-
"olm.bundle.channelEntry": `{"name":"prometheus.0.47.0"}`,
1094-
"olm.channel": `{"channelName":"beta","priority":0,"replaces":"prometheusoperator.0.37.0"}`,
1095-
"olm.package": `{"packageName":"prometheus","version":"0.47.0"}`,
1096-
"olm.gvk": `[]`,
1097-
}),
1098-
"operatorhub/badimage/0.1.0": *input.NewEntity("operatorhub/badimage/0.1.0", map[string]string{
1099-
"olm.bundle.path": `{"name": "quay.io/operatorhubio/badimage:v0.1.0"}`,
1100-
"olm.bundle.channelEntry": `{"name":"badimage.0.1.0"}`,
1101-
"olm.package": `{"packageName":"badimage","version":"0.1.0"}`,
1102-
"olm.gvk": `[]`,
1103-
}),
1104-
"operatorhub/plain/0.1.0": *input.NewEntity("operatorhub/plain/0.1.0", map[string]string{
1105-
"olm.bundle.path": `"quay.io/operatorhub/plain@sha256:plain"`,
1106-
"olm.bundle.channelEntry": `{"name":"plain.0.1.0"}`,
1107-
"olm.channel": `{"channelName":"beta","priority":0}`,
1108-
"olm.package": `{"packageName":"plain","version":"0.1.0"}`,
1109-
"olm.gvk": `[]`,
1110-
"olm.bundle.mediatype": `"plain+v0"`,
1111-
}),
1112-
"operatorhub/badmedia/0.1.0": *input.NewEntity("operatorhub/badmedia/0.1.0", map[string]string{
1113-
"olm.bundle.path": `"quay.io/operatorhub/badmedia@sha256:badmedia"`,
1114-
"olm.bundle.channelEntry": `{"name":"badmedia.0.1.0"}`,
1115-
"olm.channel": `{"channelName":"beta","priority":0}`,
1116-
"olm.package": `{"packageName":"badmedia","version":"0.1.0"}`,
1117-
"olm.gvk": `[]`,
1118-
"olm.bundle.mediatype": `"badmedia+v1"`,
1119-
}),
1120-
})
1051+
var betaChannel = catalogmetadata.Channel{Channel: declcfg.Channel{
1052+
Name: "beta",
1053+
Entries: []declcfg.ChannelEntry{
1054+
{
1055+
Name: "operatorhub/prometheus/0.37.0",
1056+
},
1057+
{
1058+
Name: "operatorhub/prometheus/0.47.0",
1059+
Replaces: "operatorhub/prometheus/0.37.0",
1060+
},
1061+
{
1062+
Name: "operatorhub/plain/0.1.0",
1063+
},
1064+
{
1065+
Name: "operatorhub/badmedia/0.1.0",
1066+
},
1067+
},
1068+
}}
1069+
1070+
var testBundleList = []*catalogmetadata.Bundle{
1071+
{Bundle: declcfg.Bundle{
1072+
Name: "operatorhub/prometheus/0.37.0",
1073+
Package: "prometheus",
1074+
Image: "quay.io/operatorhubio/prometheus@sha256:3e281e587de3d03011440685fc4fb782672beab044c1ebadc42788ce05a21c35",
1075+
Properties: []property.Property{
1076+
{Type: property.TypePackage, Value: json.RawMessage(`{"packageName":"prometheus","version":"0.37.0"}`)},
1077+
{Type: property.TypeGVK, Value: json.RawMessage(`[]`)},
1078+
},
1079+
}, InChannels: []*catalogmetadata.Channel{&betaChannel}},
1080+
{Bundle: declcfg.Bundle{
1081+
Name: "operatorhub/prometheus/0.47.0",
1082+
Package: "prometheus",
1083+
Image: "quay.io/operatorhubio/prometheus@sha256:5b04c49d8d3eff6a338b56ec90bdf491d501fe301c9cdfb740e5bff6769a21ed",
1084+
Properties: []property.Property{
1085+
{Type: property.TypePackage, Value: json.RawMessage(`{"packageName":"prometheus","version":"0.47.0"}`)},
1086+
{Type: property.TypeGVK, Value: json.RawMessage(`[]`)},
1087+
},
1088+
}, InChannels: []*catalogmetadata.Channel{&betaChannel}},
1089+
{Bundle: declcfg.Bundle{
1090+
Name: "operatorhub/plain/0.1.0",
1091+
Package: "plain",
1092+
Image: "quay.io/operatorhub/plain@sha256:plain",
1093+
Properties: []property.Property{
1094+
{Type: property.TypePackage, Value: json.RawMessage(`{"packageName":"plain","version":"0.1.0"}`)},
1095+
{Type: property.TypeGVK, Value: json.RawMessage(`[]`)},
1096+
{Type: "olm.bundle.mediatype", Value: json.RawMessage(`"plain+v0"`)},
1097+
},
1098+
}, InChannels: []*catalogmetadata.Channel{&betaChannel}},
1099+
{Bundle: declcfg.Bundle{
1100+
Name: "operatorhub/badmedia/0.1.0",
1101+
Package: "badmedia",
1102+
Image: "quay.io/operatorhub/badmedia@sha256:badmedia",
1103+
Properties: []property.Property{
1104+
{Type: property.TypePackage, Value: json.RawMessage(`{"packageName":"badmedia","version":"0.1.0"}`)},
1105+
{Type: property.TypeGVK, Value: json.RawMessage(`[]`)},
1106+
{Type: "olm.bundle.mediatype", Value: json.RawMessage(`"badmedia+v1"`)},
1107+
},
1108+
}, InChannels: []*catalogmetadata.Channel{&betaChannel}},
1109+
}

internal/resolution/variables/bundle.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ type BundleVariable struct {
1818
dependencies []*catalogmetadata.Bundle
1919
}
2020

21-
func (b *BundleVariable) BundleEntity() *catalogmetadata.Bundle {
21+
func (b *BundleVariable) Bundle() *catalogmetadata.Bundle {
2222
return b.bundle
2323
}
2424

internal/resolution/variables/bundle_test.go

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,55 @@
11
package variables_test
22

33
import (
4+
"encoding/json"
45
"testing"
56

67
"github.com/operator-framework/deppy/pkg/deppy"
78
"github.com/operator-framework/deppy/pkg/deppy/constraint"
8-
"github.com/operator-framework/deppy/pkg/deppy/input"
9+
"github.com/operator-framework/operator-registry/alpha/declcfg"
910
"github.com/operator-framework/operator-registry/alpha/property"
1011

11-
olmentity "github.com/operator-framework/operator-controller/internal/resolution/entities"
12+
"github.com/operator-framework/operator-controller/internal/catalogmetadata"
1213
olmvariables "github.com/operator-framework/operator-controller/internal/resolution/variables"
1314
)
1415

1516
func TestBundleVariable(t *testing.T) {
16-
bundleEntity := olmentity.NewBundleEntity(input.NewEntity("bundle-1", map[string]string{
17-
property.TypePackage: `{"packageName": "test-package", "version": "1.0.0"}`,
18-
property.TypeChannel: `{"channelName":"stable","priority":0}`,
19-
}))
20-
dependencies := []*olmentity.BundleEntity{
21-
olmentity.NewBundleEntity(input.NewEntity("bundle-2", map[string]string{
22-
property.TypePackage: `{"packageName": "test-package-2", "version": "2.0.0"}`,
23-
property.TypeChannel: `{"channelName":"stable","priority":0}`,
24-
})),
25-
olmentity.NewBundleEntity(input.NewEntity("bundle-3", map[string]string{
26-
property.TypePackage: `{"packageName": "test-package-3", "version": "2.0.0"}`,
27-
property.TypeChannel: `{"channelName":"stable","priority":0}`,
28-
})),
29-
}
30-
bv := olmvariables.NewBundleVariable(bundleEntity, dependencies)
31-
32-
if bv.BundleEntity() != bundleEntity {
33-
t.Errorf("bundle entity '%v' does not match expected '%v'", bv.BundleEntity(), bundleEntity)
17+
bundle := &catalogmetadata.Bundle{
18+
InChannels: []*catalogmetadata.Channel{
19+
{Channel: declcfg.Channel{Name: "stable"}},
20+
},
21+
Bundle: declcfg.Bundle{Name: "bundle-1", Properties: []property.Property{
22+
{Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package", "version": "1.0.0"}`)},
23+
}},
3424
}
25+
dependencies := []*catalogmetadata.Bundle{
26+
{
27+
InChannels: []*catalogmetadata.Channel{
28+
{Channel: declcfg.Channel{Name: "stable"}},
29+
},
30+
Bundle: declcfg.Bundle{Name: "bundle-2", Properties: []property.Property{
31+
{Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package", "version": "2.0.0"}`)},
32+
}},
33+
},
34+
{
35+
InChannels: []*catalogmetadata.Channel{
36+
{Channel: declcfg.Channel{Name: "stable"}},
37+
},
38+
Bundle: declcfg.Bundle{Name: "bundle-3", Properties: []property.Property{
39+
{Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package", "version": "3.0.0"}`)},
40+
}},
41+
},
42+
}
43+
ids := olmvariables.BundleToBundleVariableIDs(bundle)
44+
if len(ids) != len(bundle.InChannels) {
45+
t.Fatalf("bundle should produce one variable ID per channel; received: %d", len(bundle.InChannels))
46+
}
47+
bv := olmvariables.NewBundleVariable(ids[0], bundle, dependencies)
48+
49+
if bv.Bundle() != bundle {
50+
t.Errorf("bundle '%v' does not match expected '%v'", bv.Bundle(), bundle)
51+
}
52+
3553
for i, d := range bv.Dependencies() {
3654
if d != dependencies[i] {
3755
t.Errorf("dependency[%v] '%v' does not match expected '%v'", i, d, dependencies[i])

internal/resolution/variables/installed_package.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ type InstalledPackageVariable struct {
1717
bundles []*catalogmetadata.Bundle
1818
}
1919

20-
func (r *InstalledPackageVariable) BundleEntities() []*catalogmetadata.Bundle {
20+
func (r *InstalledPackageVariable) Bundles() []*catalogmetadata.Bundle {
2121
return r.bundles
2222
}
2323

0 commit comments

Comments
 (0)