github.com/DaAlbrecht/cf-cli@v0.0.0-20231128151943-1fe19bb400b9/util/manifestparser/parser_test.go (about)

     1  package manifestparser_test
     2  
     3  import (
     4  	"errors"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  
     9  	. "code.cloudfoundry.org/cli/util/manifestparser"
    10  	"github.com/cloudfoundry/bosh-cli/director/template"
    11  	. "github.com/onsi/ginkgo"
    12  	. "github.com/onsi/gomega"
    13  	"gopkg.in/yaml.v2"
    14  )
    15  
    16  var _ = Describe("ManifestParser", func() {
    17  	var parser ManifestParser
    18  
    19  	Describe("InterpolateManifest", func() {
    20  		var (
    21  			givenManifest    []byte
    22  			pathToManifest   string
    23  			pathsToVarsFiles []string
    24  			vars             []template.VarKV
    25  
    26  			interpolatedManifest []byte
    27  			executeErr           error
    28  		)
    29  
    30  		BeforeEach(func() {
    31  			tempFile, err := ioutil.TempFile("", "manifest-test-")
    32  			Expect(err).ToNot(HaveOccurred())
    33  			Expect(tempFile.Close()).ToNot(HaveOccurred())
    34  			pathToManifest = tempFile.Name()
    35  			vars = nil
    36  
    37  			pathsToVarsFiles = nil
    38  		})
    39  
    40  		AfterEach(func() {
    41  			Expect(os.RemoveAll(pathToManifest)).ToNot(HaveOccurred())
    42  			for _, path := range pathsToVarsFiles {
    43  				Expect(os.RemoveAll(path)).ToNot(HaveOccurred())
    44  			}
    45  		})
    46  
    47  		JustBeforeEach(func() {
    48  			interpolatedManifest, executeErr = parser.InterpolateManifest(pathToManifest, pathsToVarsFiles, vars)
    49  		})
    50  
    51  		When("the manifest does *not* need interpolation", func() {
    52  			BeforeEach(func() {
    53  				givenManifest = []byte(`---
    54  applications:
    55  - name: spark
    56  - name: flame
    57  `)
    58  				err := ioutil.WriteFile(pathToManifest, givenManifest, 0666)
    59  				Expect(err).ToNot(HaveOccurred())
    60  			})
    61  
    62  			It("parses the manifest properly", func() {
    63  				Expect(executeErr).ToNot(HaveOccurred())
    64  
    65  				Expect(string(interpolatedManifest)).To(Equal(`applications:
    66  - name: spark
    67  - name: flame
    68  `))
    69  			})
    70  		})
    71  
    72  		When("the manifest contains variables that need interpolation", func() {
    73  			BeforeEach(func() {
    74  				givenManifest = []byte(`---
    75  applications:
    76  - name: ((var1))
    77  - name: ((var2))
    78  `)
    79  				err := ioutil.WriteFile(pathToManifest, givenManifest, 0666)
    80  				Expect(err).ToNot(HaveOccurred())
    81  			})
    82  
    83  			When("only vars files are provided", func() {
    84  				var (
    85  					varsDir string
    86  				)
    87  
    88  				BeforeEach(func() {
    89  					var err error
    90  					varsDir, err = ioutil.TempDir("", "vars-test")
    91  					Expect(err).ToNot(HaveOccurred())
    92  
    93  					varsFilePath1 := filepath.Join(varsDir, "vars-1")
    94  					err = ioutil.WriteFile(varsFilePath1, []byte("var1: spark"), 0666)
    95  					Expect(err).ToNot(HaveOccurred())
    96  
    97  					varsFilePath2 := filepath.Join(varsDir, "vars-2")
    98  					err = ioutil.WriteFile(varsFilePath2, []byte("var2: flame"), 0666)
    99  					Expect(err).ToNot(HaveOccurred())
   100  
   101  					pathsToVarsFiles = append(pathsToVarsFiles, varsFilePath1, varsFilePath2)
   102  				})
   103  
   104  				AfterEach(func() {
   105  					Expect(os.RemoveAll(varsDir)).ToNot(HaveOccurred())
   106  				})
   107  
   108  				When("multiple values for the same variable(s) are provided", func() {
   109  					BeforeEach(func() {
   110  						varsFilePath1 := filepath.Join(varsDir, "vars-1")
   111  						err := ioutil.WriteFile(varsFilePath1, []byte("var1: garbageapp\nvar1: spark\nvar2: doesn't matter"), 0666)
   112  						Expect(err).ToNot(HaveOccurred())
   113  
   114  						varsFilePath2 := filepath.Join(varsDir, "vars-2")
   115  						err = ioutil.WriteFile(varsFilePath2, []byte("var2: flame"), 0666)
   116  						Expect(err).ToNot(HaveOccurred())
   117  
   118  						pathsToVarsFiles = append(pathsToVarsFiles, varsFilePath1, varsFilePath2)
   119  					})
   120  
   121  					It("interpolates the placeholder values", func() {
   122  						Expect(executeErr).ToNot(HaveOccurred())
   123  						Expect(string(interpolatedManifest)).To(Equal(`applications:
   124  - name: spark
   125  - name: flame
   126  `))
   127  					})
   128  				})
   129  
   130  				When("the provided files exists and contain valid yaml", func() {
   131  					It("interpolates the placeholder values", func() {
   132  						Expect(executeErr).ToNot(HaveOccurred())
   133  						Expect(string(interpolatedManifest)).To(Equal(`applications:
   134  - name: spark
   135  - name: flame
   136  `))
   137  					})
   138  				})
   139  
   140  				When("a variable in the manifest is not provided in the vars file", func() {
   141  					BeforeEach(func() {
   142  						varsFilePath := filepath.Join(varsDir, "vars-1")
   143  						err := ioutil.WriteFile(varsFilePath, []byte("notvar: foo"), 0666)
   144  						Expect(err).ToNot(HaveOccurred())
   145  
   146  						pathsToVarsFiles = []string{varsFilePath}
   147  					})
   148  
   149  					It("returns an error", func() {
   150  						Expect(executeErr.Error()).To(Equal("Expected to find variables: var1, var2"))
   151  					})
   152  				})
   153  
   154  				When("the provided file path does not exist", func() {
   155  					BeforeEach(func() {
   156  						pathsToVarsFiles = []string{"garbagepath"}
   157  					})
   158  
   159  					It("returns an error", func() {
   160  						Expect(executeErr).To(HaveOccurred())
   161  						Expect(os.IsNotExist(executeErr)).To(BeTrue())
   162  					})
   163  				})
   164  
   165  				When("the provided file is not a valid yaml file", func() {
   166  					BeforeEach(func() {
   167  						varsFilePath := filepath.Join(varsDir, "vars-1")
   168  						err := ioutil.WriteFile(varsFilePath, []byte(": bad"), 0666)
   169  						Expect(err).ToNot(HaveOccurred())
   170  
   171  						pathsToVarsFiles = []string{varsFilePath}
   172  					})
   173  
   174  					It("returns an error", func() {
   175  						Expect(executeErr).To(HaveOccurred())
   176  						Expect(executeErr).To(MatchError(InvalidYAMLError{
   177  							Err: errors.New("yaml: did not find expected key"),
   178  						}))
   179  					})
   180  				})
   181  			})
   182  
   183  			When("only vars are provided", func() {
   184  				BeforeEach(func() {
   185  					vars = []template.VarKV{
   186  						{Name: "var1", Value: "spark"},
   187  						{Name: "var2", Value: "flame"},
   188  					}
   189  				})
   190  
   191  				It("interpolates the placeholder values", func() {
   192  					Expect(executeErr).ToNot(HaveOccurred())
   193  					Expect(string(interpolatedManifest)).To(Equal(`applications:
   194  - name: spark
   195  - name: flame
   196  `))
   197  				})
   198  			})
   199  
   200  			When("vars and vars files are provided", func() {
   201  				var varsFilePath string
   202  				BeforeEach(func() {
   203  					tmp, err := ioutil.TempFile("", "util-manifest-varsilfe")
   204  					Expect(err).NotTo(HaveOccurred())
   205  					Expect(tmp.Close()).NotTo(HaveOccurred())
   206  
   207  					varsFilePath = tmp.Name()
   208  					err = ioutil.WriteFile(varsFilePath, []byte("var1: spark\nvar2: 12345"), 0666)
   209  					Expect(err).ToNot(HaveOccurred())
   210  
   211  					pathsToVarsFiles = []string{varsFilePath}
   212  					vars = []template.VarKV{
   213  						{Name: "var2", Value: "flame"},
   214  					}
   215  				})
   216  
   217  				AfterEach(func() {
   218  					Expect(os.RemoveAll(varsFilePath)).ToNot(HaveOccurred())
   219  				})
   220  
   221  				It("interpolates the placeholder values, prioritizing the vars flag", func() {
   222  					Expect(executeErr).ToNot(HaveOccurred())
   223  					Expect(string(interpolatedManifest)).To(Equal(`applications:
   224  - name: spark
   225  - name: flame
   226  `))
   227  				})
   228  			})
   229  		})
   230  	})
   231  
   232  	Describe("ParseManifest", func() {
   233  		var (
   234  			pathToManifest string
   235  			rawManifest    []byte
   236  
   237  			executeErr     error
   238  			parsedManifest Manifest
   239  		)
   240  
   241  		BeforeEach(func() {
   242  			pathToManifest = "/some/path/to/manifest.yml"
   243  			rawManifest = nil
   244  		})
   245  
   246  		JustBeforeEach(func() {
   247  			parsedManifest, executeErr = parser.ParseManifest(pathToManifest, rawManifest)
   248  		})
   249  
   250  		When("the manifest does not contain applications", func() {
   251  			BeforeEach(func() {
   252  				rawManifest = []byte(`applications:
   253  `)
   254  			})
   255  
   256  			It("returns an error", func() {
   257  				Expect(executeErr).To(HaveOccurred())
   258  				Expect(executeErr).To(MatchError(errors.New("Manifest must have at least one application.")))
   259  			})
   260  		})
   261  
   262  		When("invalid yaml is passed", func() {
   263  			BeforeEach(func() {
   264  				rawManifest = []byte("\t\t")
   265  			})
   266  
   267  			It("returns an error", func() {
   268  				Expect(executeErr).To(HaveOccurred())
   269  			})
   270  		})
   271  
   272  		When("unmarshalling returns an error", func() {
   273  			BeforeEach(func() {
   274  				rawManifest = []byte(`---
   275  	blah blah
   276  	`)
   277  			})
   278  
   279  			It("returns an error", func() {
   280  				Expect(executeErr).To(HaveOccurred())
   281  				Expect(executeErr).To(MatchError(&yaml.TypeError{}))
   282  			})
   283  		})
   284  
   285  		When("the manifest is valid", func() {
   286  			BeforeEach(func() {
   287  				rawManifest = []byte(`applications:
   288  - name: one
   289  - name: two
   290  `)
   291  			})
   292  
   293  			It("interpolates the placeholder values", func() {
   294  				Expect(executeErr).ToNot(HaveOccurred())
   295  				Expect(parsedManifest.AppNames()).To(ConsistOf("one", "two"))
   296  			})
   297  		})
   298  	})
   299  
   300  	Describe("MarshalManifest", func() {
   301  		It("marshals the manifest", func() {
   302  			manifest := Manifest{
   303  				Applications: []Application{
   304  					{
   305  						Name: "app-1",
   306  						Processes: []Process{
   307  							{
   308  								Type:                    "web",
   309  								RemainingManifestFields: map[string]interface{}{"unknown-process-key": 2},
   310  							},
   311  						},
   312  						RemainingManifestFields: map[string]interface{}{"unknown-key": 1},
   313  					},
   314  				},
   315  			}
   316  
   317  			yaml, err := parser.MarshalManifest(manifest)
   318  
   319  			Expect(err).NotTo(HaveOccurred())
   320  			Expect(yaml).To(MatchYAML(`applications:
   321  - name: app-1
   322    unknown-key: 1
   323    processes:
   324    - type: web
   325      unknown-process-key: 2
   326  `))
   327  		})
   328  	})
   329  })