github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/integration/v6/isolated/app_command_test.go (about)

     1  package isolated
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"path/filepath"
     7  
     8  	"code.cloudfoundry.org/cli/integration/helpers"
     9  	. "github.com/onsi/ginkgo"
    10  	. "github.com/onsi/gomega"
    11  	. "github.com/onsi/gomega/gbytes"
    12  	. "github.com/onsi/gomega/gexec"
    13  )
    14  
    15  var _ = Describe("app command", func() {
    16  	var (
    17  		orgName   string
    18  		spaceName string
    19  		appName   string
    20  	)
    21  
    22  	BeforeEach(func() {
    23  		orgName = helpers.NewOrgName()
    24  		spaceName = helpers.NewSpaceName()
    25  		appName = helpers.PrefixedRandomName("app")
    26  	})
    27  
    28  	Describe("help", func() {
    29  		When("--help flag is set", func() {
    30  			It("Displays command usage to output", func() {
    31  				session := helpers.CF("app", "--help")
    32  				Eventually(session).Should(Say("NAME:"))
    33  				Eventually(session).Should(Say("app - Display health and status for an app"))
    34  				Eventually(session).Should(Say("USAGE:"))
    35  				Eventually(session).Should(Say("cf app APP_NAME"))
    36  				Eventually(session).Should(Say("OPTIONS:"))
    37  				Eventually(session).Should(Say("--guid      Retrieve and display the given app's guid.  All other health and status output for the app is suppressed."))
    38  				Eventually(session).Should(Say("SEE ALSO:"))
    39  				Eventually(session).Should(Say("apps, events, logs, map-route, push, unmap-route"))
    40  				Eventually(session).Should(Exit(0))
    41  			})
    42  		})
    43  	})
    44  
    45  	When("the environment is not setup correctly", func() {
    46  		It("fails with the appropriate errors", func() {
    47  			helpers.CheckEnvironmentTargetedCorrectly(true, true, ReadOnlyOrg, "app", "some-app")
    48  		})
    49  
    50  		When("no API endpoint is set", func() {
    51  			BeforeEach(func() {
    52  				helpers.UnsetAPI()
    53  			})
    54  
    55  			It("fails with no API endpoint set message", func() {
    56  				session := helpers.CF("app", appName)
    57  				Eventually(session).Should(Say("FAILED"))
    58  				Eventually(session.Err).Should(Say("No API endpoint set\\. Use 'cf login' or 'cf api' to target an endpoint\\."))
    59  				Eventually(session).Should(Exit(1))
    60  			})
    61  		})
    62  		When("not logged in", func() {
    63  			BeforeEach(func() {
    64  				helpers.LogoutCF()
    65  			})
    66  
    67  			It("fails with not logged in message", func() {
    68  				session := helpers.CF("app", appName)
    69  				Eventually(session).Should(Say("FAILED"))
    70  				Eventually(session.Err).Should(Say("Not logged in\\. Use 'cf login' or 'cf login --sso' to log in\\."))
    71  				Eventually(session).Should(Exit(1))
    72  			})
    73  		})
    74  
    75  		When("there is no org set", func() {
    76  			BeforeEach(func() {
    77  				helpers.LogoutCF()
    78  				helpers.LoginCF()
    79  			})
    80  
    81  			It("fails with no org targeted error message", func() {
    82  				session := helpers.CF("app", appName)
    83  				Eventually(session).Should(Say("FAILED"))
    84  				Eventually(session.Err).Should(Say("No org targeted, use 'cf target -o ORG' to target an org\\."))
    85  				Eventually(session).Should(Exit(1))
    86  			})
    87  		})
    88  
    89  		When("there is no space set", func() {
    90  			BeforeEach(func() {
    91  				helpers.LogoutCF()
    92  				helpers.LoginCF()
    93  				helpers.TargetOrg(ReadOnlyOrg)
    94  			})
    95  
    96  			It("fails with no space targeted error message", func() {
    97  				session := helpers.CF("app", appName)
    98  				Eventually(session).Should(Say("FAILED"))
    99  				Eventually(session.Err).Should(Say("No space targeted, use 'cf target -s SPACE' to target a space\\."))
   100  				Eventually(session).Should(Exit(1))
   101  			})
   102  		})
   103  	})
   104  
   105  	When("the environment is set up correctly", func() {
   106  		BeforeEach(func() {
   107  			helpers.SetupCF(orgName, spaceName)
   108  		})
   109  
   110  		AfterEach(func() {
   111  			helpers.QuickDeleteOrg(orgName)
   112  		})
   113  
   114  		Describe("version dependent display", func() {
   115  			When("CC API >= 3.55.0", func() {
   116  				BeforeEach(func() {
   117  					helpers.SkipIfVersionLessThan("3.55.0")
   118  				})
   119  
   120  				When("all instances of the app are down", func() {
   121  					BeforeEach(func() {
   122  						infiniteMemQuota := helpers.QuotaName()
   123  						Eventually(helpers.CF("create-quota", infiniteMemQuota, "-i", "-1", "-r", "-1", "-m", "2000G")).Should(Exit(0))
   124  						Eventually(helpers.CF("set-quota", orgName, infiniteMemQuota)).Should(Exit(0))
   125  
   126  						helpers.WithHelloWorldApp(func(appDir string) {
   127  							Eventually(helpers.CF("push", appName, "-p", appDir)).Should(Exit(0))
   128  						})
   129  						Eventually(helpers.CFWithEnv(map[string]string{"CF_STAGING_TIMEOUT": "0.1", "CF_STARTUP_TIMEOUT": "0.1"}, "scale", appName, "-m", "1000G", "-f")).Should(Exit(1))
   130  					})
   131  
   132  					It("displays the down app instances", func() {
   133  						session := helpers.CF("app", appName)
   134  
   135  						userName, _ := helpers.GetCredentials()
   136  						Eventually(session).Should(Say(`Showing health and status for app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName))
   137  						Eventually(session).Should(Say("name:\\s+%s", appName))
   138  						Eventually(session).Should(Say("requested state:\\s+started"))
   139  						Eventually(session).Should(Say("type:\\s+web"))
   140  						Eventually(session).Should(Say("#0\\s+down\\s+\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z.+insufficient resources: memory"))
   141  						Eventually(session).Should(Exit(0))
   142  					})
   143  				})
   144  			})
   145  
   146  			When("the app is created but not pushed", func() {
   147  				BeforeEach(func() {
   148  					Eventually(helpers.CF("v3-create-app", appName)).Should(Exit(0))
   149  				})
   150  
   151  				It("displays blank fields for unpopulated fields", func() {
   152  					session := helpers.CF("app", appName)
   153  					Eventually(session).Should(Say("name:\\s+%s", appName))
   154  					Eventually(session).Should(Say("requested state:\\s+stopped"))
   155  					Eventually(session).Should(Say("routes:\\s+\n"))
   156  					Eventually(session).Should(Say("last uploaded:\\s+\n"))
   157  					Eventually(session).Should(Say("stack:\\s+\n"))
   158  					Eventually(session).Should(Say("buildpacks:\\s+\n"))
   159  					Eventually(session).Should(Exit(0))
   160  				})
   161  			})
   162  
   163  			When("the app is a buildpack app", func() {
   164  				var domainName string
   165  
   166  				BeforeEach(func() {
   167  					domainName = helpers.DefaultSharedDomain()
   168  				})
   169  
   170  				When("the app is started and has 2 instances", func() {
   171  					BeforeEach(func() {
   172  						helpers.WithHelloWorldApp(func(appDir string) {
   173  							manifestContents := []byte(fmt.Sprintf(`
   174  ---
   175  applications:
   176  - name: %s
   177    memory: 128M
   178    instances: 2
   179    disk_quota: 128M
   180    routes:
   181    - route: %s.%s
   182  `, appName, appName, domainName))
   183  							manifestPath := filepath.Join(appDir, "manifest.yml")
   184  							err := ioutil.WriteFile(manifestPath, manifestContents, 0666)
   185  							Expect(err).ToNot(HaveOccurred())
   186  
   187  							// Create manifest
   188  							Eventually(helpers.CF("push", appName, "-p", appDir, "-f", manifestPath, "-b", "staticfile_buildpack")).Should(Exit(0))
   189  						})
   190  					})
   191  
   192  					// TODO: use multiprocess
   193  					It("uses the multiprocess display", func() {
   194  						userName, _ := helpers.GetCredentials()
   195  
   196  						session := helpers.CF("app", appName)
   197  
   198  						Eventually(session).Should(Say("Showing health and status for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   199  
   200  						Eventually(session).ShouldNot(Say("This command is in EXPERIMENTAL stage and may change without notice"))
   201  						Eventually(session).Should(Say("name:\\s+%s", appName))
   202  						Eventually(session).Should(Say("requested state:\\s+started"))
   203  						Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName))
   204  						Eventually(session).Should(Say("last uploaded:\\s+\\w{3} \\d{1,2} \\w{3} \\d{2}:\\d{2}:\\d{2} \\w{3,4} \\d{4}"))
   205  						Eventually(session).Should(Say("stack:\\s+cflinuxfs"))
   206  						Eventually(session).Should(Say("buildpacks:\\s+staticfile"))
   207  						Eventually(session).Should(Say("type:\\s+web"))
   208  						Eventually(session).Should(Say("instances:\\s+\\d/2"))
   209  						Eventually(session).Should(Say("memory usage:\\s+128M"))
   210  						Eventually(session).Should(Say("\\s+state\\s+since\\s+cpu\\s+memory\\s+disk\\s+details"))
   211  						Eventually(session).Should(Say("#0\\s+(starting|running)\\s+\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z"))
   212  
   213  						Eventually(session).Should(Exit(0))
   214  					})
   215  				})
   216  			})
   217  
   218  			When("the app is stopped", func() {
   219  				BeforeEach(func() {
   220  					helpers.WithHelloWorldApp(func(appDir string) {
   221  						Eventually(helpers.CF("push", appName, "-p", appDir, "-b", "staticfile_buildpack", "--no-start")).Should(Exit(0))
   222  					})
   223  				})
   224  
   225  				It("displays that there are no running instances of the app", func() {
   226  					session := helpers.CF("app", appName)
   227  
   228  					userName, _ := helpers.GetCredentials()
   229  					Eventually(session).Should(Say(`Showing health and status for app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName))
   230  					Eventually(session).Should(Say("name:\\s+%s", appName))
   231  					Eventually(session).Should(Say("requested state:\\s+stopped"))
   232  					Eventually(session).Should(Say("type:\\s+web"))
   233  					Eventually(session).Should(Say("#0\\s+down\\s+\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z"))
   234  					Eventually(session).Should(Exit(0))
   235  				})
   236  			})
   237  
   238  			When("the app has 0 instances", func() {
   239  				BeforeEach(func() {
   240  					helpers.WithHelloWorldApp(func(appDir string) {
   241  						Eventually(helpers.CF("push", appName, "-p", appDir, "-b", "staticfile_buildpack", "-i", "0")).Should(Exit(0))
   242  					})
   243  				})
   244  
   245  				It("displays the app information", func() {
   246  					session := helpers.CF("app", appName)
   247  					userName, _ := helpers.GetCredentials()
   248  
   249  					Eventually(session).Should(Say(`Showing health and status for app %s in org %s / space %s as %s\.\.\.`, appName, orgName, spaceName, userName))
   250  					Eventually(session).Should(Say("name:\\s+%s", appName))
   251  					Eventually(session).Should(Say("requested state:\\s+started"))
   252  					Eventually(session).Should(Say("type:\\s+web"))
   253  					Eventually(session).Should(Say("There are no running instances of this process"))
   254  					Eventually(session).Should(Exit(0))
   255  				})
   256  			})
   257  
   258  			When("the --guid flag is given", func() {
   259  				var appGUID string
   260  
   261  				BeforeEach(func() {
   262  					helpers.WithHelloWorldApp(func(appDir string) {
   263  						Eventually(helpers.CF("push", appName, "-p", appDir, "-b", "staticfile_buildpack", "--no-start")).Should(Exit(0))
   264  					})
   265  
   266  					var AppInfo struct {
   267  						Resources []struct {
   268  							GUID string `json:"guid"`
   269  						} `json:"resources"`
   270  					}
   271  
   272  					helpers.Curl(&AppInfo, "/v3/apps?names=%s", appName)
   273  					appGUID = AppInfo.Resources[0].GUID
   274  				})
   275  
   276  				It("displays the app guid", func() {
   277  					session := helpers.CF("app", "--guid", appName)
   278  					Eventually(session).Should(Say(appGUID))
   279  					Eventually(session).Should(Exit(0))
   280  				})
   281  			})
   282  
   283  			When("the app uses multiple buildpacks", func() {
   284  				BeforeEach(func() {
   285  					// Until version 3.43, droplets did not list all buildpacks they were built with (#150068339).
   286  					helpers.SkipIfVersionLessThan("3.43.0")
   287  
   288  					helpers.WithMultiBuildpackApp(func(appDir string) {
   289  						Eventually(helpers.CF("v3-push", appName, "-p", appDir, "-b", "ruby_buildpack", "-b", "go_buildpack")).Should(Exit(0))
   290  					})
   291  				})
   292  
   293  				It("displays the app buildpacks", func() {
   294  					session := helpers.CF("app", appName)
   295  					Eventually(session).Should(Say("buildpacks:\\s+ruby_buildpack,\\s+go"))
   296  					Eventually(session).Should(Exit(0))
   297  				})
   298  			})
   299  		})
   300  
   301  		Describe("version independent display", func() {
   302  			When("the app name is not provided", func() {
   303  				It("tells the user that the app name is required, prints help text, and exits 1", func() {
   304  					session := helpers.CF("app")
   305  
   306  					Eventually(session.Err).Should(Say("Incorrect Usage: the required argument `APP_NAME` was not provided"))
   307  					Eventually(session).Should(Say("NAME:"))
   308  					Eventually(session).Should(Exit(1))
   309  				})
   310  			})
   311  
   312  			When("the app does not exist", func() {
   313  				When("no flags are given", func() {
   314  					It("tells the user that the app is not found and exits 1", func() {
   315  						session := helpers.CF("app", appName)
   316  
   317  						Eventually(session).Should(Say("FAILED"))
   318  						Eventually(session.Err).Should(Say("App '%s' not found", appName))
   319  						Eventually(session).Should(Exit(1))
   320  					})
   321  				})
   322  
   323  				When("the --guid flag is given", func() {
   324  					It("tells the user that the app is not found and exits 1", func() {
   325  						session := helpers.CF("app", "--guid", appName)
   326  
   327  						Eventually(session).Should(Say("FAILED"))
   328  						Eventually(session.Err).Should(Say("App '%s' not found", appName))
   329  						Eventually(session).Should(Exit(1))
   330  					})
   331  				})
   332  			})
   333  
   334  			When("the app exists", func() {
   335  				When("isolation segments are available", func() {
   336  					BeforeEach(func() {
   337  						Eventually(helpers.CF("create-isolation-segment", RealIsolationSegment)).Should(Exit(0))
   338  						Eventually(helpers.CF("enable-org-isolation", orgName, RealIsolationSegment)).Should(Exit(0))
   339  						Eventually(helpers.CF("set-space-isolation-segment", spaceName, RealIsolationSegment)).Should(Exit(0))
   340  
   341  						helpers.WithHelloWorldApp(func(appDir string) {
   342  							Eventually(helpers.CF("push", appName, "-p", appDir, "-b", "staticfile_buildpack")).Should(Exit(0))
   343  						})
   344  					})
   345  
   346  					It("displays the app isolation segment information", func() {
   347  						session := helpers.CF("app", appName)
   348  
   349  						Eventually(session).Should(Say("isolation segment:\\s+%s", RealIsolationSegment))
   350  						Eventually(session).Should(Exit(0))
   351  					})
   352  				})
   353  
   354  				When("isolation segment is not set for the application", func() {
   355  					BeforeEach(func() {
   356  						helpers.WithHelloWorldApp(func(appDir string) {
   357  							Eventually(helpers.CF("push", appName, "-p", appDir, "-b", "staticfile_buildpack")).Should(Exit(0))
   358  						})
   359  					})
   360  
   361  					It("displays the app isolation segment information", func() {
   362  						session := helpers.CF("app", appName)
   363  
   364  						Consistently(session).ShouldNot(Say("isolation segment:"))
   365  						Eventually(session).Should(Exit(0))
   366  					})
   367  				})
   368  
   369  				When("the app is a Docker app", func() {
   370  					BeforeEach(func() {
   371  						Eventually(helpers.CF("push", appName, "-o", DockerImage)).Should(Exit())
   372  					})
   373  
   374  					It("displays the docker image", func() {
   375  						session := helpers.CF("app", appName)
   376  						Eventually(session).Should(Say("name:\\s+%s", appName))
   377  						Eventually(session).Should(Say("docker image:\\s+%s", DockerImage))
   378  						Eventually(session).Should(Exit(0))
   379  					})
   380  
   381  					It("does not display buildpack", func() {
   382  						session := helpers.CF("app", appName)
   383  						Consistently(session).ShouldNot(Say("buildpacks?:"))
   384  						Eventually(session).Should(Exit(0))
   385  					})
   386  				})
   387  
   388  				When("the app has tcp routes", func() {
   389  					var tcpDomain helpers.Domain
   390  
   391  					BeforeEach(func() {
   392  						tcpDomain = helpers.NewDomain(orgName, helpers.NewDomainName("tcp"))
   393  						tcpDomain.CreateWithRouterGroup(helpers.FindOrCreateTCPRouterGroup(GinkgoParallelNode()))
   394  						helpers.WithHelloWorldApp(func(appDir string) {
   395  							manifestContents := []byte(fmt.Sprintf(`
   396  ---
   397  applications:
   398  - name: %s
   399    routes:
   400    - route: %s:1024
   401  `, appName, tcpDomain.Name))
   402  							manifestPath := filepath.Join(appDir, "manifest.yml")
   403  							err := ioutil.WriteFile(manifestPath, manifestContents, 0666)
   404  							Expect(err).ToNot(HaveOccurred())
   405  
   406  							// Create manifest
   407  							Eventually(helpers.CF("push", appName, "-p", appDir, "-f", manifestPath, "-b", "staticfile_buildpack")).Should(Exit(0))
   408  						})
   409  
   410  						It("displays the app information", func() {
   411  							session := helpers.CF("app", appName)
   412  							Eventually(session).Should(Say("routes:\\s+[\\w\\d-]+\\.%s", tcpDomain))
   413  							Eventually(session).Should(Exit(0))
   414  						})
   415  					})
   416  				})
   417  			})
   418  		})
   419  	})
   420  })