github.com/liamawhite/cli-with-i18n@v6.32.1-0.20171122084555-dede0a5c3448+incompatible/command/v2/app_command_test.go (about)

     1  package v2_test
     2  
     3  import (
     4  	"errors"
     5  	"time"
     6  
     7  	"github.com/cloudfoundry/bytefmt"
     8  	"github.com/liamawhite/cli-with-i18n/actor/actionerror"
     9  	"github.com/liamawhite/cli-with-i18n/actor/sharedaction"
    10  	"github.com/liamawhite/cli-with-i18n/actor/v2action"
    11  	"github.com/liamawhite/cli-with-i18n/api/cloudcontroller/ccv2"
    12  	"github.com/liamawhite/cli-with-i18n/command/commandfakes"
    13  	"github.com/liamawhite/cli-with-i18n/command/translatableerror"
    14  	. "github.com/liamawhite/cli-with-i18n/command/v2"
    15  	"github.com/liamawhite/cli-with-i18n/command/v2/v2fakes"
    16  	"github.com/liamawhite/cli-with-i18n/types"
    17  	"github.com/liamawhite/cli-with-i18n/util/configv3"
    18  	"github.com/liamawhite/cli-with-i18n/util/ui"
    19  	. "github.com/onsi/ginkgo"
    20  	. "github.com/onsi/gomega"
    21  	. "github.com/onsi/gomega/gbytes"
    22  )
    23  
    24  var _ = Describe("App Command", func() {
    25  	var (
    26  		cmd             AppCommand
    27  		testUI          *ui.UI
    28  		fakeConfig      *commandfakes.FakeConfig
    29  		fakeSharedActor *commandfakes.FakeSharedActor
    30  		fakeActor       *v2fakes.FakeAppActor
    31  		binaryName      string
    32  		executeErr      error
    33  	)
    34  
    35  	BeforeEach(func() {
    36  		testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer())
    37  		fakeConfig = new(commandfakes.FakeConfig)
    38  		fakeSharedActor = new(commandfakes.FakeSharedActor)
    39  		fakeActor = new(v2fakes.FakeAppActor)
    40  
    41  		cmd = AppCommand{
    42  			UI:          testUI,
    43  			Config:      fakeConfig,
    44  			SharedActor: fakeSharedActor,
    45  			Actor:       fakeActor,
    46  		}
    47  
    48  		cmd.RequiredArgs.AppName = "some-app"
    49  
    50  		binaryName = "faceman"
    51  		fakeConfig.BinaryNameReturns(binaryName)
    52  	})
    53  
    54  	JustBeforeEach(func() {
    55  		executeErr = cmd.Execute(nil)
    56  	})
    57  
    58  	Context("when checking target fails", func() {
    59  		BeforeEach(func() {
    60  			fakeSharedActor.CheckTargetReturns(sharedaction.NotLoggedInError{BinaryName: binaryName})
    61  		})
    62  
    63  		It("returns an error if the check fails", func() {
    64  			Expect(executeErr).To(MatchError(translatableerror.NotLoggedInError{BinaryName: "faceman"}))
    65  
    66  			Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1))
    67  			_, checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0)
    68  			Expect(checkTargetedOrg).To(BeTrue())
    69  			Expect(checkTargetedSpace).To(BeTrue())
    70  		})
    71  	})
    72  
    73  	Context("when the user is logged in, and org and space are targeted", func() {
    74  		BeforeEach(func() {
    75  			fakeConfig.HasTargetedOrganizationReturns(true)
    76  			fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org"})
    77  			fakeConfig.HasTargetedSpaceReturns(true)
    78  			fakeConfig.TargetedSpaceReturns(configv3.Space{
    79  				GUID: "some-space-guid",
    80  				Name: "some-space"})
    81  			fakeConfig.CurrentUserReturns(
    82  				configv3.User{Name: "some-user"},
    83  				nil)
    84  		})
    85  
    86  		Context("when getting the current user returns an error", func() {
    87  			var expectedErr error
    88  
    89  			BeforeEach(func() {
    90  				expectedErr = errors.New("getting current user error")
    91  				fakeConfig.CurrentUserReturns(
    92  					configv3.User{},
    93  					expectedErr)
    94  			})
    95  
    96  			It("returns the error", func() {
    97  				Expect(executeErr).To(MatchError(expectedErr))
    98  			})
    99  		})
   100  
   101  		It("displays flavor text", func() {
   102  			Expect(testUI.Out).To(Say("Showing health and status for app some-app in org some-org / space some-space as some-user..."))
   103  		})
   104  
   105  		Context("when the --guid flag is provided", func() {
   106  			BeforeEach(func() {
   107  				cmd.GUID = true
   108  			})
   109  
   110  			Context("when no errors occur", func() {
   111  				BeforeEach(func() {
   112  					fakeActor.GetApplicationByNameAndSpaceReturns(
   113  						v2action.Application{GUID: "some-guid"},
   114  						v2action.Warnings{"warning-1", "warning-2"},
   115  						nil)
   116  				})
   117  
   118  				It("displays the application guid and all warnings", func() {
   119  					Expect(executeErr).ToNot(HaveOccurred())
   120  
   121  					Expect(testUI.Out).To(Say("some-guid"))
   122  					Expect(testUI.Err).To(Say("warning-1"))
   123  					Expect(testUI.Err).To(Say("warning-2"))
   124  				})
   125  			})
   126  
   127  			Context("when an error is encountered getting the app", func() {
   128  				Context("when the error is translatable", func() {
   129  					BeforeEach(func() {
   130  						fakeActor.GetApplicationByNameAndSpaceReturns(
   131  							v2action.Application{},
   132  							v2action.Warnings{"warning-1", "warning-2"},
   133  							actionerror.ApplicationNotFoundError{Name: "some-app"})
   134  					})
   135  
   136  					It("returns a translatable error and all warnings", func() {
   137  						Expect(executeErr).To(MatchError(translatableerror.ApplicationNotFoundError{Name: "some-app"}))
   138  
   139  						Expect(testUI.Err).To(Say("warning-1"))
   140  						Expect(testUI.Err).To(Say("warning-2"))
   141  					})
   142  				})
   143  
   144  				Context("when the error is not translatable", func() {
   145  					var expectedErr error
   146  
   147  					BeforeEach(func() {
   148  						expectedErr = errors.New("get app summary error")
   149  						fakeActor.GetApplicationByNameAndSpaceReturns(
   150  							v2action.Application{},
   151  							v2action.Warnings{"warning-1", "warning-2"},
   152  							expectedErr)
   153  					})
   154  
   155  					It("returns the error and all warnings", func() {
   156  						Expect(executeErr).To(MatchError(expectedErr))
   157  
   158  						Expect(testUI.Err).To(Say("warning-1"))
   159  						Expect(testUI.Err).To(Say("warning-2"))
   160  					})
   161  				})
   162  			})
   163  		})
   164  
   165  		Context("when the --guid flag is not provided", func() {
   166  			Context("when the app is a buildpack app", func() {
   167  				Context("when no errors occur", func() {
   168  					var (
   169  						applicationSummary v2action.ApplicationSummary
   170  						warnings           []string
   171  					)
   172  
   173  					BeforeEach(func() {
   174  						applicationSummary = v2action.ApplicationSummary{
   175  							Application: v2action.Application{
   176  								Name:              "some-app",
   177  								GUID:              "some-app-guid",
   178  								Instances:         types.NullInt{Value: 3, IsSet: true},
   179  								Memory:            128,
   180  								PackageUpdatedAt:  time.Unix(0, 0),
   181  								DetectedBuildpack: types.FilteredString{IsSet: true, Value: "some-buildpack"},
   182  								State:             "STARTED",
   183  							},
   184  							IsolationSegment: "some-isolation-segment",
   185  							Stack: v2action.Stack{
   186  								Name: "potatos",
   187  							},
   188  							Routes: []v2action.Route{
   189  								{
   190  									Host: "banana",
   191  									Domain: v2action.Domain{
   192  										Name: "fruit.com",
   193  									},
   194  									Path: "/hi",
   195  								},
   196  								{
   197  									Domain: v2action.Domain{
   198  										Name: "foobar.com",
   199  									},
   200  									Port: types.NullInt{IsSet: true, Value: 13},
   201  								},
   202  							},
   203  						}
   204  						warnings = []string{"app-summary-warning"}
   205  					})
   206  
   207  					Context("when the app does not have running instances", func() {
   208  						BeforeEach(func() {
   209  							applicationSummary.RunningInstances = []v2action.ApplicationInstanceWithStats{}
   210  							fakeActor.GetApplicationSummaryByNameAndSpaceReturns(applicationSummary, warnings, nil)
   211  						})
   212  
   213  						It("displays the app summary, 'no running instances' message, and all warnings", func() {
   214  							Expect(testUI.Out).To(Say("Showing health and status for app some-app in org some-org / space some-space as some-user..."))
   215  							Expect(testUI.Out).To(Say(""))
   216  
   217  							Expect(testUI.Out).To(Say("name:\\s+some-app"))
   218  							Expect(testUI.Out).To(Say("requested state:\\s+started"))
   219  							Expect(testUI.Out).To(Say("instances:\\s+0\\/3"))
   220  							// Note: in real life, iso segs are tied to *running* instances, so this field
   221  							// would be blank
   222  							Expect(testUI.Out).To(Say("isolation segment:\\s+some-isolation-segment"))
   223  							Expect(testUI.Out).To(Say("usage:\\s+128M x 3 instances"))
   224  							Expect(testUI.Out).To(Say("routes:\\s+banana.fruit.com/hi, foobar.com:13"))
   225  							Expect(testUI.Out).To(Say("last uploaded:\\s+\\w{3} [0-3]\\d \\w{3} [0-2]\\d:[0-5]\\d:[0-5]\\d \\w+ \\d{4}"))
   226  							Expect(testUI.Out).To(Say("stack:\\s+potatos"))
   227  							Expect(testUI.Out).To(Say("buildpack:\\s+some-buildpack"))
   228  							Expect(testUI.Out).To(Say(""))
   229  							Expect(testUI.Out).To(Say("There are no running instances of this app"))
   230  
   231  							Expect(testUI.Err).To(Say("app-summary-warning"))
   232  						})
   233  
   234  						It("should not display the instance table", func() {
   235  							Expect(testUI.Out).NotTo(Say("state\\s+since\\s+cpu\\s+memory\\s+disk"))
   236  						})
   237  					})
   238  
   239  					Context("when the app has running instances", func() {
   240  						BeforeEach(func() {
   241  							applicationSummary.RunningInstances = []v2action.ApplicationInstanceWithStats{
   242  								{
   243  									ID:          0,
   244  									State:       v2action.ApplicationInstanceState(ccv2.ApplicationInstanceRunning),
   245  									Since:       1403140717.984577,
   246  									CPU:         0.73,
   247  									Disk:        50 * bytefmt.MEGABYTE,
   248  									DiskQuota:   2048 * bytefmt.MEGABYTE,
   249  									Memory:      100 * bytefmt.MEGABYTE,
   250  									MemoryQuota: 128 * bytefmt.MEGABYTE,
   251  									Details:     "info from the backend",
   252  								},
   253  								{
   254  									ID:          1,
   255  									State:       v2action.ApplicationInstanceState(ccv2.ApplicationInstanceCrashed),
   256  									Since:       1403100000.900000,
   257  									CPU:         0.37,
   258  									Disk:        50 * bytefmt.MEGABYTE,
   259  									DiskQuota:   2048 * bytefmt.MEGABYTE,
   260  									Memory:      100 * bytefmt.MEGABYTE,
   261  									MemoryQuota: 128 * bytefmt.MEGABYTE,
   262  									Details:     "potato",
   263  								},
   264  							}
   265  						})
   266  
   267  						Context("when the isolation segment is not empty", func() {
   268  							BeforeEach(func() {
   269  								fakeActor.GetApplicationSummaryByNameAndSpaceReturns(applicationSummary, warnings, nil)
   270  							})
   271  
   272  							It("displays app summary, instance table, and all warnings", func() {
   273  								Expect(testUI.Out).To(Say("Showing health and status for app some-app in org some-org / space some-space as some-user..."))
   274  								Expect(testUI.Out).To(Say(""))
   275  								Expect(testUI.Out).To(Say("name:\\s+some-app"))
   276  								Expect(testUI.Out).To(Say("requested state:\\s+started"))
   277  								Expect(testUI.Out).To(Say("instances:\\s+1\\/3"))
   278  								Expect(testUI.Out).To(Say("isolation segment:\\s+some-isolation-segment"))
   279  								Expect(testUI.Out).To(Say("usage:\\s+128M x 3 instances"))
   280  								Expect(testUI.Out).To(Say("routes:\\s+banana.fruit.com/hi, foobar.com:13"))
   281  								Expect(testUI.Out).To(Say("last uploaded:\\s+\\w{3} [0-3]\\d \\w{3} [0-2]\\d:[0-5]\\d:[0-5]\\d \\w+ \\d{4}"))
   282  								Expect(testUI.Out).To(Say("stack:\\s+potatos"))
   283  								Expect(testUI.Out).To(Say("buildpack:\\s+some-buildpack"))
   284  								Expect(testUI.Out).To(Say(""))
   285  								Expect(testUI.Out).To(Say("state\\s+since\\s+cpu\\s+memory\\s+disk\\s+details"))
   286  								Expect(testUI.Out).To(Say(`#0\s+running\s+2014-06-19T01:18:37Z\s+73.0%\s+100M of 128M\s+50M of 2G\s+info from the backend`))
   287  								Expect(testUI.Out).To(Say(`#1\s+crashed\s+2014-06-18T14:00:00Z\s+37.0%\s+100M of 128M\s+50M of 2G\s+potato`))
   288  
   289  								Expect(testUI.Err).To(Say("app-summary-warning"))
   290  
   291  								Expect(fakeActor.GetApplicationSummaryByNameAndSpaceCallCount()).To(Equal(1))
   292  								appName, spaceGUID := fakeActor.GetApplicationSummaryByNameAndSpaceArgsForCall(0)
   293  								Expect(appName).To(Equal("some-app"))
   294  								Expect(spaceGUID).To(Equal("some-space-guid"))
   295  							})
   296  						})
   297  
   298  						Context("when the isolation segment is empty", func() {
   299  							BeforeEach(func() {
   300  								applicationSummary.IsolationSegment = ""
   301  								fakeActor.GetApplicationSummaryByNameAndSpaceReturns(applicationSummary, warnings, nil)
   302  							})
   303  
   304  							It("displays app summary, instance table, and all warnings", func() {
   305  								Expect(testUI.Out).To(Say("Showing health and status for app some-app in org some-org / space some-space as some-user..."))
   306  								Expect(testUI.Out).To(Say(""))
   307  								Expect(testUI.Out).To(Say("name:\\s+some-app"))
   308  								Expect(testUI.Out).To(Say("requested state:\\s+started"))
   309  								Expect(testUI.Out).To(Say("instances:\\s+1\\/3"))
   310  								Expect(testUI.Out).ToNot(Say("isolation segment:\\s+"))
   311  								Expect(testUI.Out).To(Say("usage:\\s+128M x 3 instances"))
   312  								Expect(testUI.Out).To(Say("routes:\\s+banana.fruit.com/hi, foobar.com:13"))
   313  								Expect(testUI.Out).To(Say("last uploaded:\\s+\\w{3} [0-3]\\d \\w{3} [0-2]\\d:[0-5]\\d:[0-5]\\d \\w+ \\d{4}"))
   314  								Expect(testUI.Out).To(Say("stack:\\s+potatos"))
   315  								Expect(testUI.Out).To(Say("buildpack:\\s+some-buildpack"))
   316  								Expect(testUI.Out).To(Say(""))
   317  								Expect(testUI.Out).To(Say("state\\s+since\\s+cpu\\s+memory\\s+disk\\s+details"))
   318  								Expect(testUI.Out).To(Say(`#0\s+running\s+2014-06-19T01:18:37Z\s+73.0%\s+100M of 128M\s+50M of 2G\s+info from the backend`))
   319  								Expect(testUI.Out).To(Say(`#1\s+crashed\s+2014-06-18T14:00:00Z\s+37.0%\s+100M of 128M\s+50M of 2G\s+potato`))
   320  
   321  								Expect(testUI.Err).To(Say("app-summary-warning"))
   322  
   323  								Expect(fakeActor.GetApplicationSummaryByNameAndSpaceCallCount()).To(Equal(1))
   324  								appName, spaceGUID := fakeActor.GetApplicationSummaryByNameAndSpaceArgsForCall(0)
   325  								Expect(appName).To(Equal("some-app"))
   326  								Expect(spaceGUID).To(Equal("some-space-guid"))
   327  							})
   328  						})
   329  					})
   330  				})
   331  
   332  				Context("when an error is encountered getting app summary", func() {
   333  					Context("when the error is not translatable", func() {
   334  						var expectedErr error
   335  
   336  						BeforeEach(func() {
   337  							expectedErr = errors.New("get app summary error")
   338  							fakeActor.GetApplicationSummaryByNameAndSpaceReturns(
   339  								v2action.ApplicationSummary{},
   340  								nil,
   341  								expectedErr)
   342  						})
   343  
   344  						It("returns the error", func() {
   345  							Expect(executeErr).To(MatchError(expectedErr))
   346  						})
   347  					})
   348  
   349  					Context("when the error is translatable", func() {
   350  						BeforeEach(func() {
   351  							fakeActor.GetApplicationSummaryByNameAndSpaceReturns(
   352  								v2action.ApplicationSummary{},
   353  								nil,
   354  								actionerror.ApplicationNotFoundError{Name: "some-app"})
   355  						})
   356  
   357  						It("returns a translatable error", func() {
   358  							Expect(executeErr).To(MatchError(translatableerror.ApplicationNotFoundError{Name: "some-app"}))
   359  						})
   360  					})
   361  				})
   362  			})
   363  
   364  			Context("when the app is a Docker app", func() {
   365  				var applicationSummary v2action.ApplicationSummary
   366  
   367  				BeforeEach(func() {
   368  					applicationSummary = v2action.ApplicationSummary{
   369  						Application: v2action.Application{
   370  							Name:             "some-app",
   371  							GUID:             "some-app-guid",
   372  							Instances:        types.NullInt{Value: 3, IsSet: true},
   373  							Memory:           128,
   374  							PackageUpdatedAt: time.Unix(0, 0),
   375  							State:            "STARTED",
   376  							DockerImage:      "some-docker-image",
   377  						},
   378  						Stack: v2action.Stack{
   379  							Name: "potatos",
   380  						},
   381  						Routes: []v2action.Route{
   382  							{
   383  								Host: "banana",
   384  								Domain: v2action.Domain{
   385  									Name: "fruit.com",
   386  								},
   387  								Path: "/hi",
   388  							},
   389  							{
   390  								Domain: v2action.Domain{
   391  									Name: "foobar.com",
   392  								},
   393  								Port: types.NullInt{IsSet: true, Value: 13},
   394  							},
   395  						},
   396  					}
   397  					fakeActor.GetApplicationSummaryByNameAndSpaceReturns(applicationSummary, nil, nil)
   398  				})
   399  
   400  				It("displays the Docker image and does not display buildpack", func() {
   401  					Expect(testUI.Out).To(Say("name:\\s+some-app"))
   402  					Expect(testUI.Out).To(Say("docker image:\\s+some-docker-image"))
   403  
   404  					b, ok := testUI.Out.(*Buffer)
   405  					Expect(ok).To(BeTrue())
   406  					Expect(string(b.Contents())).ToNot(MatchRegexp("buildpack:"))
   407  				})
   408  			})
   409  		})
   410  	})
   411  })