github.com/nimakaviani/cli@v6.37.1-0.20180619223813-e734901a73fa+incompatible/util/manifest/manifest_test.go (about)

     1  package manifest_test
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"strings"
    10  
    11  	"code.cloudfoundry.org/cli/types"
    12  	. "code.cloudfoundry.org/cli/util/manifest"
    13  
    14  	"github.com/cloudfoundry/bosh-cli/director/template"
    15  	. "github.com/onsi/ginkgo"
    16  	. "github.com/onsi/ginkgo/extensions/table"
    17  	. "github.com/onsi/gomega"
    18  	. "github.com/onsi/gomega/gstruct"
    19  )
    20  
    21  var _ = Describe("Manifest", func() {
    22  	var manifest string
    23  
    24  	Describe("ReadAndInterpolateManifest", func() {
    25  		var (
    26  			pathToManifest   string
    27  			pathsToVarsFiles []string
    28  			vars             []template.VarKV
    29  			apps             []Application
    30  			executeErr       error
    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  			apps, executeErr = ReadAndInterpolateManifest(pathToManifest, pathsToVarsFiles, vars)
    52  		})
    53  
    54  		Context("when the manifest contains NO variables that need interpolation", func() {
    55  			BeforeEach(func() {
    56  				manifest = `---
    57  applications:
    58  - name: app-1
    59    buildpack: "some-buildpack"
    60    command: "some-command"
    61    health-check-http-endpoint: "\\some-endpoint"
    62    health-check-type: "http"
    63    instances: 10
    64    disk_quota: 100M
    65    docker:
    66      image: "some-docker-image"
    67      username: "some-docker-username"
    68    memory: 200M
    69    random-route: true
    70    stack: "some-stack"
    71    timeout: 120
    72  - name: "app-2"
    73    buildpack: default
    74    disk_quota: 1G
    75    instances: 0
    76    memory: 2G
    77    routes:
    78    - route: foo.bar.com
    79    - route: baz.qux.com
    80    - route: blep.blah.com/boop
    81    services:
    82    - service_1
    83    - service_2
    84  - name: "app-3"
    85    no-route: true
    86    env:
    87      env_1: 'foo'
    88      env_2: 182837403930483038
    89      env_3: true
    90      env_4: 1.00001
    91  - name: "app-4"
    92    buildpack: null
    93    command: null
    94  - name: "app-5"
    95    domain: "some-domain"
    96    domains:
    97    - domain_1
    98    - domain_2
    99  - name: "app-6"
   100    host: "some-hostname"
   101    hosts:
   102    - hostname_1
   103    - hostname_2
   104    no-hostname: true
   105  - name: "app-7"
   106    routes:
   107    - route: hello.com
   108    - route: bleep.blah.com
   109    random-route: true
   110  `
   111  
   112  				err := ioutil.WriteFile(pathToManifest, []byte(manifest), 0666)
   113  				Expect(err).ToNot(HaveOccurred())
   114  			})
   115  
   116  			Context("when the manifest does not contain deprecated fields", func() {
   117  				It("returns a merged set of applications", func() {
   118  					Expect(executeErr).ToNot(HaveOccurred())
   119  					Expect(apps).To(HaveLen(7))
   120  
   121  					Expect(apps[0]).To(Equal(Application{
   122  						Name: "app-1",
   123  						Buildpack: types.FilteredString{
   124  							IsSet: true,
   125  							Value: "some-buildpack",
   126  						},
   127  						Command: types.FilteredString{
   128  							IsSet: true,
   129  							Value: "some-command",
   130  						},
   131  						HealthCheckHTTPEndpoint: "\\some-endpoint",
   132  						HealthCheckType:         "http",
   133  						Instances: types.NullInt{
   134  							Value: 10,
   135  							IsSet: true,
   136  						},
   137  						DiskQuota: types.NullByteSizeInMb{
   138  							Value: 100,
   139  							IsSet: true,
   140  						},
   141  						DockerImage:    "some-docker-image",
   142  						DockerUsername: "some-docker-username",
   143  						Memory: types.NullByteSizeInMb{
   144  							Value: 200,
   145  							IsSet: true,
   146  						},
   147  						RandomRoute:        true,
   148  						StackName:          "some-stack",
   149  						HealthCheckTimeout: 120,
   150  					}))
   151  
   152  					Expect(apps[1]).To(Equal(Application{
   153  						Name: "app-2",
   154  						Buildpack: types.FilteredString{
   155  							IsSet: true,
   156  							Value: "",
   157  						},
   158  						DiskQuota: types.NullByteSizeInMb{
   159  							Value: 1024,
   160  							IsSet: true,
   161  						},
   162  						Instances: types.NullInt{
   163  							IsSet: true,
   164  							Value: 0,
   165  						},
   166  						Memory: types.NullByteSizeInMb{
   167  							Value: 2048,
   168  							IsSet: true,
   169  						},
   170  						Routes:   []string{"foo.bar.com", "baz.qux.com", "blep.blah.com/boop"},
   171  						Services: []string{"service_1", "service_2"},
   172  					}))
   173  
   174  					Expect(apps[2]).To(Equal(Application{
   175  						Name: "app-3",
   176  						EnvironmentVariables: map[string]string{
   177  							"env_1": "foo",
   178  							"env_2": "182837403930483038",
   179  							"env_3": "true",
   180  							"env_4": "1.00001",
   181  						},
   182  						NoRoute: true,
   183  					}))
   184  
   185  					Expect(apps[3]).To(Equal(Application{
   186  						Name: "app-4",
   187  						Buildpack: types.FilteredString{
   188  							IsSet: true,
   189  							Value: "",
   190  						},
   191  						Command: types.FilteredString{
   192  							IsSet: true,
   193  							Value: "",
   194  						},
   195  					}))
   196  
   197  					Expect(apps[4].Name).To(Equal("app-5"))
   198  					Expect(apps[4].DeprecatedDomain).ToNot(BeNil())
   199  					Expect(apps[4].DeprecatedDomains).ToNot(BeNil())
   200  
   201  					Expect(apps[5].Name).To(Equal("app-6"))
   202  					Expect(apps[5].DeprecatedHost).ToNot(BeNil())
   203  					Expect(apps[5].DeprecatedHosts).ToNot(BeNil())
   204  					Expect(apps[5].DeprecatedNoHostname).ToNot(BeNil())
   205  
   206  					Expect(apps[6]).To(Equal(Application{
   207  						Name:        "app-7",
   208  						Routes:      []string{"hello.com", "bleep.blah.com"},
   209  						RandomRoute: true,
   210  					}))
   211  				})
   212  			})
   213  
   214  			Context("when provided deprecated fields", func() {
   215  				Context("when global fields are provided", func() {
   216  					DescribeTable("raises a GlobalFieldsError",
   217  						func(manifestProperty string, numberOfValues int) {
   218  							tempManifest, err := ioutil.TempFile("", "manifest-test-")
   219  							Expect(err).ToNot(HaveOccurred())
   220  							Expect(tempManifest.Close()).ToNot(HaveOccurred())
   221  							manifestPath := tempManifest.Name()
   222  							defer os.RemoveAll(manifestPath)
   223  
   224  							if numberOfValues == 1 {
   225  								manifest = fmt.Sprintf("---\n%s: value", manifestProperty)
   226  							} else {
   227  								values := []string{"A", "B"}
   228  								manifest = fmt.Sprintf("---\n%s: [%s]", manifestProperty, strings.Join(values, ","))
   229  							}
   230  							err = ioutil.WriteFile(manifestPath, []byte(manifest), 0666)
   231  							Expect(err).ToNot(HaveOccurred())
   232  
   233  							_, err = ReadAndInterpolateManifest(manifestPath, pathsToVarsFiles, vars)
   234  							Expect(err).To(MatchError(GlobalFieldsError{Fields: []string{manifestProperty}}))
   235  						},
   236  
   237  						Entry("global buildpack", "buildpack", 1),
   238  						Entry("global command", "command", 1),
   239  						Entry("global disk quota", "disk_quota", 1),
   240  						Entry("global docker", "docker", 1),
   241  						Entry("global domain", "domain", 1),
   242  						Entry("global domains", "domains", 2),
   243  						Entry("global environment variables", "env", 2),
   244  						Entry("global health check HTTP endpoint", "health-check-http-endpoint", 1),
   245  						Entry("global health check timeout", "timeout", 1),
   246  						Entry("global health check type", "health-check-type", 1),
   247  						Entry("global host", "host", 1),
   248  						Entry("global hosts", "hosts", 2),
   249  						Entry("global instances", "instances", 1),
   250  						Entry("global memory", "memory", 1),
   251  						Entry("global name", "name", 1),
   252  						Entry("global no hostname", "no-hostname", 1),
   253  						Entry("global no route", "no-route", 1),
   254  						Entry("global path", "path", 1),
   255  						Entry("global random-route", "random-route", 1),
   256  						Entry("global routes", "routes", 2),
   257  						Entry("global services", "services", 2),
   258  						Entry("global stack", "stack", 1),
   259  					)
   260  				})
   261  			})
   262  
   263  			Context("when inheritance is provided", func() {
   264  				BeforeEach(func() {
   265  					manifest = `---
   266  inherit: "./some-inheritance-file"
   267  applications:
   268  - name: "app-1"
   269  `
   270  
   271  					err := ioutil.WriteFile(pathToManifest, []byte(manifest), 0666)
   272  					Expect(err).ToNot(HaveOccurred())
   273  				})
   274  
   275  				It("raises an InheritanceFieldError", func() {
   276  					Expect(executeErr).To(MatchError(InheritanceFieldError{}))
   277  				})
   278  			})
   279  
   280  			Context("when the manifest specified a single buildpack", func() {
   281  				BeforeEach(func() {
   282  					manifest = `---
   283  applications:
   284  - name: app-1
   285    buildpack: "some-buildpack"
   286    memory: 200M
   287    instances: 10
   288  `
   289  					err := ioutil.WriteFile(pathToManifest, []byte(manifest), 0666)
   290  					Expect(err).ToNot(HaveOccurred())
   291  				})
   292  
   293  				It("returns a merged set of applications", func() {
   294  					Expect(executeErr).ToNot(HaveOccurred())
   295  					Expect(apps).To(HaveLen(1))
   296  
   297  					Expect(apps[0]).To(MatchFields(IgnoreExtras, Fields{
   298  						"Buildpack": Equal(types.FilteredString{
   299  							IsSet: true,
   300  							Value: "some-buildpack",
   301  						}),
   302  						"Buildpacks": BeEmpty(),
   303  					}))
   304  				})
   305  			})
   306  
   307  			Context("when the manifest contains buildpacks (plural)", func() {
   308  				BeforeEach(func() {
   309  					manifest = `---
   310  applications:
   311  - name: app-1
   312    buildpacks:
   313    - "some-buildpack-1"
   314    - "some-buildpack-2"
   315    memory: 200M
   316    instances: 10
   317  - name: app-2
   318    buildpacks:
   319    - "some-other-buildpack-1"
   320    - "some-other-buildpack-2"
   321    memory: 2048M
   322    instances: 0`
   323  					err := ioutil.WriteFile(pathToManifest, []byte(manifest), 0666)
   324  					Expect(err).ToNot(HaveOccurred())
   325  				})
   326  
   327  				It("returns a merged set of applications", func() {
   328  					Expect(executeErr).ToNot(HaveOccurred())
   329  					Expect(apps).To(HaveLen(2))
   330  
   331  					Expect(apps[0]).To(MatchFields(IgnoreExtras, Fields{
   332  						"Buildpack": Equal(types.FilteredString{
   333  							IsSet: false,
   334  							Value: "",
   335  						}),
   336  						"Buildpacks": ConsistOf("some-buildpack-1", "some-buildpack-2"),
   337  					}))
   338  
   339  					Expect(apps[1]).To(MatchFields(IgnoreExtras, Fields{
   340  						"Buildpack": Equal(types.FilteredString{
   341  							IsSet: false,
   342  							Value: "",
   343  						}),
   344  						"Buildpacks": ConsistOf(
   345  							"some-other-buildpack-1",
   346  							"some-other-buildpack-2",
   347  						),
   348  					}))
   349  				})
   350  			})
   351  
   352  			Context("when the manifest sets buildpacks to an empty array", func() {
   353  				BeforeEach(func() {
   354  					manifest = `---
   355  applications:
   356  - name: app-1
   357    buildpacks: []
   358    memory: 200M
   359    instances: 10
   360  `
   361  					err := ioutil.WriteFile(pathToManifest, []byte(manifest), 0666)
   362  					Expect(err).ToNot(HaveOccurred())
   363  				})
   364  
   365  				It("returns a merged set of applications", func() {
   366  					Expect(executeErr).ToNot(HaveOccurred())
   367  					Expect(apps).To(HaveLen(1))
   368  
   369  					Expect(apps[0]).To(MatchFields(IgnoreExtras, Fields{
   370  						"Buildpack": Equal(types.FilteredString{
   371  							IsSet: false,
   372  							Value: "",
   373  						}),
   374  						"Buildpacks": Equal([]string{}),
   375  					}))
   376  				})
   377  			})
   378  
   379  			Context("when the manifest contains an empty buildpacks attribute", func() {
   380  				BeforeEach(func() {
   381  					manifest = `---
   382  applications:
   383  - name: app-1
   384    buildpacks:
   385  `
   386  					err := ioutil.WriteFile(pathToManifest, []byte(manifest), 0666)
   387  					Expect(err).ToNot(HaveOccurred())
   388  				})
   389  
   390  				It("raises an error", func() {
   391  					Expect(executeErr).ToNot(MatchError(new(EmptyBuildpacksError)))
   392  				})
   393  			})
   394  		})
   395  
   396  		Context("when the manifest contains variables that need interpolation", func() {
   397  			BeforeEach(func() {
   398  				manifest = `---
   399  applications:
   400  - name: ((var1))
   401    instances: ((var2))
   402  `
   403  				err := ioutil.WriteFile(pathToManifest, []byte(manifest), 0666)
   404  				Expect(err).ToNot(HaveOccurred())
   405  			})
   406  
   407  			Context("when only vars files are provided", func() {
   408  				var (
   409  					varsDir string
   410  				)
   411  
   412  				BeforeEach(func() {
   413  					var err error
   414  					varsDir, err = ioutil.TempDir("", "vars-test")
   415  					Expect(err).ToNot(HaveOccurred())
   416  
   417  					varsFilePath1 := filepath.Join(varsDir, "vars-1")
   418  					err = ioutil.WriteFile(varsFilePath1, []byte("var1: app-1"), 0666)
   419  					Expect(err).ToNot(HaveOccurred())
   420  
   421  					varsFilePath2 := filepath.Join(varsDir, "vars-2")
   422  					err = ioutil.WriteFile(varsFilePath2, []byte("var2: 4"), 0666)
   423  					Expect(err).ToNot(HaveOccurred())
   424  
   425  					pathsToVarsFiles = append(pathsToVarsFiles, varsFilePath1, varsFilePath2)
   426  				})
   427  
   428  				AfterEach(func() {
   429  					Expect(os.RemoveAll(varsDir)).ToNot(HaveOccurred())
   430  				})
   431  
   432  				Context("when multiple values for the same variable(s) are provided", func() {
   433  					BeforeEach(func() {
   434  						varsFilePath1 := filepath.Join(varsDir, "vars-1")
   435  						err := ioutil.WriteFile(varsFilePath1, []byte("var1: garbageapp\nvar1: app-1\nvar2: 0"), 0666)
   436  						Expect(err).ToNot(HaveOccurred())
   437  
   438  						varsFilePath2 := filepath.Join(varsDir, "vars-2")
   439  						err = ioutil.WriteFile(varsFilePath2, []byte("var2: 4"), 0666)
   440  						Expect(err).ToNot(HaveOccurred())
   441  
   442  						pathsToVarsFiles = append(pathsToVarsFiles, varsFilePath1, varsFilePath2)
   443  					})
   444  
   445  					It("interpolates the placeholder values", func() {
   446  						Expect(executeErr).ToNot(HaveOccurred())
   447  						Expect(apps[0].Name).To(Equal("app-1"))
   448  						Expect(apps[0].Instances).To(Equal(types.NullInt{Value: 4, IsSet: true}))
   449  					})
   450  				})
   451  
   452  				Context("when the provided files exists and contain valid yaml", func() {
   453  					It("interpolates the placeholder values", func() {
   454  						Expect(executeErr).ToNot(HaveOccurred())
   455  						Expect(apps[0].Name).To(Equal("app-1"))
   456  						Expect(apps[0].Instances).To(Equal(types.NullInt{Value: 4, IsSet: true}))
   457  					})
   458  				})
   459  
   460  				Context("when a variable in the manifest is not provided in the vars file", func() {
   461  					BeforeEach(func() {
   462  						varsFilePath := filepath.Join(varsDir, "vars-1")
   463  						err := ioutil.WriteFile(varsFilePath, []byte("notvar: foo"), 0666)
   464  						Expect(err).ToNot(HaveOccurred())
   465  
   466  						pathsToVarsFiles = []string{varsFilePath}
   467  					})
   468  
   469  					It("returns an error", func() {
   470  						Expect(executeErr.Error()).To(Equal("Expected to find variables: var1, var2"))
   471  					})
   472  				})
   473  
   474  				Context("when the provided file path does not exist", func() {
   475  					BeforeEach(func() {
   476  						pathsToVarsFiles = []string{"garbagepath"}
   477  					})
   478  
   479  					It("returns an error", func() {
   480  						Expect(executeErr).To(HaveOccurred())
   481  						Expect(os.IsNotExist(executeErr)).To(BeTrue())
   482  					})
   483  				})
   484  
   485  				Context("when the provided file is not a valid yaml file", func() {
   486  					BeforeEach(func() {
   487  						varsFilePath := filepath.Join(varsDir, "vars-1")
   488  						err := ioutil.WriteFile(varsFilePath, []byte(": bad"), 0666)
   489  						Expect(err).ToNot(HaveOccurred())
   490  
   491  						pathsToVarsFiles = []string{varsFilePath}
   492  					})
   493  
   494  					It("returns an error", func() {
   495  						Expect(executeErr).To(HaveOccurred())
   496  						Expect(executeErr).To(MatchError(InvalidYAMLError{
   497  							Err: errors.New("yaml: did not find expected key"),
   498  						}))
   499  					})
   500  				})
   501  			})
   502  
   503  			Context("when only vars are provided", func() {
   504  				BeforeEach(func() {
   505  					vars = []template.VarKV{
   506  						{Name: "var1", Value: "app-1"},
   507  						{Name: "var2", Value: 4},
   508  					}
   509  					manifest = `---
   510  applications:
   511  - name: ((var1))
   512    instances: ((var2))
   513  `
   514  				})
   515  
   516  				It("interpolates the placeholder values", func() {
   517  					Expect(executeErr).ToNot(HaveOccurred())
   518  					Expect(apps[0].Name).To(Equal("app-1"))
   519  					Expect(apps[0].Instances).To(Equal(types.NullInt{Value: 4, IsSet: true}))
   520  				})
   521  			})
   522  
   523  			Context("when vars and vars files are provided", func() {
   524  				var varsFilePath string
   525  				BeforeEach(func() {
   526  					tmp, err := ioutil.TempFile("", "util-manifest-varsilfe")
   527  					Expect(err).NotTo(HaveOccurred())
   528  					Expect(tmp.Close()).NotTo(HaveOccurred())
   529  
   530  					varsFilePath = tmp.Name()
   531  					err = ioutil.WriteFile(varsFilePath, []byte("var1: app-1\nvar2: 12345"), 0666)
   532  					Expect(err).ToNot(HaveOccurred())
   533  
   534  					pathsToVarsFiles = []string{varsFilePath}
   535  					vars = []template.VarKV{
   536  						{Name: "var2", Value: 4},
   537  					}
   538  				})
   539  
   540  				AfterEach(func() {
   541  					Expect(os.RemoveAll(varsFilePath)).ToNot(HaveOccurred())
   542  				})
   543  
   544  				It("interpolates the placeholder values, prioritizing the vars flag", func() {
   545  					Expect(executeErr).ToNot(HaveOccurred())
   546  					Expect(apps[0].Name).To(Equal("app-1"))
   547  					Expect(apps[0].Instances).To(Equal(types.NullInt{Value: 4, IsSet: true}))
   548  				})
   549  			})
   550  		})
   551  	})
   552  
   553  	Describe("WriteApplicationManifest", func() {
   554  		var (
   555  			application Application
   556  			tmpDir      string
   557  			filePath    string
   558  
   559  			executeErr error
   560  		)
   561  
   562  		BeforeEach(func() {
   563  			var err error
   564  			tmpDir, err = ioutil.TempDir("", "manifest-test-")
   565  			Expect(err).NotTo(HaveOccurred())
   566  			filePath = filepath.Join(tmpDir, "manifest.yml")
   567  		})
   568  
   569  		AfterEach(func() {
   570  			os.RemoveAll(tmpDir)
   571  		})
   572  
   573  		JustBeforeEach(func() {
   574  			executeErr = WriteApplicationManifest(application, filePath)
   575  		})
   576  
   577  		Context("when all app properties are provided", func() {
   578  			BeforeEach(func() {
   579  				application = Application{
   580  					Name: "app-1",
   581  					Buildpack: types.FilteredString{
   582  						IsSet: true,
   583  						Value: "some-buildpack",
   584  					},
   585  					Buildpacks: []string{"buildpack1", "buildpack2"},
   586  					Command: types.FilteredString{
   587  						IsSet: true,
   588  						Value: "some-command",
   589  					},
   590  					DockerImage:    "some-docker-image",
   591  					DockerUsername: "some-docker-username",
   592  					DockerPassword: "",
   593  					EnvironmentVariables: map[string]string{
   594  						"env_1": "foo",
   595  						"env_2": "182837403930483038",
   596  						"env_3": "true",
   597  						"env_4": "1.00001",
   598  					},
   599  					HealthCheckHTTPEndpoint: "\\some-endpoint",
   600  					HealthCheckType:         "http",
   601  					Instances: types.NullInt{
   602  						Value: 10,
   603  						IsSet: true,
   604  					},
   605  					DiskQuota: types.NullByteSizeInMb{
   606  						Value: 1024,
   607  						IsSet: true,
   608  					},
   609  					Memory: types.NullByteSizeInMb{
   610  						Value: 200,
   611  						IsSet: true,
   612  					},
   613  					NoRoute:            true,
   614  					Routes:             []string{"foo.bar.com", "baz.qux.com", "blep.blah.com/boop"},
   615  					Services:           []string{"service_1", "service_2"},
   616  					StackName:          "some-stack",
   617  					HealthCheckTimeout: 120,
   618  				}
   619  			})
   620  
   621  			It("creates and writes the manifest to the specified filepath", func() {
   622  				Expect(executeErr).NotTo(HaveOccurred())
   623  				manifestBytes, err := ioutil.ReadFile(filePath)
   624  				Expect(err).NotTo(HaveOccurred())
   625  				Expect(string(manifestBytes)).To(Equal(`applications:
   626  - name: app-1
   627    buildpack: some-buildpack
   628    buildpacks:
   629    - buildpack1
   630    - buildpack2
   631    command: some-command
   632    disk_quota: 1G
   633    docker:
   634      image: some-docker-image
   635      username: some-docker-username
   636    env:
   637      env_1: foo
   638      env_2: "182837403930483038"
   639      env_3: "true"
   640      env_4: "1.00001"
   641    health-check-http-endpoint: \some-endpoint
   642    health-check-type: http
   643    instances: 10
   644    memory: 200M
   645    no-route: true
   646    routes:
   647    - route: foo.bar.com
   648    - route: baz.qux.com
   649    - route: blep.blah.com/boop
   650    services:
   651    - service_1
   652    - service_2
   653    stack: some-stack
   654    timeout: 120
   655  `))
   656  			})
   657  		})
   658  
   659  		Context("when some properties are not provided", func() {
   660  			BeforeEach(func() {
   661  				application = Application{
   662  					Name: "app-1",
   663  				}
   664  			})
   665  
   666  			It("does not save them in manifest", func() {
   667  				Expect(executeErr).NotTo(HaveOccurred())
   668  				manifestBytes, err := ioutil.ReadFile(filePath)
   669  				Expect(err).NotTo(HaveOccurred())
   670  				Expect(string(manifestBytes)).To(Equal(`applications:
   671  - name: app-1
   672  `))
   673  			})
   674  		})
   675  
   676  		Context("when the file is a relative path", func() {
   677  			var pwd string
   678  
   679  			BeforeEach(func() {
   680  				var err error
   681  				pwd, err = os.Getwd()
   682  				Expect(err).ToNot(HaveOccurred())
   683  
   684  				filePath = "./manifest.yml"
   685  				Expect(os.Chdir(tmpDir)).To(Succeed())
   686  
   687  				application = Application{
   688  					Name: "app-1",
   689  				}
   690  			})
   691  
   692  			AfterEach(func() {
   693  				Expect(os.Chdir(pwd)).To(Succeed())
   694  			})
   695  
   696  			It("writes the file in an expanded path", func() {
   697  				Expect(executeErr).ToNot(HaveOccurred())
   698  				manifestBytes, err := ioutil.ReadFile(filepath.Join(tmpDir, "manifest.yml"))
   699  				Expect(err).ToNot(HaveOccurred())
   700  				Expect(string(manifestBytes)).To(Equal(`applications:
   701  - name: app-1
   702  `))
   703  			})
   704  		})
   705  
   706  		Context("when the file already exists", func() {
   707  			BeforeEach(func() {
   708  				err := ioutil.WriteFile(filePath, []byte(`{}`), 0644)
   709  				Expect(err).ToNot(HaveOccurred())
   710  				application = Application{
   711  					Name: "app-1",
   712  				}
   713  			})
   714  
   715  			Context("writes the file", func() {
   716  				It("truncates and writes the manifest to specified filepath", func() {
   717  					Expect(executeErr).ToNot(HaveOccurred())
   718  					manifestBytes, err := ioutil.ReadFile(filePath)
   719  					Expect(err).ToNot(HaveOccurred())
   720  					Expect(string(manifestBytes)).To(Equal(`applications:
   721  - name: app-1
   722  `))
   723  				})
   724  			})
   725  		})
   726  	})
   727  })