package internal import ( "os" "testing" "github.com/operator-framework/api/pkg/manifests" "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/stretchr/testify/require" ) func TestValidateBundleOperatorHub(t *testing.T) { var table = []struct { description string directory string hasError bool errStrings []string }{ { description: "registryv1 bundle/valid bundle", directory: "./testdata/valid_bundle", hasError: false, }, { description: "registryv1 bundle/invald bundle operatorhubio", directory: "./testdata/invalid_bundle_operatorhub", hasError: true, errStrings: []string{ `Error: Value : (etcdoperator.v0.9.4) csv.Spec.Provider.Name not specified`, `Error: Value : (etcdoperator.v0.9.4) csv.Spec.Maintainers elements should contain both name and email`, `Error: Value : (etcdoperator.v0.9.4) csv.Spec.Maintainers email invalidemail is invalid: mail: missing '@' or angle-addr`, `Error: Value : (etcdoperator.v0.9.4) csv.Spec.Links elements should contain both name and url`, `Error: Value : (etcdoperator.v0.9.4) csv.Spec.Links url https//coreos.com/operators/etcd/docs/latest/ is invalid: parse "https//coreos.com/operators/etcd/docs/latest/": invalid URI for request`, `Error: Value : (etcdoperator.v0.9.4) csv.Metadata.Annotations.Capabilities Installs and stuff is not a valid capabilities level`, `Error: Value : (etcdoperator.v0.9.4) csv.Spec.Icon should only have one element`, `Error: Value : (etcdoperator.v0.9.4) csv.Metadata.Annotations["categories"] value Magic is not in the set of default categories`, `Error: Value : (etcdoperator.v0.9.4) csv.Spec.Version must be set`, }, }, } for _, tt := range table { // Validate the bundle object bundle, err := manifests.GetBundleFromDir(tt.directory) require.NoError(t, err) results := OperatorHubValidator.Validate(bundle) if len(results) > 0 { require.Equal(t, results[0].HasError(), tt.hasError) if results[0].HasError() { require.Equal(t, len(tt.errStrings), len(results[0].Errors)) for _, err := range results[0].Errors { errString := err.Error() require.Contains(t, tt.errStrings, errString) } } } } } func TestCustomCategories(t *testing.T) { var table = []struct { description string directory string hasError bool errStrings []string custom bool }{ { description: "valid bundle custom categories", directory: "./testdata/valid_bundle_custom_categories", hasError: false, custom: true, }, { description: "valid bundle standard categories", directory: "./testdata/valid_bundle", hasError: false, custom: false, }, } for _, tt := range table { if tt.custom { os.Setenv("OPERATOR_BUNDLE_CATEGORIES", "./testdata/categories.json") } else { os.Setenv("OPERATOR_BUNDLE_CATEGORIES", "") } // Validate the bundle object bundle, err := manifests.GetBundleFromDir(tt.directory) require.NoError(t, err) results := OperatorHubValidator.Validate(bundle) if len(results) > 0 { require.Equal(t, results[0].HasError(), tt.hasError) if results[0].HasError() { require.Equal(t, len(tt.errStrings), len(results[0].Errors)) for _, err := range results[0].Errors { errString := err.Error() require.Contains(t, tt.errStrings, errString) } } } } } func TestExtractCategories(t *testing.T) { path := "./testdata/categories.json" categories, err := extractCategories(path) if err != nil { t.Fatalf("extracting categories.json: %s", err) } expected := map[string]struct{}{ "Cloud Pak": {}, "Registry": {}, "MyCoolThing": {}, "This/Or & That": {}, } for key := range categories { if _, ok := expected[key]; !ok { t.Fatalf("did not find key %s", key) } } } func TestCheckSpecIcon(t *testing.T) { validIcon := v1alpha1.Icon{ Data: "iVBORw0KGgoAAAANSUhEUgAAAOEAAADZCAYAAADWmle6AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAGXRFWHRTb2Z0d2Fy", MediaType: "image/png", } invalidIcon := v1alpha1.Icon{ MediaType: "image/png", } invalidMediaTypeIcon := validIcon invalidMediaTypeIcon.MediaType = "invalid" type args struct { icon []v1alpha1.Icon } tests := []struct { name string args args wantError bool wantWarning bool errStrings []string warnStrings []string }{ { name: "should work with a valid value", args: args{icon: []v1alpha1.Icon{validIcon}}, }, { name: "should return an warning when the icon is not provided", wantWarning: true, warnStrings: []string{"csv.Spec.Icon not specified"}, }, { name: "should fail when the data informed for the icon is invalid", args: args{icon: []v1alpha1.Icon{invalidIcon}}, wantError: true, errStrings: []string{"csv.Spec.Icon elements should contain both data and mediatype"}, }, { name: "should fail when the data informed has not a valid MediaType", args: args{icon: []v1alpha1.Icon{invalidMediaTypeIcon}}, wantError: true, errStrings: []string{"csv.Spec.Icon invalid does not have a valid mediatype"}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { csv := v1alpha1.ClusterServiceVersion{} csv.Spec.Icon = tt.args.icon checks := CSVChecks{csv: csv, errs: []error{}, warns: []error{}} result := checkSpecIcon(checks) require.Equal(t, tt.wantWarning, len(result.warns) > 0) if tt.wantWarning { require.Equal(t, len(tt.warnStrings), len(result.warns)) for _, w := range result.warns { wString := w.Error() require.Contains(t, tt.warnStrings, wString) } } require.Equal(t, tt.wantError, len(result.errs) > 0) if tt.wantError { require.Equal(t, len(tt.errStrings), len(result.errs)) for _, err := range result.errs { errString := err.Error() require.Contains(t, tt.errStrings, errString) } } }) } } func TestCheckSpecMinKubeVersion(t *testing.T) { type args struct { minKubeVersion string } tests := []struct { name string args args wantError bool wantWarning bool errStrings []string warnStrings []string }{ { name: "should work with a valid value", args: args{minKubeVersion: "1.16"}, }, { name: "should return a warning when the minKubeVersion is not informed ", args: args{minKubeVersion: ""}, wantWarning: true, warnStrings: []string{minKubeVersionWarnMessage}, }, { name: "should fail when an invalid value is informed", args: args{minKubeVersion: "alpha1"}, wantError: true, errStrings: []string{"csv.Spec.MinKubeVersion has an invalid value: alpha1"}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { csv := v1alpha1.ClusterServiceVersion{} csv.Spec.MinKubeVersion = tt.args.minKubeVersion checks := CSVChecks{csv: csv, errs: []error{}, warns: []error{}} result := checkSpecMinKubeVersion(checks) require.Equal(t, tt.wantWarning, len(result.warns) > 0) if tt.wantWarning { require.Equal(t, len(tt.warnStrings), len(result.warns)) for _, w := range result.warns { wString := w.Error() require.Contains(t, tt.warnStrings, wString) } } require.Equal(t, tt.wantError, len(result.errs) > 0) if tt.wantError { require.Equal(t, len(tt.errStrings), len(result.errs)) for _, err := range result.errs { errString := err.Error() require.Contains(t, tt.errStrings, errString) } } }) } }