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