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

     1  package isolated
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"path/filepath"
     7  	"runtime"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"code.cloudfoundry.org/cli/integration/helpers"
    12  	"code.cloudfoundry.org/cli/util/configv3"
    13  	. "github.com/onsi/ginkgo"
    14  	. "github.com/onsi/ginkgo/extensions/table"
    15  	. "github.com/onsi/gomega"
    16  	. "github.com/onsi/gomega/gbytes"
    17  	. "github.com/onsi/gomega/gexec"
    18  )
    19  
    20  var _ = Describe("Verbose", func() {
    21  	BeforeEach(func() {
    22  		helpers.SkipIfClientCredentialsTestMode()
    23  	})
    24  
    25  	Context("v2 legacy", func() {
    26  		DescribeTable("displays verbose output",
    27  			func(command func() *Session) {
    28  				helpers.LoginCF()
    29  
    30  				session := command()
    31  				Eventually(session).Should(Say("REQUEST:"))
    32  				Eventually(session).Should(Say("GET /v2/organizations"))
    33  				Eventually(session).Should(Say("RESPONSE:"))
    34  				Eventually(session).Should(Exit(0))
    35  			},
    36  
    37  			Entry("when the -v option is provided with additional command", func() *Session {
    38  				return helpers.CF("-v", "orgs")
    39  			}),
    40  
    41  			Entry("when the CF_TRACE env variable is set", func() *Session {
    42  				return helpers.CFWithEnv(map[string]string{"CF_TRACE": "true"}, "orgs")
    43  			}),
    44  		)
    45  	})
    46  
    47  	Context("v2 refactor", func() {
    48  		DescribeTable("displays verbose output to terminal",
    49  			func(env string, configTrace string, flag bool) {
    50  				tmpDir, err := ioutil.TempDir("", "")
    51  				defer os.RemoveAll(tmpDir)
    52  				Expect(err).NotTo(HaveOccurred())
    53  
    54  				helpers.LoginCF()
    55  				helpers.TargetOrgAndSpace(ReadOnlyOrg, ReadOnlySpace)
    56  
    57  				var envMap map[string]string
    58  				if env != "" {
    59  					if string(env[0]) == "/" {
    60  						env = filepath.Join(tmpDir, env)
    61  					}
    62  					envMap = map[string]string{"CF_TRACE": env}
    63  				}
    64  
    65  				// We use 'create-user' because it makes a request via the UAA client
    66  				// and a request via the CC client, testing the logging wrapper in both
    67  				// clients.
    68  				randomUsername := helpers.NewUsername()
    69  				randomPassword := helpers.NewPassword()
    70  				command := []string{"create-user", randomUsername, randomPassword}
    71  
    72  				if flag {
    73  					command = append(command, "-v")
    74  				}
    75  
    76  				if configTrace != "" {
    77  					if string(configTrace[0]) == "/" {
    78  						configTrace = filepath.Join(tmpDir, configTrace)
    79  					}
    80  					session := helpers.CF("config", "--trace", configTrace)
    81  					Eventually(session).Should(Exit(0))
    82  				}
    83  
    84  				session := helpers.CFWithEnv(envMap, command...)
    85  
    86  				Eventually(session).Should(Say("REQUEST:"))
    87  				Eventually(session).Should(Say("GET /v2/info"))
    88  				Eventually(session).Should(Say("RESPONSE:"))
    89  				Eventually(session).Should(Say("REQUEST:"))
    90  				Eventually(session).Should(Say("POST /Users"))
    91  				Eventually(session).Should(Say(`User-Agent: cf/[\w.+-]+ \(go\d+\.\d+(\.\d+)?; %s %s\)`, runtime.GOARCH, runtime.GOOS))
    92  				Eventually(session).Should(Say("RESPONSE:"))
    93  				Eventually(session).Should(Say("REQUEST:"))
    94  				Eventually(session).Should(Say("POST /v2/users"))
    95  				Eventually(session).Should(Say(`User-Agent: cf/[\w.+-]+ \(go\d+\.\d+(\.\d+)?; %s %s\)`, runtime.GOARCH, runtime.GOOS))
    96  				Eventually(session).Should(Say("RESPONSE:"))
    97  				Eventually(session).Should(Exit(0))
    98  			},
    99  
   100  			Entry("CF_TRACE true: enables verbose", "true", "", false),
   101  			Entry("CF_TRACE true, config trace false: enables verbose", "true", "false", false),
   102  			Entry("CF_TRACE true, config trace file path: enables verbose AND logging to file", "true", "/foo", false),
   103  
   104  			Entry("CF_TRACE false, '-v': enables verbose", "false", "", true),
   105  			Entry("CF_TRACE false, config trace file path, '-v': enables verbose AND logging to file", "false", "/foo", true),
   106  
   107  			Entry("CF_TRACE empty:, '-v': enables verbose", "", "", true),
   108  			Entry("CF_TRACE empty, config trace true: enables verbose", "", "true", false),
   109  			Entry("CF_TRACE empty, config trace file path, '-v': enables verbose AND logging to file", "", "/foo", true),
   110  
   111  			Entry("CF_TRACE filepath, '-v': enables logging to file", "/foo", "", true),
   112  			Entry("CF_TRACE filepath, config trace true: enables verbose AND logging to file", "/foo", "true", false),
   113  			Entry("CF_TRACE filepath, config trace filepath, '-v': enables verbose AND logging to file for BOTH paths", "/foo", "/bar", true),
   114  		)
   115  
   116  		DescribeTable("displays verbose output to multiple files",
   117  			func(env string, configTrace string, flag bool, location []string) {
   118  				tmpDir, err := ioutil.TempDir("", "")
   119  				defer os.RemoveAll(tmpDir)
   120  				Expect(err).NotTo(HaveOccurred())
   121  
   122  				helpers.LoginCF()
   123  				helpers.TargetOrgAndSpace(ReadOnlyOrg, ReadOnlySpace)
   124  
   125  				var envMap map[string]string
   126  				if env != "" {
   127  					if string(env[0]) == "/" {
   128  						env = filepath.Join(tmpDir, env)
   129  					}
   130  					envMap = map[string]string{"CF_TRACE": env}
   131  				}
   132  
   133  				// We use 'create-user' because it makes a request via the UAA client
   134  				// and a request via the CC client, testing the logging wrapper in both
   135  				// clients.
   136  				randomUsername := helpers.NewUsername()
   137  				randomPassword := helpers.NewPassword()
   138  				command := []string{"create-user", randomUsername, randomPassword}
   139  
   140  				if flag {
   141  					command = append(command, "-v")
   142  				}
   143  
   144  				if configTrace != "" {
   145  					if string(configTrace[0]) == "/" {
   146  						configTrace = filepath.Join(tmpDir, configTrace)
   147  					}
   148  					session := helpers.CF("config", "--trace", configTrace)
   149  					Eventually(session).Should(Exit(0))
   150  				}
   151  
   152  				session := helpers.CFWithEnv(envMap, command...)
   153  				Eventually(session).Should(Exit(0))
   154  
   155  				for _, filePath := range location {
   156  					contents, err := ioutil.ReadFile(tmpDir + filePath)
   157  					Expect(err).ToNot(HaveOccurred())
   158  
   159  					Expect(string(contents)).To(MatchRegexp("REQUEST:"))
   160  					Expect(string(contents)).To(MatchRegexp("POST /Users"))
   161  					Expect(string(contents)).To(MatchRegexp("RESPONSE:"))
   162  					Expect(string(contents)).To(MatchRegexp("REQUEST:"))
   163  					Expect(string(contents)).To(MatchRegexp("POST /v2/users"))
   164  					Expect(string(contents)).To(MatchRegexp("RESPONSE:"))
   165  
   166  					stat, err := os.Stat(tmpDir + filePath)
   167  					Expect(err).ToNot(HaveOccurred())
   168  
   169  					if runtime.GOOS == "windows" {
   170  						Expect(stat.Mode().String()).To(Equal(os.FileMode(0666).String()))
   171  					} else {
   172  						Expect(stat.Mode().String()).To(Equal(os.FileMode(0600).String()))
   173  					}
   174  				}
   175  			},
   176  
   177  			Entry("CF_TRACE true, config trace file path: enables verbose AND logging to file", "true", "/foo", false, []string{"/foo"}),
   178  
   179  			Entry("CF_TRACE false, config trace file path: enables logging to file", "false", "/foo", false, []string{"/foo"}),
   180  			Entry("CF_TRACE false, config trace file path, '-v': enables verbose AND logging to file", "false", "/foo", true, []string{"/foo"}),
   181  
   182  			Entry("CF_TRACE empty, config trace file path: enables logging to file", "", "/foo", false, []string{"/foo"}),
   183  			Entry("CF_TRACE empty, config trace file path, '-v': enables verbose AND logging to file", "", "/foo", true, []string{"/foo"}),
   184  
   185  			Entry("CF_TRACE filepath: enables logging to file", "/foo", "", false, []string{"/foo"}),
   186  			Entry("CF_TRACE filepath, '-v': enables logging to file", "/foo", "", true, []string{"/foo"}),
   187  			Entry("CF_TRACE filepath, config trace true: enables verbose AND logging to file", "/foo", "true", false, []string{"/foo"}),
   188  			Entry("CF_TRACE filepath, config trace filepath: enables logging to file for BOTH paths", "/foo", "/bar", false, []string{"/foo", "/bar"}),
   189  			Entry("CF_TRACE filepath, config trace filepath, '-v': enables verbose AND logging to file for BOTH paths", "/foo", "/bar", true, []string{"/foo", "/bar"}),
   190  		)
   191  	})
   192  
   193  	Context("v3", func() {
   194  		DescribeTable("displays verbose output to terminal",
   195  			func(env string, configTrace string, flag bool) {
   196  				tmpDir, err := ioutil.TempDir("", "")
   197  				defer os.RemoveAll(tmpDir)
   198  				Expect(err).NotTo(HaveOccurred())
   199  
   200  				helpers.SetupCF(ReadOnlyOrg, ReadOnlySpace)
   201  
   202  				// Invalidate the access token to cause a token refresh in order to
   203  				// test the call to the UAA.
   204  				helpers.SetConfig(func(config *configv3.Config) {
   205  					config.ConfigFile.AccessToken = helpers.ExpiredAccessToken()
   206  				})
   207  
   208  				var envMap map[string]string
   209  				if env != "" {
   210  					if string(env[0]) == "/" {
   211  						env = filepath.Join(tmpDir, env)
   212  					}
   213  					envMap = map[string]string{"CF_TRACE": env}
   214  				}
   215  
   216  				command := []string{"run-task", "app", "echo"}
   217  
   218  				if flag {
   219  					command = append(command, "-v")
   220  				}
   221  
   222  				if configTrace != "" {
   223  					if string(configTrace[0]) == "/" {
   224  						configTrace = filepath.Join(tmpDir, configTrace)
   225  					}
   226  					session := helpers.CF("config", "--trace", configTrace)
   227  					Eventually(session).Should(Exit(0))
   228  				}
   229  
   230  				session := helpers.CFWithEnv(envMap, command...)
   231  				// implicit access token refresh
   232  				Eventually(session).Should(Say("REQUEST:"))
   233  				Eventually(session).Should(Say("POST /oauth/token"))
   234  				Eventually(session).Should(Say(`User-Agent: cf/[\w.+-]+ \(go\d+\.\d+(\.\d+)?; %s %s\)`, runtime.GOARCH, runtime.GOOS))
   235  				Eventually(session).Should(Say(`\[PRIVATE DATA HIDDEN\]`)) //This is required to test the previous line. If it fails, the previous matcher went too far.
   236  				Eventually(session).Should(Say("RESPONSE:"))
   237  				// actual request
   238  				Eventually(session).Should(Say("REQUEST:"))
   239  				Eventually(session).Should(Say("GET /v3/apps"))
   240  				Eventually(session).Should(Say(`User-Agent: cf/[\w.+-]+ \(go\d+\.\d+(\.\d+)?; %s %s\)`, runtime.GOARCH, runtime.GOOS))
   241  				Eventually(session).Should(Say("RESPONSE:"))
   242  
   243  				Eventually(session).Should(Exit(1))
   244  			},
   245  
   246  			Entry("CF_TRACE true: enables verbose", "true", "", false),
   247  			Entry("CF_TRACE true, config trace false: enables verbose", "true", "false", false),
   248  			Entry("CF_TRACE true, config trace file path: enables verbose AND logging to file", "true", "/foo", false),
   249  
   250  			Entry("CF_TRACE false, '-v': enables verbose", "false", "", true),
   251  			Entry("CF_TRACE false, config trace file path, '-v': enables verbose AND logging to file", "false", "/foo", true),
   252  
   253  			Entry("CF_TRACE empty:, '-v': enables verbose", "", "", true),
   254  			Entry("CF_TRACE empty, config trace true: enables verbose", "", "true", false),
   255  			Entry("CF_TRACE empty, config trace file path, '-v': enables verbose AND logging to file", "", "/foo", true),
   256  
   257  			Entry("CF_TRACE filepath, '-v': enables logging to file", "/foo", "", true),
   258  			Entry("CF_TRACE filepath, config trace true: enables verbose AND logging to file", "/foo", "true", false),
   259  			Entry("CF_TRACE filepath, config trace filepath, '-v': enables verbose AND logging to file for BOTH paths", "/foo", "/bar", true),
   260  		)
   261  
   262  		DescribeTable("displays verbose output to multiple files",
   263  			func(env string, configTrace string, flag bool, location []string) {
   264  				tmpDir, err := ioutil.TempDir("", "")
   265  				defer os.RemoveAll(tmpDir)
   266  				Expect(err).NotTo(HaveOccurred())
   267  
   268  				helpers.SetupCF(ReadOnlyOrg, ReadOnlySpace)
   269  
   270  				// Invalidate the access token to cause a token refresh in order to
   271  				// test the call to the UAA.
   272  				helpers.SetConfig(func(config *configv3.Config) {
   273  					config.ConfigFile.AccessToken = helpers.ExpiredAccessToken()
   274  				})
   275  
   276  				var envMap map[string]string
   277  				if env != "" {
   278  					if string(env[0]) == "/" {
   279  						env = filepath.Join(tmpDir, env)
   280  					}
   281  					envMap = map[string]string{"CF_TRACE": env}
   282  				}
   283  
   284  				command := []string{"run-task", "app", "echo"}
   285  
   286  				if flag {
   287  					command = append(command, "-v")
   288  				}
   289  
   290  				if configTrace != "" {
   291  					if string(configTrace[0]) == "/" {
   292  						configTrace = filepath.Join(tmpDir, configTrace)
   293  					}
   294  					session := helpers.CF("config", "--trace", configTrace)
   295  					Eventually(session).Should(Exit(0))
   296  				}
   297  
   298  				session := helpers.CFWithEnv(envMap, command...)
   299  				Eventually(session).Should(Exit(1))
   300  
   301  				for _, filePath := range location {
   302  					contents, err := ioutil.ReadFile(tmpDir + filePath)
   303  					Expect(err).ToNot(HaveOccurred())
   304  
   305  					Expect(string(contents)).To(MatchRegexp("REQUEST:"))
   306  					Expect(string(contents)).To(MatchRegexp("GET /v3/apps"))
   307  					Expect(string(contents)).To(MatchRegexp("RESPONSE:"))
   308  					Expect(string(contents)).To(MatchRegexp("REQUEST:"))
   309  					Expect(string(contents)).To(MatchRegexp("POST /oauth/token"))
   310  					Expect(string(contents)).To(MatchRegexp("RESPONSE:"))
   311  
   312  					stat, err := os.Stat(tmpDir + filePath)
   313  					Expect(err).ToNot(HaveOccurred())
   314  
   315  					if runtime.GOOS == "windows" {
   316  						Expect(stat.Mode().String()).To(Equal(os.FileMode(0666).String()))
   317  					} else {
   318  						Expect(stat.Mode().String()).To(Equal(os.FileMode(0600).String()))
   319  					}
   320  				}
   321  			},
   322  
   323  			Entry("CF_TRACE true, config trace file path: enables verbose AND logging to file", "true", "/foo", false, []string{"/foo"}),
   324  
   325  			Entry("CF_TRACE false, config trace file path: enables logging to file", "false", "/foo", false, []string{"/foo"}),
   326  			Entry("CF_TRACE false, config trace file path, '-v': enables verbose AND logging to file", "false", "/foo", true, []string{"/foo"}),
   327  
   328  			Entry("CF_TRACE empty, config trace file path: enables logging to file", "", "/foo", false, []string{"/foo"}),
   329  			Entry("CF_TRACE empty, config trace file path, '-v': enables verbose AND logging to file", "", "/foo", true, []string{"/foo"}),
   330  
   331  			Entry("CF_TRACE filepath: enables logging to file", "/foo", "", false, []string{"/foo"}),
   332  			Entry("CF_TRACE filepath, '-v': enables logging to file", "/foo", "", true, []string{"/foo"}),
   333  			Entry("CF_TRACE filepath, config trace true: enables verbose AND logging to file", "/foo", "true", false, []string{"/foo"}),
   334  			Entry("CF_TRACE filepath, config trace filepath: enables logging to file for BOTH paths", "/foo", "/bar", false, []string{"/foo", "/bar"}),
   335  			Entry("CF_TRACE filepath, config trace filepath, '-v': enables verbose AND logging to file for BOTH paths", "/foo", "/bar", true, []string{"/foo", "/bar"}),
   336  		)
   337  	})
   338  
   339  	Describe("NOAA", func() {
   340  		var orgName string
   341  
   342  		BeforeEach(func() {
   343  			orgName = helpers.NewOrgName()
   344  			spaceName := helpers.NewSpaceName()
   345  
   346  			helpers.SetupCF(orgName, spaceName)
   347  		})
   348  
   349  		AfterEach(func() {
   350  			Eventually(helpers.CF("config", "--trace", "false")).Should(Exit(0))
   351  			helpers.QuickDeleteOrg(orgName)
   352  		})
   353  
   354  		DescribeTable("displays verbose output to terminal",
   355  			func(env string, configTrace string, flag bool) {
   356  				tmpDir, err := ioutil.TempDir("", "")
   357  				defer os.RemoveAll(tmpDir)
   358  				Expect(err).NotTo(HaveOccurred())
   359  
   360  				appName := helpers.PrefixedRandomName("app")
   361  
   362  				helpers.WithHelloWorldApp(func(appDir string) {
   363  					Eventually(helpers.CF("push", appName, "--no-start", "-p", appDir, "-b", "staticfile_buildpack", "--no-route")).Should(Exit(0))
   364  				})
   365  
   366  				var envMap map[string]string
   367  				if env != "" {
   368  					if string(env[0]) == "/" {
   369  						env = filepath.Join(tmpDir, env)
   370  					}
   371  					envMap = map[string]string{"CF_TRACE": env}
   372  				}
   373  
   374  				command := []string{"logs", appName}
   375  
   376  				if flag {
   377  					command = append(command, "-v")
   378  				}
   379  
   380  				if configTrace != "" {
   381  					if string(configTrace[0]) == "/" {
   382  						configTrace = filepath.Join(tmpDir, configTrace)
   383  					}
   384  					session := helpers.CF("config", "--trace", configTrace)
   385  					Eventually(session).Should(Exit(0))
   386  				}
   387  
   388  				session := helpers.CFWithEnv(envMap, command...)
   389  
   390  				Eventually(session).Should(Say("REQUEST:"))
   391  				Eventually(session).Should(Say("GET /v2/info"))
   392  				Eventually(session).Should(Say("WEBSOCKET REQUEST:"))
   393  				Eventually(session).Should(Say(`Authorization: \[PRIVATE DATA HIDDEN\]`))
   394  				Eventually(session.Kill()).Should(Exit())
   395  			},
   396  
   397  			Entry("CF_TRACE true: enables verbose", "true", "", false),
   398  			Entry("CF_TRACE true, config trace false: enables verbose", "true", "false", false),
   399  			Entry("CF_TRACE true, config trace file path: enables verbose AND logging to file", "true", "/foo", false),
   400  
   401  			Entry("CF_TRACE false, '-v': enables verbose", "false", "", true),
   402  			Entry("CF_TRACE false, config trace file path, '-v': enables verbose AND logging to file", "false", "/foo", true),
   403  
   404  			Entry("CF_TRACE empty:, '-v': enables verbose", "", "", true),
   405  			Entry("CF_TRACE empty, config trace true: enables verbose", "", "true", false),
   406  			Entry("CF_TRACE empty, config trace file path, '-v': enables verbose AND logging to file", "", "/foo", true),
   407  
   408  			Entry("CF_TRACE filepath, '-v': enables logging to file", "/foo", "", true),
   409  			Entry("CF_TRACE filepath, config trace true: enables verbose AND logging to file", "/foo", "true", false),
   410  			Entry("CF_TRACE filepath, config trace filepath, '-v': enables verbose AND logging to file for BOTH paths", "/foo", "/bar", true),
   411  		)
   412  
   413  		DescribeTable("displays verbose output to multiple files",
   414  			func(env string, configTrace string, location []string) {
   415  				tmpDir, err := ioutil.TempDir("", "")
   416  				defer os.RemoveAll(tmpDir)
   417  				Expect(err).NotTo(HaveOccurred())
   418  
   419  				appName := helpers.PrefixedRandomName("app")
   420  
   421  				helpers.WithHelloWorldApp(func(appDir string) {
   422  					Eventually(helpers.CF("push", appName, "--no-start", "-p", appDir, "-b", "staticfile_buildpack", "--no-route")).Should(Exit(0))
   423  				})
   424  
   425  				var envMap map[string]string
   426  				if env != "" {
   427  					if string(env[0]) == "/" {
   428  						env = filepath.Join(tmpDir, env)
   429  					}
   430  					envMap = map[string]string{"CF_TRACE": env}
   431  				}
   432  
   433  				if configTrace != "" {
   434  					if strings.HasPrefix(configTrace, "/") {
   435  						configTrace = filepath.Join(tmpDir, configTrace)
   436  					}
   437  					session := helpers.CF("config", "--trace", configTrace)
   438  					Eventually(session).Should(Exit(0))
   439  				}
   440  
   441  				session := helpers.CFWithEnv(envMap, "logs", "-v", appName)
   442  
   443  				Eventually(session).Should(Say("WEBSOCKET RESPONSE"))
   444  				Eventually(session.Kill()).Should(Exit())
   445  
   446  				for _, filePath := range location {
   447  					contents, err := ioutil.ReadFile(tmpDir + filePath)
   448  					Expect(err).ToNot(HaveOccurred())
   449  
   450  					Expect(string(contents)).To(MatchRegexp("REQUEST:"))
   451  					Expect(string(contents)).To(MatchRegexp("GET /v2/info"))
   452  					Expect(string(contents)).To(MatchRegexp("WEBSOCKET REQUEST:"))
   453  					Expect(string(contents)).To(MatchRegexp(`Authorization: \[PRIVATE DATA HIDDEN\]`))
   454  
   455  					stat, err := os.Stat(tmpDir + filePath)
   456  					Expect(err).ToNot(HaveOccurred())
   457  
   458  					if runtime.GOOS == "windows" {
   459  						Expect(stat.Mode().String()).To(Equal(os.FileMode(0666).String()))
   460  					} else {
   461  						Expect(stat.Mode().String()).To(Equal(os.FileMode(0600).String()))
   462  					}
   463  				}
   464  			},
   465  
   466  			Entry("CF_TRACE true, config trace file path: enables verbose AND logging to file", "true", "/foo", []string{"/foo"}),
   467  
   468  			Entry("CF_TRACE false, config trace file path: enables logging to file", "false", "/foo", []string{"/foo"}),
   469  			Entry("CF_TRACE false, config trace file path, '-v': enables verbose AND logging to file", "false", "/foo", []string{"/foo"}),
   470  
   471  			Entry("CF_TRACE empty, config trace file path: enables logging to file", "", "/foo", []string{"/foo"}),
   472  			Entry("CF_TRACE empty, config trace file path, '-v': enables verbose AND logging to file", "", "/foo", []string{"/foo"}),
   473  
   474  			Entry("CF_TRACE filepath: enables logging to file", "/foo", "", []string{"/foo"}),
   475  			Entry("CF_TRACE filepath, '-v': enables logging to file", "/foo", "", []string{"/foo"}),
   476  			Entry("CF_TRACE filepath, config trace true: enables verbose AND logging to file", "/foo", "true", []string{"/foo"}),
   477  			Entry("CF_TRACE filepath, config trace filepath: enables logging to file for BOTH paths", "/foo", "/bar", []string{"/foo", "/bar"}),
   478  			Entry("CF_TRACE filepath, config trace filepath, '-v': enables verbose AND logging to file for BOTH paths", "/foo", "/bar", []string{"/foo", "/bar"}),
   479  		)
   480  	})
   481  
   482  	Describe("routing", func() {
   483  		BeforeEach(func() {
   484  			helpers.SkipIfNoRoutingAPI()
   485  		})
   486  
   487  		When("the user does not provide the -v flag, the CF_TRACE env var, or the --trace config option", func() {
   488  			It("should not log requests", func() {
   489  				tmpDir, err := ioutil.TempDir("", "")
   490  				defer os.RemoveAll(tmpDir)
   491  				Expect(err).NotTo(HaveOccurred())
   492  
   493  				helpers.LoginCF()
   494  				helpers.TargetOrgAndSpace(ReadOnlyOrg, ReadOnlySpace)
   495  
   496  				command := []string{"create-shared-domain", helpers.NewDomainName(), "--router-group", "default-tcp"}
   497  
   498  				session := helpers.CF(command...)
   499  
   500  				Consistently(session).ShouldNot(Say(`GET /routing/v1`))
   501  				Eventually(session).Should(Exit(0))
   502  			})
   503  		})
   504  
   505  		DescribeTable("verbose logging to stdout",
   506  			func(cfTraceEnvVar string, configTraceValue string, vFlagSet bool) {
   507  				tmpDir, err := ioutil.TempDir("", "")
   508  				defer os.RemoveAll(tmpDir)
   509  				Expect(err).NotTo(HaveOccurred())
   510  
   511  				helpers.LoginCF()
   512  				helpers.TargetOrgAndSpace(ReadOnlyOrg, ReadOnlySpace)
   513  
   514  				var envTraceFile string
   515  				if _, err := strconv.ParseBool(cfTraceEnvVar); err != nil && len(cfTraceEnvVar) > 0 {
   516  					cfTraceEnvVar = filepath.Join(tmpDir, cfTraceEnvVar)
   517  					envTraceFile = cfTraceEnvVar
   518  				}
   519  				envMap := map[string]string{"CF_TRACE": cfTraceEnvVar}
   520  
   521  				command := []string{"create-shared-domain", helpers.NewDomainName(), "--router-group", "default-tcp"}
   522  
   523  				if vFlagSet {
   524  					command = append(command, "-v")
   525  				}
   526  
   527  				var configTraceFile string
   528  				if configTraceValue != "" {
   529  					if _, err := strconv.ParseBool(configTraceValue); err != nil && len(configTraceValue) > 0 {
   530  						configTraceValue = filepath.Join(tmpDir, configTraceValue)
   531  						configTraceFile = configTraceValue
   532  					}
   533  					session := helpers.CF("config", "--trace", configTraceValue)
   534  					Eventually(session).Should(Exit(0))
   535  				}
   536  
   537  				session := helpers.CFWithEnv(envMap, command...)
   538  
   539  				Eventually(session).Should(Say(`GET /routing/v1/router_groups\?name=default-tcp`))
   540  				Eventually(session).Should(Exit(0))
   541  
   542  				if len(envTraceFile) > 0 {
   543  					assertLogsWrittenToFile(envTraceFile, "GET /routing/v1/router_groups?name=default-tcp")
   544  				}
   545  
   546  				if len(configTraceFile) > 0 {
   547  					assertLogsWrittenToFile(configTraceFile, "GET /routing/v1/router_groups?name=default-tcp")
   548  				}
   549  			},
   550  
   551  			Entry("CF_TRACE=true, enables verbose", "true", "", false),
   552  			Entry("CF_TRACE=true, config trace false: enables verbose", "true", "false", false),
   553  			Entry("CF_TRACE=true, config trace file path: enables verbose AND logging to file", "true", "/foo", false),
   554  
   555  			Entry("CF_TRACE=false, '-v': enables verbose", "false", "", true),
   556  			Entry("CF_TRACE=false, config trace file path, '-v': enables verbose AND logging to file", "false", "/foo", true),
   557  
   558  			Entry("CF_TRACE unset, '-v': enables verbose", "", "", true),
   559  			Entry("CF_TRACE unset, config trace true: enables verbose", "", "true", false),
   560  			Entry("CF_TRACE unset, config trace file path, '-v': enables verbose AND logging to file", "", "/foo", true),
   561  
   562  			Entry("CF_TRACE=filepath, '-v': enables logging to file", "/foo", "", true),
   563  			Entry("CF_TRACE=filepath, config trace true: enables verbose AND logging to file", "/foo", "true", false),
   564  		)
   565  
   566  		DescribeTable("verbose logging to a file",
   567  			func(cfTraceEnvVar string, configTraceValue string, vFlagSet bool) {
   568  				tmpDir, err := ioutil.TempDir("", "")
   569  				defer os.RemoveAll(tmpDir)
   570  				Expect(err).NotTo(HaveOccurred())
   571  
   572  				helpers.LoginCF()
   573  				helpers.TargetOrgAndSpace(ReadOnlyOrg, ReadOnlySpace)
   574  
   575  				var envMap map[string]string
   576  
   577  				var envTraceFile string
   578  				if cfTraceEnvVar != "" {
   579  					if _, err := strconv.ParseBool(cfTraceEnvVar); err != nil {
   580  						cfTraceEnvVar = filepath.Join(tmpDir, cfTraceEnvVar)
   581  						envTraceFile = cfTraceEnvVar
   582  					}
   583  					envMap = map[string]string{"CF_TRACE": cfTraceEnvVar}
   584  				}
   585  
   586  				var configTraceFile string
   587  				if configTraceValue != "" {
   588  					if _, err := strconv.ParseBool(configTraceValue); err != nil {
   589  						configTraceValue = filepath.Join(tmpDir, configTraceValue)
   590  						configTraceFile = configTraceValue
   591  					}
   592  					session := helpers.CF("config", "--trace", configTraceValue)
   593  					Eventually(session).Should(Exit(0))
   594  				}
   595  
   596  				command := []string{"create-shared-domain", helpers.NewDomainName(), "--router-group", "default-tcp"}
   597  
   598  				if vFlagSet {
   599  					command = append(command, "-v")
   600  				}
   601  
   602  				session := helpers.CFWithEnv(envMap, command...)
   603  				Eventually(session).Should(Exit(0))
   604  
   605  				if len(envTraceFile) > 0 {
   606  					assertLogsWrittenToFile(envTraceFile, "GET /routing/v1/router_groups?name=default-tcp")
   607  				}
   608  
   609  				if len(configTraceFile) > 0 {
   610  					assertLogsWrittenToFile(configTraceFile, "GET /routing/v1/router_groups?name=default-tcp")
   611  				}
   612  			},
   613  
   614  			Entry("CF_TRACE=false, config trace file path: enables logging to file", "false", "/foo", false),
   615  			Entry("CF_TRACE unset, config trace file path: enables logging to file", "", "/foo", false),
   616  			Entry("CF_TRACE=filepath: enables logging to file", "/foo", "", false),
   617  		)
   618  
   619  		When("the values of CF_TRACE and config.trace are two different filepaths", func() {
   620  			var (
   621  				configTraceFile, envTraceFile string
   622  				cfEnv                         map[string]string
   623  			)
   624  
   625  			BeforeEach(func() {
   626  				helpers.LoginCF()
   627  				helpers.TargetOrgAndSpace(ReadOnlyOrg, ReadOnlySpace)
   628  
   629  				tmpDir, err := ioutil.TempDir("", "")
   630  				defer os.RemoveAll(tmpDir)
   631  				Expect(err).NotTo(HaveOccurred())
   632  
   633  				configTraceFile = filepath.Join(tmpDir, "/foo")
   634  				session := helpers.CF("config", "--trace", configTraceFile)
   635  				Eventually(session).Should(Exit(0))
   636  
   637  				envTraceFile = filepath.Join(tmpDir, "/bar")
   638  				cfEnv = map[string]string{
   639  					"CF_TRACE": envTraceFile,
   640  				}
   641  			})
   642  
   643  			It("logs verbose output to both files", func() {
   644  				command := []string{"create-shared-domain", helpers.NewDomainName(), "--router-group", "default-tcp"}
   645  
   646  				session := helpers.CFWithEnv(cfEnv, command...)
   647  				Eventually(session).Should(Exit(0))
   648  
   649  				assertLogsWrittenToFile(envTraceFile, "GET /routing/v1/router_groups?name=default-tcp")
   650  				assertLogsWrittenToFile(configTraceFile, "GET /routing/v1/router_groups?name=default-tcp")
   651  
   652  				configStat, err := os.Stat(configTraceFile)
   653  				Expect(err).ToNot(HaveOccurred())
   654  
   655  				envStat, err := os.Stat(envTraceFile)
   656  				Expect(err).ToNot(HaveOccurred())
   657  
   658  				var fileMode os.FileMode
   659  				if runtime.GOOS == "windows" {
   660  					fileMode = os.FileMode(0666)
   661  				} else {
   662  					fileMode = os.FileMode(0600)
   663  				}
   664  
   665  				Expect(configStat.Mode().String()).To(Equal(fileMode.String()))
   666  				Expect(envStat.Mode().String()).To(Equal(fileMode.String()))
   667  			})
   668  		})
   669  	})
   670  })
   671  
   672  func assertLogsWrittenToFile(filepath string, expected string) {
   673  	contents, err := ioutil.ReadFile(filepath)
   674  	Expect(err).ToNot(HaveOccurred())
   675  	Expect(string(contents)).To(ContainSubstring(expected), "Logging to a file failed")
   676  }