github.com/liamawhite/cli-with-i18n@v6.32.1-0.20171122084555-dede0a5c3448+incompatible/cf/commands/application/app_test.go (about)

     1  package application_test
     2  
     3  import (
     4  	"encoding/json"
     5  	"time"
     6  
     7  	"github.com/liamawhite/cli-with-i18n/cf/api"
     8  	"github.com/liamawhite/cli-with-i18n/cf/api/resources"
     9  	"github.com/liamawhite/cli-with-i18n/cf/api/stacks/stacksfakes"
    10  	"github.com/liamawhite/cli-with-i18n/cf/commandregistry"
    11  	"github.com/liamawhite/cli-with-i18n/cf/commands/application"
    12  	"github.com/liamawhite/cli-with-i18n/cf/errors"
    13  	"github.com/liamawhite/cli-with-i18n/cf/flags"
    14  	"github.com/liamawhite/cli-with-i18n/cf/formatters"
    15  	"github.com/liamawhite/cli-with-i18n/cf/models"
    16  	"github.com/liamawhite/cli-with-i18n/cf/requirements"
    17  	"github.com/liamawhite/cli-with-i18n/cf/requirements/requirementsfakes"
    18  	"github.com/liamawhite/cli-with-i18n/plugin/models"
    19  
    20  	testconfig "github.com/liamawhite/cli-with-i18n/util/testhelpers/configuration"
    21  	testterm "github.com/liamawhite/cli-with-i18n/util/testhelpers/terminal"
    22  
    23  	"github.com/liamawhite/cli-with-i18n/cf/api/apifakes"
    24  	"github.com/liamawhite/cli-with-i18n/cf/api/appinstances/appinstancesfakes"
    25  
    26  	. "github.com/liamawhite/cli-with-i18n/util/testhelpers/matchers"
    27  
    28  	. "github.com/onsi/ginkgo"
    29  	. "github.com/onsi/gomega"
    30  )
    31  
    32  var _ = Describe("App", func() {
    33  	var (
    34  		ui               *testterm.FakeUI
    35  		appSummaryRepo   *apifakes.FakeAppSummaryRepository
    36  		appInstancesRepo *appinstancesfakes.FakeAppInstancesRepository
    37  		stackRepo        *stacksfakes.FakeStackRepository
    38  		getAppModel      *plugin_models.GetAppModel
    39  
    40  		cmd         commandregistry.Command
    41  		deps        commandregistry.Dependency
    42  		factory     *requirementsfakes.FakeFactory
    43  		flagContext flags.FlagContext
    44  
    45  		loginRequirement         requirements.Requirement
    46  		targetedSpaceRequirement requirements.Requirement
    47  		applicationRequirement   *requirementsfakes.FakeApplicationRequirement
    48  	)
    49  
    50  	BeforeEach(func() {
    51  		cmd = &application.ShowApp{}
    52  		flagContext = flags.NewFlagContext(cmd.MetaData().Flags)
    53  
    54  		ui = &testterm.FakeUI{}
    55  
    56  		getAppModel = &plugin_models.GetAppModel{}
    57  
    58  		repoLocator := api.RepositoryLocator{}
    59  		appSummaryRepo = new(apifakes.FakeAppSummaryRepository)
    60  		repoLocator = repoLocator.SetAppSummaryRepository(appSummaryRepo)
    61  		appInstancesRepo = new(appinstancesfakes.FakeAppInstancesRepository)
    62  		repoLocator = repoLocator.SetAppInstancesRepository(appInstancesRepo)
    63  		stackRepo = new(stacksfakes.FakeStackRepository)
    64  		repoLocator = repoLocator.SetStackRepository(stackRepo)
    65  
    66  		deps = commandregistry.Dependency{
    67  			UI:     ui,
    68  			Config: testconfig.NewRepositoryWithDefaults(),
    69  			PluginModels: &commandregistry.PluginModels{
    70  				Application: getAppModel,
    71  			},
    72  			RepoLocator: repoLocator,
    73  		}
    74  
    75  		cmd.SetDependency(deps, false)
    76  
    77  		factory = new(requirementsfakes.FakeFactory)
    78  
    79  		loginRequirement = &passingRequirement{}
    80  		factory.NewLoginRequirementReturns(loginRequirement)
    81  
    82  		targetedSpaceRequirement = &passingRequirement{}
    83  		factory.NewTargetedSpaceRequirementReturns(targetedSpaceRequirement)
    84  
    85  		applicationRequirement = new(requirementsfakes.FakeApplicationRequirement)
    86  		factory.NewApplicationRequirementReturns(applicationRequirement)
    87  	})
    88  
    89  	Describe("Requirements", func() {
    90  		Context("when not provided exactly one arg", func() {
    91  			BeforeEach(func() {
    92  				flagContext.Parse("app-name", "extra-arg")
    93  			})
    94  
    95  			It("fails with usage", func() {
    96  				_, err := cmd.Requirements(factory, flagContext)
    97  				Expect(err).To(HaveOccurred())
    98  				Expect(ui.Outputs()).To(ContainSubstrings(
    99  					[]string{"Incorrect Usage. Requires an argument"},
   100  					[]string{"NAME"},
   101  					[]string{"USAGE"},
   102  				))
   103  			})
   104  		})
   105  
   106  		Context("when provided exactly one arg", func() {
   107  			BeforeEach(func() {
   108  				flagContext.Parse("app-name")
   109  			})
   110  
   111  			It("returns a LoginRequirement", func() {
   112  				actualRequirements, err := cmd.Requirements(factory, flagContext)
   113  				Expect(err).NotTo(HaveOccurred())
   114  				Expect(factory.NewLoginRequirementCallCount()).To(Equal(1))
   115  
   116  				Expect(actualRequirements).To(ContainElement(loginRequirement))
   117  			})
   118  
   119  			It("returns a TargetedSpaceRequirement", func() {
   120  				actualRequirements, err := cmd.Requirements(factory, flagContext)
   121  				Expect(err).NotTo(HaveOccurred())
   122  				Expect(factory.NewTargetedSpaceRequirementCallCount()).To(Equal(1))
   123  
   124  				Expect(actualRequirements).To(ContainElement(targetedSpaceRequirement))
   125  			})
   126  
   127  			It("returns an ApplicationRequirement", func() {
   128  				actualRequirements, err := cmd.Requirements(factory, flagContext)
   129  				Expect(err).NotTo(HaveOccurred())
   130  				Expect(factory.NewApplicationRequirementCallCount()).To(Equal(1))
   131  				Expect(factory.NewApplicationRequirementArgsForCall(0)).To(Equal("app-name"))
   132  
   133  				Expect(actualRequirements).To(ContainElement(applicationRequirement))
   134  			})
   135  		})
   136  	})
   137  
   138  	Describe("Execute", func() {
   139  		var (
   140  			getApplicationModel models.Application
   141  			getAppSummaryModel  models.Application
   142  			appStackModel       models.Stack
   143  			appInstanceFields   []models.AppInstanceFields
   144  			getAppSummaryErr    error
   145  			err                 error
   146  		)
   147  
   148  		BeforeEach(func() {
   149  			err := flagContext.Parse("app-name")
   150  			Expect(err).NotTo(HaveOccurred())
   151  			cmd.Requirements(factory, flagContext)
   152  
   153  			paginatedApplicationResources := resources.PaginatedApplicationResources{}
   154  			err = json.Unmarshal([]byte(getApplicationJSON), &paginatedApplicationResources)
   155  			Expect(err).NotTo(HaveOccurred())
   156  
   157  			getApplicationModel = paginatedApplicationResources.Resources[0].ToModel()
   158  
   159  			applicationFromSummary := api.ApplicationFromSummary{}
   160  			err = json.Unmarshal([]byte(getSummaryJSON), &applicationFromSummary)
   161  			Expect(err).NotTo(HaveOccurred())
   162  
   163  			getAppSummaryModel = applicationFromSummary.ToModel()
   164  
   165  			appInstanceFields = []models.AppInstanceFields{
   166  				{
   167  					State:     models.InstanceRunning,
   168  					Details:   "fake-instance-details",
   169  					Since:     time.Date(2015, time.November, 19, 1, 1, 17, 0, time.UTC),
   170  					CPUUsage:  float64(0.25),
   171  					DiskUsage: int64(1 * formatters.GIGABYTE),
   172  					DiskQuota: int64(2 * formatters.GIGABYTE),
   173  					MemUsage:  int64(24 * formatters.MEGABYTE),
   174  					MemQuota:  int64(32 * formatters.MEGABYTE),
   175  				},
   176  			}
   177  
   178  			appStackModel = models.Stack{
   179  				GUID: "fake-stack-guid",
   180  				Name: "fake-stack-name",
   181  			}
   182  
   183  			applicationRequirement.GetApplicationReturns(getApplicationModel)
   184  			appSummaryRepo.GetSummaryReturns(getAppSummaryModel, getAppSummaryErr)
   185  			appInstancesRepo.GetInstancesReturns(appInstanceFields, nil)
   186  			stackRepo.FindByGUIDReturns(appStackModel, nil)
   187  		})
   188  
   189  		JustBeforeEach(func() {
   190  			err = cmd.Execute(flagContext)
   191  		})
   192  
   193  		It("gets the application summary", func() {
   194  			Expect(err).NotTo(HaveOccurred())
   195  			Expect(appSummaryRepo.GetSummaryCallCount()).To(Equal(1))
   196  		})
   197  
   198  		It("gets the app instances", func() {
   199  			Expect(err).NotTo(HaveOccurred())
   200  			Expect(appInstancesRepo.GetInstancesCallCount()).To(Equal(1))
   201  		})
   202  
   203  		It("gets the application from the application requirement", func() {
   204  			Expect(err).NotTo(HaveOccurred())
   205  			Expect(applicationRequirement.GetApplicationCallCount()).To(Equal(1))
   206  		})
   207  
   208  		It("gets the stack name from the stack repository", func() {
   209  			Expect(err).NotTo(HaveOccurred())
   210  			Expect(stackRepo.FindByGUIDCallCount()).To(Equal(1))
   211  		})
   212  
   213  		It("prints a summary of the app", func() {
   214  			Expect(err).NotTo(HaveOccurred())
   215  			Expect(ui.Outputs()).To(ContainSubstrings(
   216  				[]string{"Showing health and status for app fake-app-name"},
   217  				[]string{"requested state: started"},
   218  				[]string{"instances: 1/1"},
   219  				// Commented to hide app-ports for release #117189491
   220  				// []string{"app ports: 8080, 9090"},
   221  				[]string{"usage: 1G x 1 instances"},
   222  				[]string{"urls: fake-route-host.fake-route-domain-name"},
   223  				[]string{"last uploaded: Thu Nov 19 01:00:15 UTC 2015"},
   224  				[]string{"stack: fake-stack-name"},
   225  				// buildpack tested separately
   226  				[]string{"#0", "running", "2015-11-19 01:01:17 AM", "25.0%", "24M of 32M", "1G of 2G"},
   227  			))
   228  		})
   229  
   230  		Context("when getting the application summary fails because the app is stopped", func() {
   231  			BeforeEach(func() {
   232  				getAppSummaryModel.RunningInstances = 0
   233  				getAppSummaryModel.InstanceCount = 1
   234  				getAppSummaryModel.State = "stopped"
   235  				appSummaryRepo.GetSummaryReturns(getAppSummaryModel, errors.NewHTTPError(400, errors.InstancesError, "error"))
   236  			})
   237  
   238  			It("prints appropriate output", func() {
   239  				Expect(err).NotTo(HaveOccurred())
   240  				Expect(ui.Outputs()).To(ContainSubstrings(
   241  					[]string{"Showing health and status", "fake-app-name", "my-org", "my-space", "my-user"},
   242  					[]string{"state", "stopped"},
   243  					[]string{"instances", "0/1"},
   244  					[]string{"usage", "1G x 1 instances"},
   245  					[]string{"There are no running instances of this app."},
   246  				))
   247  			})
   248  		})
   249  
   250  		Context("when getting the application summary fails because the app has not yet finished staged", func() {
   251  			BeforeEach(func() {
   252  				getAppSummaryModel.RunningInstances = 0
   253  				getAppSummaryModel.InstanceCount = 1
   254  				getAppSummaryModel.State = "stopped"
   255  				appSummaryRepo.GetSummaryReturns(getAppSummaryModel, errors.NewHTTPError(400, errors.NotStaged, "error"))
   256  			})
   257  
   258  			It("prints appropriate output", func() {
   259  				Expect(err).NotTo(HaveOccurred())
   260  				Expect(ui.Outputs()).To(ContainSubstrings(
   261  					[]string{"Showing health and status", "fake-app-name", "my-org", "my-space", "my-user"},
   262  					[]string{"state", "stopped"},
   263  					[]string{"instances", "0/1"},
   264  					[]string{"usage", "1G x 1 instances"},
   265  					[]string{"There are no running instances of this app."},
   266  				))
   267  			})
   268  		})
   269  
   270  		Context("when getting the application summary fails for any other reason", func() {
   271  			BeforeEach(func() {
   272  				getAppSummaryModel.RunningInstances = 0
   273  				getAppSummaryModel.InstanceCount = 1
   274  				appSummaryRepo.GetSummaryReturns(getAppSummaryModel, errors.New("an-error"))
   275  			})
   276  
   277  			It("returns an error", func() {
   278  				Expect(err).To(HaveOccurred())
   279  				Expect(err.Error()).To(Equal("an-error"))
   280  			})
   281  
   282  			Context("when the app is stopped", func() {
   283  				BeforeEach(func() {
   284  					getAppSummaryModel.State = "stopped"
   285  					appSummaryRepo.GetSummaryReturns(getAppSummaryModel, errors.New("an-error"))
   286  				})
   287  
   288  				It("prints appropriate output", func() {
   289  					Expect(err).NotTo(HaveOccurred())
   290  					Expect(ui.Outputs()).To(ContainSubstrings(
   291  						[]string{"Showing health and status", "fake-app-name", "my-org", "my-space", "my-user"},
   292  						[]string{"state", "stopped"},
   293  						[]string{"instances", "0/1"},
   294  						[]string{"usage", "1G x 1 instances"},
   295  						[]string{"There are no running instances of this app."},
   296  					))
   297  				})
   298  			})
   299  		})
   300  
   301  		Context("when getting the app instances fails", func() {
   302  			BeforeEach(func() {
   303  				appInstancesRepo.GetInstancesReturns([]models.AppInstanceFields{}, errors.New("an-error"))
   304  			})
   305  
   306  			It("returns an error", func() {
   307  				Expect(err).To(HaveOccurred())
   308  				Expect(err.Error()).To(Equal("an-error"))
   309  			})
   310  
   311  			Context("when the app is stopped", func() {
   312  				BeforeEach(func() {
   313  					getAppSummaryModel.RunningInstances = 0
   314  					getAppSummaryModel.State = "stopped"
   315  					appSummaryRepo.GetSummaryReturns(getAppSummaryModel, nil)
   316  				})
   317  
   318  				It("prints appropriate output", func() {
   319  					Expect(err).NotTo(HaveOccurred())
   320  					Expect(ui.Outputs()).To(ContainSubstrings(
   321  						[]string{"Showing health and status", "fake-app-name", "my-org", "my-space", "my-user"},
   322  						[]string{"state", "stopped"},
   323  						[]string{"instances", "0/1"},
   324  						[]string{"usage", "1G x 1 instances"},
   325  						[]string{"There are no running instances of this app."},
   326  					))
   327  				})
   328  			})
   329  		})
   330  
   331  		Context("when the package updated at is missing", func() {
   332  			BeforeEach(func() {
   333  				getAppSummaryModel.PackageUpdatedAt = nil
   334  				appSummaryRepo.GetSummaryReturns(getAppSummaryModel, nil)
   335  			})
   336  
   337  			It("prints 'unknown' as last uploaded", func() {
   338  				Expect(err).NotTo(HaveOccurred())
   339  
   340  				Expect(ui.Outputs()).To(ContainSubstrings(
   341  					[]string{"last uploaded: unknown"},
   342  				))
   343  			})
   344  		})
   345  
   346  		Context("when the application has no app ports", func() {
   347  			BeforeEach(func() {
   348  				getAppSummaryModel.AppPorts = []int{}
   349  				appSummaryRepo.GetSummaryReturns(getAppSummaryModel, nil)
   350  			})
   351  
   352  			It("does not print 'app ports'", func() {
   353  				Expect(err).NotTo(HaveOccurred())
   354  
   355  				Expect(ui.Outputs()).NotTo(ContainSubstrings(
   356  					[]string{"app ports:"},
   357  				))
   358  			})
   359  		})
   360  
   361  		Context("when the GetApplication model includes a buildpack", func() {
   362  			// this should be the GetAppSummary model
   363  			BeforeEach(func() {
   364  				getApplicationModel.Buildpack = "fake-buildpack"
   365  				getApplicationModel.DetectedBuildpack = ""
   366  				applicationRequirement.GetApplicationReturns(getApplicationModel)
   367  			})
   368  
   369  			It("prints the buildpack", func() {
   370  				Expect(err).NotTo(HaveOccurred())
   371  
   372  				Expect(ui.Outputs()).To(ContainSubstrings(
   373  					[]string{"buildpack", "fake-buildpack"},
   374  				))
   375  			})
   376  		})
   377  
   378  		Context("when the GetApplication Model includes a detected buildpack", func() {
   379  			// this should be the GetAppSummary model
   380  			BeforeEach(func() {
   381  				getApplicationModel.Buildpack = ""
   382  				getApplicationModel.DetectedBuildpack = "fake-detected-buildpack"
   383  				applicationRequirement.GetApplicationReturns(getApplicationModel)
   384  			})
   385  
   386  			It("prints the detected buildpack", func() {
   387  				Expect(err).NotTo(HaveOccurred())
   388  
   389  				Expect(ui.Outputs()).To(ContainSubstrings(
   390  					[]string{"buildpack", "fake-detected-buildpack"},
   391  				))
   392  			})
   393  		})
   394  
   395  		Context("when the GetApplication Model does not include a buildpack or detected buildpack", func() {
   396  			// this should be the GetAppSummary model
   397  			BeforeEach(func() {
   398  				getApplicationModel.Buildpack = ""
   399  				getApplicationModel.DetectedBuildpack = ""
   400  				applicationRequirement.GetApplicationReturns(getApplicationModel)
   401  			})
   402  
   403  			It("prints the 'unknown' as the buildpack", func() {
   404  				Expect(err).NotTo(HaveOccurred())
   405  				Expect(ui.Outputs()).To(ContainSubstrings(
   406  					[]string{"buildpack", "unknown"},
   407  				))
   408  			})
   409  		})
   410  
   411  		Context("when running instances is -1", func() {
   412  			BeforeEach(func() {
   413  				getAppSummaryModel.RunningInstances = -1
   414  				appSummaryRepo.GetSummaryReturns(getAppSummaryModel, nil)
   415  			})
   416  
   417  			It("displays a '?' for running instances", func() {
   418  				Expect(err).NotTo(HaveOccurred())
   419  				Expect(ui.Outputs()).To(ContainSubstrings(
   420  					[]string{"instances", "?/1"},
   421  				))
   422  			})
   423  		})
   424  
   425  		Context("when the --guid flag is passed", func() {
   426  			BeforeEach(func() {
   427  				flagContext.Parse("app-name", "--guid")
   428  			})
   429  
   430  			It("only prints the guid for the app", func() {
   431  				Expect(err).NotTo(HaveOccurred())
   432  				Expect(ui.Outputs()).To(ContainSubstrings(
   433  					[]string{"fake-app-guid"},
   434  				))
   435  				Expect(ui.Outputs()).ToNot(ContainSubstrings(
   436  					[]string{"Showing health and status", "my-app"},
   437  				))
   438  			})
   439  		})
   440  
   441  		Context("when called from a plugin", func() {
   442  			BeforeEach(func() {
   443  				cmd.SetDependency(deps, true)
   444  			})
   445  
   446  			Context("when the app is running", func() {
   447  				It("populates the plugin model", func() {
   448  					Expect(err).NotTo(HaveOccurred())
   449  
   450  					// from AppRequirement model
   451  					Expect(getAppModel.Stack.Name).To(Equal("fake-stack-name"))
   452  					Expect(getAppModel.Stack.Guid).To(Equal("fake-stack-guid"))
   453  
   454  					// from GetAppSummary model
   455  					Expect(getAppModel.Name).To(Equal("fake-app-name"))
   456  					Expect(getAppModel.State).To(Equal("started"))
   457  					Expect(getAppModel.Guid).To(Equal("fake-app-guid"))
   458  					Expect(getAppModel.Command).To(Equal("fake-command"))
   459  					Expect(getAppModel.Diego).To(BeTrue())
   460  					Expect(getAppModel.DetectedStartCommand).To(Equal("fake-detected-start-command"))
   461  					Expect(getAppModel.DiskQuota).To(Equal(int64(1024)))
   462  					Expect(getAppModel.EnvironmentVars).To(Equal(map[string]interface{}{"fake-env-var": "fake-env-var-value"}))
   463  					Expect(getAppModel.InstanceCount).To(Equal(1))
   464  					Expect(getAppModel.Memory).To(Equal(int64(1024)))
   465  					Expect(getAppModel.RunningInstances).To(Equal(1))
   466  					Expect(getAppModel.HealthCheckTimeout).To(Equal(0))
   467  					Expect(getAppModel.SpaceGuid).To(Equal("fake-space-guid"))
   468  					Expect(getAppModel.PackageUpdatedAt.String()).To(Equal(time.Date(2015, time.November, 19, 1, 0, 15, 0, time.UTC).String()))
   469  					Expect(getAppModel.PackageState).To(Equal("STAGED"))
   470  					Expect(getAppModel.StagingFailedReason).To(BeEmpty())
   471  					Expect(getAppModel.BuildpackUrl).To(Equal("fake-buildpack"))
   472  					Expect(getAppModel.AppPorts).To(Equal([]int{8080, 9090}))
   473  					Expect(getAppModel.Routes[0].Host).To(Equal("fake-route-host"))
   474  					Expect(getAppModel.Routes[0].Guid).To(Equal("fake-route-guid"))
   475  					Expect(getAppModel.Routes[0].Domain.Name).To(Equal("fake-route-domain-name"))
   476  					Expect(getAppModel.Routes[0].Domain.Guid).To(Equal("fake-route-domain-guid"))
   477  					Expect(getAppModel.Routes[0].Path).To(Equal("some-path"))
   478  					Expect(getAppModel.Routes[0].Port).To(Equal(3333))
   479  					Expect(getAppModel.Services[0].Guid).To(Equal("fake-service-guid"))
   480  					Expect(getAppModel.Services[0].Name).To(Equal("fake-service-name"))
   481  
   482  					// from GetInstances model
   483  					Expect(getAppModel.Instances[0].State).To(Equal("running"))
   484  					Expect(getAppModel.Instances[0].Details).To(Equal("fake-instance-details"))
   485  					Expect(getAppModel.Instances[0].CpuUsage).To(Equal(float64(0.25)))
   486  					Expect(getAppModel.Instances[0].DiskUsage).To(Equal(int64(1 * formatters.GIGABYTE)))
   487  					Expect(getAppModel.Instances[0].DiskQuota).To(Equal(int64(2 * formatters.GIGABYTE)))
   488  					Expect(getAppModel.Instances[0].MemUsage).To(Equal(int64(24 * formatters.MEGABYTE)))
   489  					Expect(getAppModel.Instances[0].MemQuota).To(Equal(int64(32 * formatters.MEGABYTE)))
   490  				})
   491  			})
   492  
   493  			Context("when the app is stopped but instance is returning back an error", func() {
   494  				BeforeEach(func() {
   495  					getAppSummaryModel.State = "stopped"
   496  					appSummaryRepo.GetSummaryReturns(getAppSummaryModel, nil)
   497  
   498  					var instances []models.AppInstanceFields //Very important since this is a nil body
   499  					appInstancesRepo.GetInstancesReturns(instances, errors.New("Bonzi"))
   500  				})
   501  
   502  				It("populates the plugin model with empty sets", func() {
   503  					Expect(err).NotTo(HaveOccurred())
   504  
   505  					Expect(getAppModel.Instances).ToNot(BeNil())
   506  					Expect(getAppModel.Instances).To(BeEmpty())
   507  				})
   508  			})
   509  
   510  			Context("when the there are no routes", func() {
   511  				BeforeEach(func() {
   512  					app := models.Application{
   513  						Stack: &models.Stack{
   514  							GUID: "stack-guid",
   515  							Name: "stack-name",
   516  						},
   517  					}
   518  					appSummaryRepo.GetSummaryReturns(app, nil)
   519  				})
   520  
   521  				It("populates the plugin model with empty sets", func() {
   522  					Expect(err).NotTo(HaveOccurred())
   523  
   524  					Expect(getAppModel.Routes).ToNot(BeNil())
   525  					Expect(getAppModel.Routes).To(BeEmpty())
   526  				})
   527  			})
   528  
   529  			Context("when the there are no services", func() {
   530  				BeforeEach(func() {
   531  					app := models.Application{
   532  						Stack: &models.Stack{
   533  							GUID: "stack-guid",
   534  							Name: "stack-name",
   535  						},
   536  					}
   537  					appSummaryRepo.GetSummaryReturns(app, nil)
   538  				})
   539  
   540  				It("populates the plugin model with empty sets", func() {
   541  					Expect(err).NotTo(HaveOccurred())
   542  
   543  					Expect(getAppModel.Services).ToNot(BeNil())
   544  					Expect(getAppModel.Services).To(BeEmpty())
   545  				})
   546  			})
   547  		})
   548  	})
   549  })
   550  
   551  var getApplicationJSON string = `{
   552    "total_results": 1,
   553    "total_pages": 1,
   554    "prev_url": null,
   555    "next_url": null,
   556    "resources": [
   557      {
   558        "metadata": {
   559          "guid": "fake-app-guid",
   560          "url": "fake-url",
   561          "created_at": "2015-11-19T01:00:12Z",
   562          "updated_at": "2015-11-19T01:01:04Z"
   563        },
   564        "entity": {
   565          "name": "fake-app-name",
   566          "production": false,
   567          "space_guid": "fake-space-guid",
   568          "stack_guid": "fake-stack-guid",
   569          "buildpack": null,
   570          "detected_buildpack": "fake-detected-buildpack",
   571  				"environment_json": {
   572  					"fake-env-var": "fake-env-var-value"
   573  				},
   574  				"memory": 1024,
   575          "instances": 1,
   576          "disk_quota": 1024,
   577          "state": "started",
   578          "version": "fake-version",
   579          "command": "fake-command",
   580          "console": false,
   581          "debug": null,
   582          "staging_task_id": "fake-staging-task-id",
   583          "package_state": "STAGED",
   584          "health_check_type": "port",
   585          "health_check_timeout": null,
   586          "staging_failed_reason": null,
   587          "staging_failed_description": null,
   588          "diego": true,
   589          "docker_image": null,
   590          "package_updated_at": "2015-11-19T01:00:15Z",
   591          "detected_start_command": "fake-detected-start-command",
   592          "enable_ssh": true,
   593          "docker_credentials_json": {
   594            "redacted_message": "[PRIVATE DATA HIDDEN]"
   595          },
   596          "ports": [
   597            8080,
   598            9090
   599  				],
   600          "space_url": "fake-space-url",
   601          "space": {
   602            "metadata": {
   603              "guid": "fake-space-guid",
   604              "url": "fake-space-url",
   605              "created_at": "2014-05-12T23:36:57Z",
   606              "updated_at": null
   607            },
   608            "entity": {
   609              "name": "fake-space-name",
   610              "organization_guid": "fake-space-organization-guid",
   611              "space_quota_definition_guid": null,
   612              "allow_ssh": true,
   613              "organization_url": "fake-space-organization-url",
   614              "developers_url": "fake-space-developers-url",
   615              "managers_url": "fake-space-managers-url",
   616              "auditors_url": "fake-space-auditors-url",
   617              "apps_url": "fake-space-apps-url",
   618              "routes_url": "fake-space-routes-url",
   619              "domains_url": "fake-space-domains-url",
   620              "service_instances_url": "fake-space-service-instances-url",
   621              "app_events_url": "fake-space-app-events-url",
   622              "events_url": "fake-space-events-url",
   623              "security_groups_url": "fake-space-security-groups-url"
   624            }
   625          },
   626          "stack_url": "fake-stack-url",
   627          "stack": {
   628            "metadata": {
   629              "guid": "fake-stack-guid",
   630              "url": "fake-stack-url",
   631              "created_at": "2015-03-04T18:58:42Z",
   632              "updated_at": null
   633            },
   634            "entity": {
   635              "name": "fake-stack-name",
   636              "description": "fake-stack-description"
   637            }
   638          },
   639          "events_url": "fake-events-url",
   640          "service_bindings_url": "fake-service-bindings-url",
   641          "service_bindings": [],
   642          "routes_url": "fake-routes-url",
   643          "routes": [
   644            {
   645              "metadata": {
   646                "guid": "fake-route-guid",
   647                "url": "fake-route-url",
   648                "created_at": "2014-05-13T21:38:42Z",
   649                "updated_at": null
   650              },
   651              "entity": {
   652                "host": "fake-route-host",
   653                "path": "",
   654                "domain_guid": "fake-route-domain-guid",
   655                "space_guid": "fake-route-space-guid",
   656                "service_instance_guid": null,
   657                "port": 0,
   658                "domain_url": "fake-route-domain-url",
   659                "space_url": "fake-route-space-url",
   660                "apps_url": "fake-route-apps-url"
   661              }
   662            }
   663          ]
   664        }
   665      }
   666    ]
   667  }`
   668  
   669  var getSummaryJSON string = `{
   670  	"guid": "fake-app-guid",
   671  	"name": "fake-app-name",
   672  	"routes": [
   673  	{
   674  		"guid": "fake-route-guid",
   675  		"host": "fake-route-host",
   676  		"domain": {
   677  			"guid": "fake-route-domain-guid",
   678  			"name": "fake-route-domain-name"
   679  		},
   680  		"path": "some-path",
   681      "port": 3333
   682  	}
   683  	],
   684  	"running_instances": 1,
   685  	"services": [
   686  	{
   687  		"guid": "fake-service-guid",
   688  		"name": "fake-service-name",
   689  		"bound_app_count": 1,
   690  		"last_operation": null,
   691  		"dashboard_url": null,
   692  		"service_plan": {
   693  			"guid": "fake-service-plan-guid",
   694  			"name": "fake-service-plan-name",
   695  			"service": {
   696  				"guid": "fake-service-plan-service-guid",
   697  				"label": "fake-service-plan-service-label",
   698  				"provider": null,
   699  				"version": null
   700  			}
   701  		}
   702  	}
   703  	],
   704  	"available_domains": [
   705  	{
   706  		"guid": "fake-available-domain-guid",
   707  		"name": "fake-available-domain-name",
   708  		"owning_organization_guid": "fake-owning-organization-guid"
   709  	}
   710  	],
   711  	"production": false,
   712  	"space_guid": "fake-space-guid",
   713  	"stack_guid": "fake-stack-guid",
   714  	"buildpack": "fake-buildpack",
   715  	"detected_buildpack": "fake-detected-buildpack",
   716  	"environment_json": {
   717  		"fake-env-var": "fake-env-var-value"
   718  	},
   719  	"memory": 1024,
   720  	"instances": 1,
   721  	"disk_quota": 1024,
   722  	"state": "STARTED",
   723  	"version": "fake-version",
   724  	"command": "fake-command",
   725  	"console": false,
   726  	"debug": null,
   727  	"staging_task_id": "fake-staging-task-id",
   728  	"package_state": "STAGED",
   729  	"health_check_type": "port",
   730  	"health_check_timeout": null,
   731  	"staging_failed_reason": null,
   732  	"staging_failed_description": null,
   733  	"diego": true,
   734  	"docker_image": null,
   735  	"package_updated_at": "2015-11-19T01:00:15Z",
   736  	"detected_start_command": "fake-detected-start-command",
   737  	"enable_ssh": true,
   738  	"docker_credentials_json": {
   739  		"redacted_message": "[PRIVATE DATA HIDDEN]"
   740  	},
   741  	"ports": [
   742  		8080,
   743  		9090
   744  	]
   745  }`