github.com/cloudfoundry-community/cloudfoundry-cli@v6.44.1-0.20240130060226-cda5ed8e89a5+incompatible/util/manifestparser/parser_test.go (about) 1 package manifestparser_test 2 3 import ( 4 "errors" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 10 . "code.cloudfoundry.org/cli/util/manifestparser" 11 12 "github.com/cloudfoundry/bosh-cli/director/template" 13 . "github.com/onsi/ginkgo" 14 . "github.com/onsi/gomega" 15 ) 16 17 var _ = Describe("Parser", func() { 18 var parser *Parser 19 20 BeforeEach(func() { 21 parser = NewParser() 22 }) 23 24 Describe("NewParser", func() { 25 It("returns a parser", func() { 26 Expect(parser).ToNot(BeNil()) 27 }) 28 }) 29 30 Describe("AppNames", func() { 31 When("given a valid manifest file", func() { 32 BeforeEach(func() { 33 parser.Applications = []Application{ 34 {ApplicationModel: ApplicationModel{Name: "app-1"}, FullUnmarshalledApplication: nil}, 35 {ApplicationModel: ApplicationModel{Name: "app-2"}, FullUnmarshalledApplication: nil}} 36 }) 37 38 It("gets the app names", func() { 39 appNames := parser.AppNames() 40 Expect(appNames).To(ConsistOf("app-1", "app-2")) 41 }) 42 }) 43 }) 44 45 Describe("ContainsManifest", func() { 46 var ( 47 pathToManifest string 48 ) 49 50 BeforeEach(func() { 51 tempFile, err := ioutil.TempFile("", "contains-manifest-test") 52 Expect(err).ToNot(HaveOccurred()) 53 pathToManifest = tempFile.Name() 54 Expect(tempFile.Close()).ToNot(HaveOccurred()) 55 }) 56 57 AfterEach(func() { 58 err := os.RemoveAll(pathToManifest) 59 Expect(err).ToNot(HaveOccurred()) 60 }) 61 62 Context("when the manifest is parsed successfully", func() { 63 BeforeEach(func() { 64 rawManifest := []byte(`--- 65 applications: 66 - name: spark 67 `) 68 err := ioutil.WriteFile(pathToManifest, rawManifest, 0666) 69 Expect(err).ToNot(HaveOccurred()) 70 71 err = parser.InterpolateAndParse(pathToManifest, nil, nil) 72 Expect(err).ToNot(HaveOccurred()) 73 }) 74 75 It("returns true", func() { 76 Expect(parser.ContainsManifest()).To(BeTrue()) 77 }) 78 }) 79 80 Context("when the manifest is not parsed successfully", func() { 81 BeforeEach(func() { 82 rawManifest := []byte(`--- 83 applications: 84 `) 85 err := ioutil.WriteFile(pathToManifest, rawManifest, 0666) 86 Expect(err).ToNot(HaveOccurred()) 87 88 err = parser.InterpolateAndParse(pathToManifest, nil, nil) 89 Expect(err).To(HaveOccurred()) 90 }) 91 92 It("returns false", func() { 93 Expect(parser.ContainsManifest()).To(BeFalse()) 94 }) 95 }) 96 97 Context("when the manifest has not been parsed", func() { 98 It("returns false", func() { 99 Expect(parser.ContainsManifest()).To(BeFalse()) 100 }) 101 }) 102 }) 103 104 Describe("ContainsMultipleApps", func() { 105 When("given a valid manifest file with multiple apps", func() { 106 BeforeEach(func() { 107 parser.Applications = []Application{ 108 {ApplicationModel: ApplicationModel{Name: "app-1"}, FullUnmarshalledApplication: nil}, 109 {ApplicationModel: ApplicationModel{Name: "app-2"}, FullUnmarshalledApplication: nil}} 110 }) 111 112 It("returns true", func() { 113 Expect(parser.ContainsMultipleApps()).To(BeTrue()) 114 }) 115 }) 116 117 When("given a valid manifest file with a single app", func() { 118 BeforeEach(func() { 119 parser.Applications = []Application{{ApplicationModel: ApplicationModel{Name: "app-1"}, FullUnmarshalledApplication: nil}} 120 }) 121 122 It("returns false", func() { 123 Expect(parser.ContainsMultipleApps()).To(BeFalse()) 124 }) 125 }) 126 }) 127 128 Describe("ContainsPrivateDockerImages", func() { 129 When("the manifest contains a docker image", func() { 130 When("the image is public", func() { 131 BeforeEach(func() { 132 parser.Applications = []Application{ 133 {ApplicationModel: ApplicationModel{Name: "app-1", Docker: &Docker{Image: "image-1"}}, FullUnmarshalledApplication: nil}, 134 {ApplicationModel: ApplicationModel{Name: "app-2", Docker: &Docker{Image: "image-2"}}, FullUnmarshalledApplication: nil}} 135 }) 136 137 It("returns false", func() { 138 Expect(parser.ContainsPrivateDockerImages()).To(BeFalse()) 139 }) 140 }) 141 142 When("the image is private", func() { 143 BeforeEach(func() { 144 parser.Applications = []Application{ 145 {ApplicationModel: ApplicationModel{Name: "app-1", Docker: &Docker{Image: "image-1"}}}, 146 {ApplicationModel: ApplicationModel{Name: "app-2", Docker: &Docker{Image: "image-2", Username: "user"}}}, 147 } 148 }) 149 150 It("returns true", func() { 151 Expect(parser.ContainsPrivateDockerImages()).To(BeTrue()) 152 }) 153 }) 154 }) 155 156 When("the manifest does not contain a docker image", func() { 157 BeforeEach(func() { 158 parser.Applications = []Application{ 159 {ApplicationModel: ApplicationModel{Name: "app-1"}}, 160 {ApplicationModel: ApplicationModel{Name: "app-2"}}, 161 } 162 }) 163 164 It("returns false", func() { 165 Expect(parser.ContainsPrivateDockerImages()).To(BeFalse()) 166 }) 167 }) 168 }) 169 170 Describe("InterpolateAndParse", func() { 171 var ( 172 pathToManifest string 173 pathsToVarsFiles []string 174 vars []template.VarKV 175 176 executeErr error 177 178 rawManifest []byte 179 ) 180 181 BeforeEach(func() { 182 tempFile, err := ioutil.TempFile("", "manifest-test-") 183 Expect(err).ToNot(HaveOccurred()) 184 Expect(tempFile.Close()).ToNot(HaveOccurred()) 185 pathToManifest = tempFile.Name() 186 vars = nil 187 188 pathsToVarsFiles = nil 189 }) 190 191 AfterEach(func() { 192 Expect(os.RemoveAll(pathToManifest)).ToNot(HaveOccurred()) 193 for _, path := range pathsToVarsFiles { 194 Expect(os.RemoveAll(path)).ToNot(HaveOccurred()) 195 } 196 }) 197 198 JustBeforeEach(func() { 199 executeErr = parser.InterpolateAndParse(pathToManifest, pathsToVarsFiles, vars) 200 }) 201 202 Context("regardless of whether the manifest needs interpolation", func() { 203 BeforeEach(func() { 204 rawManifest = []byte(`--- 205 applications: 206 - name: spark 207 memory: 1G 208 instances: 2 209 - name: flame 210 memory: 1G 211 instances: 2 212 `) 213 err := ioutil.WriteFile(pathToManifest, rawManifest, 0666) 214 Expect(err).ToNot(HaveOccurred()) 215 }) 216 217 It("parses the manifest properly", func() { 218 Expect(executeErr).ToNot(HaveOccurred()) 219 220 Expect(parser.AppNames()).To(ConsistOf("spark", "flame")) 221 Expect(parser.PathToManifest).To(Equal(pathToManifest)) 222 Expect(parser.FullRawManifest()).To(MatchYAML(rawManifest)) 223 }) 224 }) 225 226 Context("invalid yaml is passed", func() { 227 BeforeEach(func() { 228 rawManifest = []byte("\t\t") 229 err := ioutil.WriteFile(pathToManifest, rawManifest, 0666) 230 Expect(err).ToNot(HaveOccurred()) 231 }) 232 233 It("parses the manifest properly", func() { 234 Expect(executeErr).To(HaveOccurred()) 235 }) 236 }) 237 238 When("the manifest contains variables that need interpolation", func() { 239 BeforeEach(func() { 240 rawManifest = []byte(`--- 241 applications: 242 - name: ((var1)) 243 - name: ((var2)) 244 `) 245 err := ioutil.WriteFile(pathToManifest, rawManifest, 0666) 246 Expect(err).ToNot(HaveOccurred()) 247 }) 248 249 When("only vars files are provided", func() { 250 var ( 251 varsDir string 252 ) 253 254 BeforeEach(func() { 255 var err error 256 varsDir, err = ioutil.TempDir("", "vars-test") 257 Expect(err).ToNot(HaveOccurred()) 258 259 varsFilePath1 := filepath.Join(varsDir, "vars-1") 260 err = ioutil.WriteFile(varsFilePath1, []byte("var1: spark"), 0666) 261 Expect(err).ToNot(HaveOccurred()) 262 263 varsFilePath2 := filepath.Join(varsDir, "vars-2") 264 err = ioutil.WriteFile(varsFilePath2, []byte("var2: flame"), 0666) 265 Expect(err).ToNot(HaveOccurred()) 266 267 pathsToVarsFiles = append(pathsToVarsFiles, varsFilePath1, varsFilePath2) 268 }) 269 270 AfterEach(func() { 271 Expect(os.RemoveAll(varsDir)).ToNot(HaveOccurred()) 272 }) 273 274 When("multiple values for the same variable(s) are provided", func() { 275 BeforeEach(func() { 276 varsFilePath1 := filepath.Join(varsDir, "vars-1") 277 err := ioutil.WriteFile(varsFilePath1, []byte("var1: garbageapp\nvar1: spark\nvar2: doesn't matter"), 0666) 278 Expect(err).ToNot(HaveOccurred()) 279 280 varsFilePath2 := filepath.Join(varsDir, "vars-2") 281 err = ioutil.WriteFile(varsFilePath2, []byte("var2: flame"), 0666) 282 Expect(err).ToNot(HaveOccurred()) 283 284 pathsToVarsFiles = append(pathsToVarsFiles, varsFilePath1, varsFilePath2) 285 }) 286 287 It("interpolates the placeholder values", func() { 288 Expect(executeErr).ToNot(HaveOccurred()) 289 Expect(parser.AppNames()).To(ConsistOf("spark", "flame")) 290 }) 291 }) 292 293 When("the provided files exists and contain valid yaml", func() { 294 It("interpolates the placeholder values", func() { 295 Expect(executeErr).ToNot(HaveOccurred()) 296 Expect(parser.AppNames()).To(ConsistOf("spark", "flame")) 297 }) 298 }) 299 300 When("a variable in the manifest is not provided in the vars file", func() { 301 BeforeEach(func() { 302 varsFilePath := filepath.Join(varsDir, "vars-1") 303 err := ioutil.WriteFile(varsFilePath, []byte("notvar: foo"), 0666) 304 Expect(err).ToNot(HaveOccurred()) 305 306 pathsToVarsFiles = []string{varsFilePath} 307 }) 308 309 It("returns an error", func() { 310 Expect(executeErr.Error()).To(Equal("Expected to find variables: var1, var2")) 311 }) 312 }) 313 314 When("the provided file path does not exist", func() { 315 BeforeEach(func() { 316 pathsToVarsFiles = []string{"garbagepath"} 317 }) 318 319 It("returns an error", func() { 320 Expect(executeErr).To(HaveOccurred()) 321 Expect(os.IsNotExist(executeErr)).To(BeTrue()) 322 }) 323 }) 324 325 When("the provided file is not a valid yaml file", func() { 326 BeforeEach(func() { 327 varsFilePath := filepath.Join(varsDir, "vars-1") 328 err := ioutil.WriteFile(varsFilePath, []byte(": bad"), 0666) 329 Expect(err).ToNot(HaveOccurred()) 330 331 pathsToVarsFiles = []string{varsFilePath} 332 }) 333 334 It("returns an error", func() { 335 Expect(executeErr).To(HaveOccurred()) 336 Expect(executeErr).To(MatchError(InvalidYAMLError{ 337 Err: errors.New("yaml: did not find expected key"), 338 })) 339 }) 340 }) 341 }) 342 343 When("only vars are provided", func() { 344 BeforeEach(func() { 345 vars = []template.VarKV{ 346 {Name: "var1", Value: "spark"}, 347 {Name: "var2", Value: "flame"}, 348 } 349 }) 350 351 It("interpolates the placeholder values", func() { 352 Expect(executeErr).ToNot(HaveOccurred()) 353 Expect(parser.AppNames()).To(ConsistOf("spark", "flame")) 354 }) 355 }) 356 357 When("vars and vars files are provided", func() { 358 var varsFilePath string 359 BeforeEach(func() { 360 tmp, err := ioutil.TempFile("", "util-manifest-varsilfe") 361 Expect(err).NotTo(HaveOccurred()) 362 Expect(tmp.Close()).NotTo(HaveOccurred()) 363 364 varsFilePath = tmp.Name() 365 err = ioutil.WriteFile(varsFilePath, []byte("var1: spark\nvar2: 12345"), 0666) 366 Expect(err).ToNot(HaveOccurred()) 367 368 pathsToVarsFiles = []string{varsFilePath} 369 vars = []template.VarKV{ 370 {Name: "var2", Value: "flame"}, 371 } 372 }) 373 374 AfterEach(func() { 375 Expect(os.RemoveAll(varsFilePath)).ToNot(HaveOccurred()) 376 }) 377 378 It("interpolates the placeholder values, prioritizing the vars flag", func() { 379 Expect(executeErr).ToNot(HaveOccurred()) 380 Expect(parser.AppNames()).To(ConsistOf("spark", "flame")) 381 }) 382 }) 383 }) 384 }) 385 386 Describe("RawAppManifest", func() { 387 var ( 388 rawAppManifest []byte 389 appName string 390 executeErr error 391 rawManifest []byte 392 pathToManifest string 393 tmpMyPath string 394 ) 395 396 BeforeEach(func() { 397 var err error 398 399 appName = "spark" 400 401 tmpMyPath, err = ioutil.TempDir("", "") 402 Expect(err).ToNot(HaveOccurred()) 403 404 rawManifest = []byte(fmt.Sprintf(`--- 405 applications: 406 - name: spark 407 memory: 1G 408 instances: 2 409 docker: 410 username: experiment 411 path: %s 412 - name: flame 413 memory: 1G 414 instances: 2 415 docker: 416 username: experiment 417 `, tmpMyPath)) 418 419 }) 420 421 JustBeforeEach(func() { 422 tempFile, err := ioutil.TempFile("", "manifest-test-") 423 Expect(err).ToNot(HaveOccurred()) 424 Expect(tempFile.Close()).ToNot(HaveOccurred()) 425 pathToManifest = tempFile.Name() 426 err = ioutil.WriteFile(pathToManifest, rawManifest, 0666) 427 Expect(err).ToNot(HaveOccurred()) 428 err = parser.InterpolateAndParse(pathToManifest, nil, nil) 429 Expect(err).ToNot(HaveOccurred()) 430 rawAppManifest, executeErr = parser.RawAppManifest(appName) 431 }) 432 433 AfterEach(func() { 434 err := os.RemoveAll(pathToManifest) 435 Expect(err).ToNot(HaveOccurred()) 436 }) 437 438 When("marshaling does not error", func() { 439 440 It("returns just the app's manifest", func() { 441 Expect(executeErr).ToNot(HaveOccurred()) 442 Expect(string(rawAppManifest)).To(MatchYAML(fmt.Sprintf(`applications: 443 - name: spark 444 memory: 1G 445 instances: 2 446 docker: 447 username: experiment 448 path: %s`, tmpMyPath))) 449 }) 450 }) 451 452 When("The app is not present", func() { 453 BeforeEach(func() { 454 appName = "not-here" 455 }) 456 457 It("returns an error", func() { 458 Expect(executeErr).To(MatchError(AppNotInManifestError{Name: "not-here"})) 459 Expect(rawAppManifest).To(BeNil()) 460 }) 461 }) 462 463 }) 464 })