diff --git a/internal/catalogmetadata/types.go b/internal/catalogmetadata/types.go index d58335f6d..dacca4d03 100644 --- a/internal/catalogmetadata/types.go +++ b/internal/catalogmetadata/types.go @@ -29,22 +29,6 @@ type Channel struct { declcfg.Channel } -type GVK property.GVK - -func (g GVK) String() string { - return fmt.Sprintf(`group:"%s" version:"%s" kind:"%s"`, g.Group, g.Version, g.Kind) -} - -type GVKRequired property.GVKRequired - -func (g GVKRequired) String() string { - return fmt.Sprintf(`group:"%s" version:"%s" kind:"%s"`, g.Group, g.Version, g.Kind) -} - -func (g GVKRequired) AsGVK() GVK { - return GVK(g) -} - type PackageRequired struct { property.PackageRequired SemverRange *bsemver.Range `json:"-"` diff --git a/internal/catalogmetadata/types_test.go b/internal/catalogmetadata/types_test.go index b930802e1..cc612d105 100644 --- a/internal/catalogmetadata/types_test.go +++ b/internal/catalogmetadata/types_test.go @@ -2,6 +2,7 @@ package catalogmetadata_test import ( "encoding/json" + "fmt" "testing" bsemver "github.com/blang/semver/v4" @@ -13,62 +14,176 @@ import ( "github.com/operator-framework/operator-controller/internal/catalogmetadata" ) -func TestGVK(t *testing.T) { - t.Run("String", func(t *testing.T) { - gvk := catalogmetadata.GVK{Group: "bar.io", Kind: "Bar", Version: "v1"} - - assert.Equal(t, `group:"bar.io" version:"v1" kind:"Bar"`, gvk.String()) - }) -} - -func TestGVKRequired(t *testing.T) { - t.Run("String", func(t *testing.T) { - gvk := catalogmetadata.GVKRequired{Group: "bar.io", Kind: "Bar", Version: "v1"} - - assert.Equal(t, `group:"bar.io" version:"v1" kind:"Bar"`, gvk.String()) - }) - - t.Run("AsGVK", func(t *testing.T) { - gvk := catalogmetadata.GVKRequired{Group: "bar.io", Kind: "Bar", Version: "v1"} - - assert.Equal(t, catalogmetadata.GVK{Group: "bar.io", Kind: "Bar", Version: "v1"}, gvk.AsGVK()) - }) +func TestBundleVersion(t *testing.T) { + for _, tt := range []struct { + name string + bundle *catalogmetadata.Bundle + wantVersion *bsemver.Version + wantErr string + }{ + { + name: "valid version", + bundle: &catalogmetadata.Bundle{Bundle: declcfg.Bundle{ + Name: "fake-bundle.v1", + Properties: []property.Property{ + { + Type: property.TypePackage, + Value: json.RawMessage(`{"packageName": "package1", "version": "1.0.0"}`), + }, + }, + }}, + wantVersion: &bsemver.Version{Major: 1}, + }, + { + name: "invalid version", + bundle: &catalogmetadata.Bundle{Bundle: declcfg.Bundle{ + Name: "fake-bundle.invalidVersion", + Properties: []property.Property{ + { + Type: property.TypePackage, + Value: json.RawMessage(`{"packageName": "package1", "version": "broken"}`), + }, + }, + }}, + wantVersion: nil, + wantErr: `could not parse semver "broken" for bundle 'fake-bundle.invalidVersion': No Major.Minor.Patch elements found`, + }, + { + name: "not found", + bundle: &catalogmetadata.Bundle{Bundle: declcfg.Bundle{ + Name: "fake-bundle.noVersion", + }}, + wantVersion: nil, + wantErr: `bundle property with type "olm.package" not found`, + }, + } { + t.Run(tt.name, func(t *testing.T) { + version, err := tt.bundle.Version() + assert.Equal(t, tt.wantVersion, version) + if tt.wantErr != "" { + assert.EqualError(t, err, tt.wantErr) + } else { + assert.NoError(t, err) + } + }) + } } -func TestBundle(t *testing.T) { - t.Run("Version", func(t *testing.T) { - validVersion := &catalogmetadata.Bundle{Bundle: declcfg.Bundle{ - Name: "fake-bundle.v1", - Properties: []property.Property{ - { - Type: property.TypePackage, - Value: json.RawMessage(`{"packageName": "package1", "version": "1.0.0"}`), +func TestBundleRequiredPackages(t *testing.T) { + for _, tt := range []struct { + name string + bundle *catalogmetadata.Bundle + wantRequiredPackages []catalogmetadata.PackageRequired + wantErr string + }{ + { + name: "valid package requirements", + bundle: &catalogmetadata.Bundle{Bundle: declcfg.Bundle{ + Name: "fake-bundle.v1", + Properties: []property.Property{ + { + Type: property.TypePackageRequired, + Value: json.RawMessage(`[{"packageName": "packageA", "versionRange": ">1.0.0"}, {"packageName": "packageB", "versionRange": ">0.5.0 <0.8.6"}]`), + }, }, + }}, + wantRequiredPackages: []catalogmetadata.PackageRequired{ + {PackageRequired: property.PackageRequired{PackageName: "packageA", VersionRange: ">1.0.0"}}, + {PackageRequired: property.PackageRequired{PackageName: "packageB", VersionRange: ">0.5.0 <0.8.6"}}, }, - }} - invalidVersion := &catalogmetadata.Bundle{Bundle: declcfg.Bundle{ - Name: "fake-bundle.invalid", - Properties: []property.Property{ - { - Type: property.TypePackage, - Value: json.RawMessage(`{"packageName": "package1", "version": "broken"}`), + }, + { + name: "bad package requirement", + bundle: &catalogmetadata.Bundle{Bundle: declcfg.Bundle{ + Name: "fake-bundle.badPackageRequirement", + Properties: []property.Property{ + { + Type: property.TypePackageRequired, + Value: json.RawMessage(`badRequiredPackageStructure`), + }, }, - }, - }} - noVersion := &catalogmetadata.Bundle{Bundle: declcfg.Bundle{ - Name: "fake-bundle.noVersion", - }} - - ver, err := validVersion.Version() - assert.NoError(t, err) - assert.Equal(t, &bsemver.Version{Major: 1}, ver) - - ver, err = invalidVersion.Version() - assert.EqualError(t, err, "could not parse semver \"broken\" for bundle 'fake-bundle.invalid': No Major.Minor.Patch elements found") - assert.Nil(t, ver) + }}, + wantRequiredPackages: nil, + wantErr: `error determining bundle required packages for bundle "fake-bundle.badPackageRequirement": property "olm.package.required" with value "badRequiredPackageStructure" could not be parsed: invalid character 'b' looking for beginning of value`, + }, + { + name: "invalid version range", + bundle: &catalogmetadata.Bundle{Bundle: declcfg.Bundle{ + Name: "fake-bundle.badVersionRange", + Properties: []property.Property{ + { + Type: property.TypePackageRequired, + Value: json.RawMessage(`[{"packageName": "packageA", "versionRange": "invalid"}]`), + }, + }, + }}, + wantRequiredPackages: nil, + wantErr: `error parsing bundle required package semver range for bundle "fake-bundle.badVersionRange" (required package "packageA"): Could not get version from string: "invalid"`, + }, + } { + t.Run(tt.name, func(t *testing.T) { + packages, err := tt.bundle.RequiredPackages() + assert.Equal(t, tt.wantRequiredPackages, packages) + if tt.wantErr != "" { + assert.EqualError(t, err, tt.wantErr) + } else { + assert.NoError(t, err) + } + }) + } +} - ver, err = noVersion.Version() - assert.EqualError(t, err, "bundle property with type \"olm.package\" not found") - assert.Nil(t, ver) - }) +func TestBundleMediaType(t *testing.T) { + for _, tt := range []struct { + name string + bundle *catalogmetadata.Bundle + wantMediaType string + wantErr string + }{ + { + name: "valid mediatype property", + bundle: &catalogmetadata.Bundle{Bundle: declcfg.Bundle{ + Name: "fake-bundle.v1", + Properties: []property.Property{ + { + Type: catalogmetadata.PropertyBundleMediaType, + Value: json.RawMessage(fmt.Sprintf(`"%s"`, catalogmetadata.MediaTypePlain)), + }, + }, + }}, + wantMediaType: catalogmetadata.MediaTypePlain, + }, + { + name: "no media type provided", + bundle: &catalogmetadata.Bundle{Bundle: declcfg.Bundle{ + Name: "fake-bundle.noMediaType", + Properties: []property.Property{}, + }}, + wantMediaType: "", + }, + { + name: "malformed media type", + bundle: &catalogmetadata.Bundle{Bundle: declcfg.Bundle{ + Name: "fake-bundle.badMediaType", + Properties: []property.Property{ + { + Type: catalogmetadata.PropertyBundleMediaType, + Value: json.RawMessage("badtype"), + }, + }, + }}, + wantMediaType: "", + wantErr: `error determining bundle mediatype for bundle "fake-bundle.badMediaType": property "olm.bundle.mediatype" with value "badtype" could not be parsed: invalid character 'b' looking for beginning of value`, + }, + } { + t.Run(tt.name, func(t *testing.T) { + mediaType, err := tt.bundle.MediaType() + assert.Equal(t, tt.wantMediaType, mediaType) + if tt.wantErr != "" { + assert.EqualError(t, err, tt.wantErr) + } else { + assert.NoError(t, err) + } + }) + } }