github.com/fabianvf/ocp-release-operator-sdk@v0.0.0-20190426141702-57620ee2f090/internal/pkg/scaffold/olm-catalog/csv_test.go (about) 1 // Copyright 2018 The Operator-SDK Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package catalog 16 17 import ( 18 "bytes" 19 "io" 20 "io/ioutil" 21 "os" 22 "path/filepath" 23 "testing" 24 25 "github.com/operator-framework/operator-sdk/internal/pkg/scaffold" 26 "github.com/operator-framework/operator-sdk/internal/pkg/scaffold/input" 27 "github.com/operator-framework/operator-sdk/internal/util/diffutil" 28 "github.com/operator-framework/operator-sdk/internal/util/fileutil" 29 30 "github.com/coreos/go-semver/semver" 31 "github.com/ghodss/yaml" 32 olmapiv1alpha1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1" 33 olminstall "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" 34 "github.com/spf13/afero" 35 ) 36 37 const testDataDir = "testdata" 38 39 var testDeployDir = filepath.Join(testDataDir, scaffold.DeployDir) 40 41 func TestCSVNew(t *testing.T) { 42 buf := &bytes.Buffer{} 43 s := &scaffold.Scaffold{ 44 GetWriter: func(_ string, _ os.FileMode) (io.Writer, error) { 45 return buf, nil 46 }, 47 } 48 csvVer := "0.1.0" 49 projectName := "app-operator" 50 51 sc := &CSV{CSVVersion: csvVer, pathPrefix: testDataDir} 52 err := s.Execute(&input.Config{ProjectName: projectName}, sc) 53 if err != nil { 54 t.Fatalf("Failed to execute the scaffold: (%v)", err) 55 } 56 57 // Get the expected CSV manifest from test data dir. 58 csvExpBytes, err := afero.ReadFile(s.Fs, sc.getCSVPath(csvVer)) 59 if err != nil { 60 t.Fatal(err) 61 } 62 csvExp := string(csvExpBytes) 63 if csvExp != buf.String() { 64 diffs := diffutil.Diff(csvExp, buf.String()) 65 t.Errorf("Expected vs actual differs.\n%v", diffs) 66 } 67 } 68 69 func writeOSPathToFS(fromFs, toFs afero.Fs, root string) error { 70 if _, err := fromFs.Stat(root); err != nil { 71 return err 72 } 73 return afero.Walk(fromFs, root, func(path string, info os.FileInfo, err error) error { 74 if err != nil || info == nil { 75 return err 76 } 77 if !info.IsDir() { 78 b, err := afero.ReadFile(fromFs, path) 79 if err != nil { 80 return err 81 } 82 return afero.WriteFile(toFs, path, b, fileutil.DefaultFileMode) 83 } 84 return nil 85 }) 86 } 87 88 func TestCSVFromOld(t *testing.T) { 89 s := &scaffold.Scaffold{Fs: afero.NewMemMapFs()} 90 projectName := "app-operator" 91 oldCSVVer, newCSVVer := "0.1.0", "0.2.0" 92 93 // Write all files in testdata/deploy to fs so manifests are present when 94 // writing a new CSV. 95 if err := writeOSPathToFS(afero.NewOsFs(), s.Fs, testDeployDir); err != nil { 96 t.Fatalf("Failed to write %s to in-memory test fs: (%v)", testDeployDir, err) 97 } 98 99 sc := &CSV{ 100 CSVVersion: newCSVVer, 101 FromVersion: oldCSVVer, 102 pathPrefix: testDataDir, 103 } 104 err := s.Execute(&input.Config{ProjectName: projectName}, sc) 105 if err != nil { 106 t.Fatalf("Failed to execute the scaffold: (%v)", err) 107 } 108 109 // Check if a new file was written at the expected path. 110 newCSVPath := sc.getCSVPath(newCSVVer) 111 newCSV, newExists, err := getCSVFromFSIfExists(s.Fs, newCSVPath) 112 if err != nil { 113 t.Fatalf("Failed to get new CSV %s: (%v)", newCSVPath, err) 114 } 115 if !newExists { 116 t.Fatalf("New CSV does not exist at %s", newCSVPath) 117 } 118 119 expName := getCSVName(projectName, newCSVVer) 120 if newCSV.ObjectMeta.Name != expName { 121 t.Errorf("Expected CSV metadata.name %s, got %s", expName, newCSV.ObjectMeta.Name) 122 } 123 expReplaces := getCSVName(projectName, oldCSVVer) 124 if newCSV.Spec.Replaces != expReplaces { 125 t.Errorf("Expected CSV spec.replaces %s, got %s", expReplaces, newCSV.Spec.Replaces) 126 } 127 } 128 129 func TestUpdateVersion(t *testing.T) { 130 projectName := "app-operator" 131 oldCSVVer, newCSVVer := "0.1.0", "0.2.0" 132 sc := &CSV{ 133 Input: input.Input{ProjectName: projectName}, 134 CSVVersion: newCSVVer, 135 pathPrefix: testDataDir, 136 } 137 csvExpBytes, err := ioutil.ReadFile(sc.getCSVPath(oldCSVVer)) 138 if err != nil { 139 t.Fatal(err) 140 } 141 csv := &olmapiv1alpha1.ClusterServiceVersion{} 142 if err := yaml.Unmarshal(csvExpBytes, csv); err != nil { 143 t.Fatal(err) 144 } 145 146 if err := sc.updateCSVVersions(csv); err != nil { 147 t.Fatalf("Failed to update csv with version %s: (%v)", newCSVVer, err) 148 } 149 150 wantedSemver := semver.New(newCSVVer) 151 if !csv.Spec.Version.Equal(*wantedSemver) { 152 t.Errorf("Wanted csv version %v, got %v", *wantedSemver, csv.Spec.Version) 153 } 154 wantedName := getCSVName(projectName, newCSVVer) 155 if csv.ObjectMeta.Name != wantedName { 156 t.Errorf("Wanted csv name %s, got %s", wantedName, csv.ObjectMeta.Name) 157 } 158 159 var resolver *olminstall.StrategyResolver 160 stratInterface, err := resolver.UnmarshalStrategy(csv.Spec.InstallStrategy) 161 if err != nil { 162 t.Fatal(err) 163 } 164 strat, ok := stratInterface.(*olminstall.StrategyDetailsDeployment) 165 if !ok { 166 t.Fatalf("Strategy of type %T was not StrategyDetailsDeployment", stratInterface) 167 } 168 csvPodImage := strat.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Image 169 // updateCSVVersions should not update podspec image. 170 wantedImage := "quay.io/example-inc/operator:v0.1.0" 171 if csvPodImage != wantedImage { 172 t.Errorf("Podspec image changed from %s to %s", wantedImage, csvPodImage) 173 } 174 175 wantedReplaces := getCSVName(projectName, "0.1.0") 176 if csv.Spec.Replaces != wantedReplaces { 177 t.Errorf("Wanted csv replaces %s, got %s", wantedReplaces, csv.Spec.Replaces) 178 } 179 } 180 181 func TestGetDisplayName(t *testing.T) { 182 cases := []struct { 183 input, wanted string 184 }{ 185 {"Appoperator", "Appoperator"}, 186 {"appoperator", "Appoperator"}, 187 {"appoperatoR", "Appoperato R"}, 188 {"AppOperator", "App Operator"}, 189 {"appOperator", "App Operator"}, 190 {"app-operator", "App Operator"}, 191 {"app-_operator", "App Operator"}, 192 {"App-operator", "App Operator"}, 193 {"app-_Operator", "App Operator"}, 194 {"app--Operator", "App Operator"}, 195 {"app--_Operator", "App Operator"}, 196 {"APP", "APP"}, 197 {"another-AppOperator_againTwiceThrice More", "Another App Operator Again Twice Thrice More"}, 198 } 199 200 for _, c := range cases { 201 dn := getDisplayName(c.input) 202 if dn != c.wanted { 203 t.Errorf("Wanted %s, got %s", c.wanted, dn) 204 } 205 } 206 }