github.com/sleungcy-sap/cli@v7.1.0+incompatible/integration/v7/isolated/verbose_flag_test.go (about)

     1  package isolated
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"path/filepath"
     7  	"runtime"
     8  	"strings"
     9  
    10  	"code.cloudfoundry.org/cli/integration/helpers"
    11  	"code.cloudfoundry.org/cli/util/configv3"
    12  	. "github.com/onsi/ginkgo"
    13  	. "github.com/onsi/ginkgo/extensions/table"
    14  	. "github.com/onsi/gomega"
    15  	. "github.com/onsi/gomega/gbytes"
    16  	. "github.com/onsi/gomega/gexec"
    17  )
    18  
    19  var _ = Describe("Verbose", func() {
    20  	BeforeEach(func() {
    21  		helpers.SkipIfClientCredentialsTestMode()
    22  	})
    23  
    24  	DescribeTable("displays verbose output to terminal",
    25  		func(env string, configTrace string, flag bool) {
    26  			tmpDir, err := ioutil.TempDir("", "")
    27  			defer os.RemoveAll(tmpDir)
    28  			Expect(err).NotTo(HaveOccurred())
    29  
    30  			helpers.SetupCF(ReadOnlyOrg, ReadOnlySpace)
    31  
    32  			// Invalidate the access token to cause a token refresh in order to
    33  			// test the call to the UAA.
    34  			helpers.SetConfig(func(config *configv3.Config) {
    35  				config.ConfigFile.AccessToken = helpers.ExpiredAccessToken()
    36  			})
    37  
    38  			var envMap map[string]string
    39  			if env != "" {
    40  				if string(env[0]) == "/" {
    41  					env = filepath.Join(tmpDir, env)
    42  				}
    43  				envMap = map[string]string{"CF_TRACE": env}
    44  			}
    45  
    46  			command := []string{"run-task", "app", "--command", "echo"}
    47  
    48  			if flag {
    49  				command = append(command, "-v")
    50  			}
    51  
    52  			if configTrace != "" {
    53  				if string(configTrace[0]) == "/" {
    54  					configTrace = filepath.Join(tmpDir, configTrace)
    55  				}
    56  				session := helpers.CF("config", "--trace", configTrace)
    57  				Eventually(session).Should(Exit(0))
    58  			}
    59  
    60  			session := helpers.CFWithEnv(envMap, command...)
    61  
    62  			Eventually(session).Should(Say("REQUEST:"))
    63  			Eventually(session).Should(Say("POST /oauth/token"))
    64  			Eventually(session).Should(Say(`User-Agent: cf/[\w.+-]+ \(go\d+\.\d+(\.\d+)?; %s %s\)`, runtime.GOARCH, runtime.GOOS))
    65  			Eventually(session).Should(Say(`\[PRIVATE DATA HIDDEN\]`)) //This is required to test the previous line. If it fails, the previous matcher went too far.
    66  			Eventually(session).Should(Say("RESPONSE:"))
    67  			Eventually(session).Should(Say("REQUEST:"))
    68  			Eventually(session).Should(Say("GET /v3/apps"))
    69  			Eventually(session).Should(Say(`User-Agent: cf/[\w.+-]+ \(go\d+\.\d+(\.\d+)?; %s %s\)`, runtime.GOARCH, runtime.GOOS))
    70  			Eventually(session).Should(Say("RESPONSE:"))
    71  			Eventually(session).Should(Exit(1))
    72  		},
    73  
    74  		Entry("CF_TRACE true: enables verbose", "true", "", false),
    75  		Entry("CF_TRACE true, config trace false: enables verbose", "true", "false", false),
    76  		Entry("CF_TRACE true, config trace file path: enables verbose AND logging to file", "true", "/foo", false),
    77  
    78  		Entry("CF_TRACE false, '-v': enables verbose", "false", "", true),
    79  		Entry("CF_TRACE false, config trace file path, '-v': enables verbose AND logging to file", "false", "/foo", true),
    80  
    81  		Entry("CF_TRACE empty:, '-v': enables verbose", "", "", true),
    82  		Entry("CF_TRACE empty, config trace true: enables verbose", "", "true", false),
    83  		Entry("CF_TRACE empty, config trace file path, '-v': enables verbose AND logging to file", "", "/foo", true),
    84  
    85  		Entry("CF_TRACE filepath, '-v': enables logging to file", "/foo", "", true),
    86  		Entry("CF_TRACE filepath, config trace true: enables verbose AND logging to file", "/foo", "true", false),
    87  		Entry("CF_TRACE filepath, config trace filepath, '-v': enables verbose AND logging to file for BOTH paths", "/foo", "/bar", true),
    88  	)
    89  
    90  	DescribeTable("displays verbose output to multiple files",
    91  		func(env string, configTrace string, flag bool, location []string) {
    92  			tmpDir, err := ioutil.TempDir("", "")
    93  			defer os.RemoveAll(tmpDir)
    94  			Expect(err).NotTo(HaveOccurred())
    95  
    96  			helpers.SetupCF(ReadOnlyOrg, ReadOnlySpace)
    97  
    98  			// Invalidate the access token to cause a token refresh in order to
    99  			// test the call to the UAA.
   100  			helpers.SetConfig(func(config *configv3.Config) {
   101  				config.ConfigFile.AccessToken = helpers.ExpiredAccessToken()
   102  			})
   103  
   104  			var envMap map[string]string
   105  			if env != "" {
   106  				if string(env[0]) == "/" {
   107  					env = filepath.Join(tmpDir, env)
   108  				}
   109  				envMap = map[string]string{"CF_TRACE": env}
   110  			}
   111  
   112  			command := []string{"run-task", "app", "--command", "echo"}
   113  
   114  			if flag {
   115  				command = append(command, "-v")
   116  			}
   117  
   118  			if configTrace != "" {
   119  				if string(configTrace[0]) == "/" {
   120  					configTrace = filepath.Join(tmpDir, configTrace)
   121  				}
   122  				session := helpers.CF("config", "--trace", configTrace)
   123  				Eventually(session).Should(Exit(0))
   124  			}
   125  
   126  			session := helpers.CFWithEnv(envMap, command...)
   127  			Eventually(session).Should(Exit(1))
   128  
   129  			for _, filePath := range location {
   130  				contents, err := ioutil.ReadFile(tmpDir + filePath)
   131  				Expect(err).ToNot(HaveOccurred())
   132  
   133  				Expect(string(contents)).To(MatchRegexp("REQUEST:"))
   134  				Expect(string(contents)).To(MatchRegexp("RESPONSE:"))
   135  				Expect(string(contents)).NotTo(MatchRegexp("HTTP REQUEST:"))
   136  				Expect(string(contents)).NotTo(MatchRegexp("HTTP RESPONSE:"))
   137  				Expect(string(contents)).To(MatchRegexp("GET /v3/apps"))
   138  				Expect(string(contents)).To(MatchRegexp("POST /oauth/token"))
   139  
   140  				stat, err := os.Stat(tmpDir + filePath)
   141  				Expect(err).ToNot(HaveOccurred())
   142  
   143  				if runtime.GOOS == "windows" {
   144  					Expect(stat.Mode().String()).To(Equal(os.FileMode(0666).String()))
   145  				} else {
   146  					Expect(stat.Mode().String()).To(Equal(os.FileMode(0600).String()))
   147  				}
   148  			}
   149  		},
   150  
   151  		Entry("CF_TRACE true, config trace file path: enables verbose AND logging to file", "true", "/foo", false, []string{"/foo"}),
   152  
   153  		Entry("CF_TRACE false, config trace file path: enables logging to file", "false", "/foo", false, []string{"/foo"}),
   154  		Entry("CF_TRACE false, config trace file path, '-v': enables verbose AND logging to file", "false", "/foo", true, []string{"/foo"}),
   155  
   156  		Entry("CF_TRACE empty, config trace file path: enables logging to file", "", "/foo", false, []string{"/foo"}),
   157  		Entry("CF_TRACE empty, config trace file path, '-v': enables verbose AND logging to file", "", "/foo", true, []string{"/foo"}),
   158  
   159  		Entry("CF_TRACE filepath: enables logging to file", "/foo", "", false, []string{"/foo"}),
   160  		Entry("CF_TRACE filepath, '-v': enables logging to file", "/foo", "", true, []string{"/foo"}),
   161  		Entry("CF_TRACE filepath, config trace true: enables verbose AND logging to file", "/foo", "true", false, []string{"/foo"}),
   162  		Entry("CF_TRACE filepath, config trace filepath: enables logging to file for BOTH paths", "/foo", "/bar", false, []string{"/foo", "/bar"}),
   163  		Entry("CF_TRACE filepath, config trace filepath, '-v': enables verbose AND logging to file for BOTH paths", "/foo", "/bar", true, []string{"/foo", "/bar"}),
   164  	)
   165  
   166  	Describe("Log cache", func() {
   167  		var orgName string
   168  
   169  		BeforeEach(func() {
   170  			orgName = helpers.NewOrgName()
   171  			spaceName := helpers.NewSpaceName()
   172  
   173  			helpers.SetupCF(orgName, spaceName)
   174  		})
   175  
   176  		AfterEach(func() {
   177  			Eventually(helpers.CF("config", "--trace", "false")).Should(Exit(0))
   178  			helpers.QuickDeleteOrg(orgName)
   179  		})
   180  
   181  		DescribeTable("displays verbose output to terminal",
   182  			func(env string, configTrace string, flag bool) {
   183  				tmpDir, err := ioutil.TempDir("", "")
   184  				defer os.RemoveAll(tmpDir)
   185  				Expect(err).NotTo(HaveOccurred())
   186  
   187  				appName := helpers.PrefixedRandomName("app")
   188  
   189  				helpers.WithHelloWorldApp(func(appDir string) {
   190  					Eventually(helpers.CF("push", appName, "--no-start", "-p", appDir, "-b", "staticfile_buildpack", "--no-route")).Should(Exit(0))
   191  				})
   192  
   193  				var envMap map[string]string
   194  				if env != "" {
   195  					if string(env[0]) == "/" {
   196  						env = filepath.Join(tmpDir, env)
   197  					}
   198  					envMap = map[string]string{"CF_TRACE": env}
   199  				}
   200  
   201  				command := []string{"logs", appName}
   202  
   203  				if flag {
   204  					command = append(command, "-v")
   205  				}
   206  
   207  				if configTrace != "" {
   208  					if string(configTrace[0]) == "/" {
   209  						configTrace = filepath.Join(tmpDir, configTrace)
   210  					}
   211  					session := helpers.CF("config", "--trace", configTrace)
   212  					Eventually(session).Should(Exit(0))
   213  				}
   214  
   215  				session := helpers.CFWithEnv(envMap, command...)
   216  
   217  				Eventually(session).Should(Say("REQUEST:"))
   218  				Eventually(session).Should(Say(`GET /\s+`))
   219  				Eventually(session).Should(Say(`GET /api/v1/read/.*\?\w+`))
   220  				Eventually(session).Should(Say(`Host: log-cache\.`))
   221  				Eventually(session).Should(Say(`Authorization: \[PRIVATE DATA HIDDEN\]`))
   222  				Eventually(session.Kill()).Should(Exit())
   223  			},
   224  
   225  			Entry("CF_TRACE true: enables verbose", "true", "", false),
   226  			Entry("CF_TRACE true, config trace false: enables verbose", "true", "false", false),
   227  			Entry("CF_TRACE true, config trace file path: enables verbose AND logging to file", "true", "/foo", false),
   228  
   229  			Entry("CF_TRACE false, '-v': enables verbose", "false", "", true),
   230  			Entry("CF_TRACE false, config trace file path, '-v': enables verbose AND logging to file", "false", "/foo", true),
   231  
   232  			Entry("CF_TRACE empty:, '-v': enables verbose", "", "", true),
   233  			Entry("CF_TRACE empty, config trace true: enables verbose", "", "true", false),
   234  			Entry("CF_TRACE empty, config trace file path, '-v': enables verbose AND logging to file", "", "/foo", true),
   235  
   236  			Entry("CF_TRACE filepath, '-v': enables logging to file", "/foo", "", true),
   237  			Entry("CF_TRACE filepath, config trace true: enables verbose AND logging to file", "/foo", "true", false),
   238  			Entry("CF_TRACE filepath, config trace filepath, '-v': enables verbose AND logging to file for BOTH paths", "/foo", "/bar", true),
   239  		)
   240  
   241  		DescribeTable("displays verbose output to multiple files",
   242  			func(env string, configTrace string, location []string) {
   243  				tmpDir, err := ioutil.TempDir("", "")
   244  				defer os.RemoveAll(tmpDir)
   245  				Expect(err).NotTo(HaveOccurred())
   246  
   247  				appName := helpers.PrefixedRandomName("app")
   248  
   249  				helpers.WithHelloWorldApp(func(appDir string) {
   250  					Eventually(helpers.CF("push", appName, "--no-start", "-p", appDir, "-b", "staticfile_buildpack", "--no-route")).Should(Exit(0))
   251  				})
   252  
   253  				var envMap map[string]string
   254  				if env != "" {
   255  					if string(env[0]) == "/" {
   256  						env = filepath.Join(tmpDir, env)
   257  					}
   258  					envMap = map[string]string{"CF_TRACE": env}
   259  				}
   260  
   261  				if configTrace != "" {
   262  					if strings.HasPrefix(configTrace, "/") {
   263  						configTrace = filepath.Join(tmpDir, configTrace)
   264  					}
   265  					session := helpers.CF("config", "--trace", configTrace)
   266  					Eventually(session).Should(Exit(0))
   267  				}
   268  
   269  				session := helpers.CFWithEnv(envMap, "logs", "-v", appName)
   270  				Eventually(session).Should(Say("RESPONSE:"))
   271  				Eventually(session).Should(Say("GET /api/v1/info HTTP/1.1"))
   272  				Eventually(session).Should(Say("GET /api/v1/read/"))
   273  				session.Kill()
   274  				Eventually(session).Should(Exit())
   275  
   276  				for _, filePath := range location {
   277  					contents, err := ioutil.ReadFile(tmpDir + filePath)
   278  					Expect(err).ToNot(HaveOccurred())
   279  					Expect(string(contents)).To(MatchRegexp("REQUEST:"))
   280  					Expect(string(contents)).To(MatchRegexp("RESPONSE:"))
   281  					Expect(string(contents)).NotTo(MatchRegexp("HTTP REQUEST:"))
   282  					Expect(string(contents)).NotTo(MatchRegexp("HTTP RESPONSE:"))
   283  					Expect(string(contents)).To(MatchRegexp(`GET /\s+`))
   284  					Expect(string(contents)).To(MatchRegexp(`Host: log-cache\.`))
   285  					Expect(string(contents)).To(MatchRegexp(`Authorization: \[PRIVATE DATA HIDDEN\]`))
   286  
   287  					stat, err := os.Stat(tmpDir + filePath)
   288  					Expect(err).ToNot(HaveOccurred())
   289  
   290  					if runtime.GOOS == "windows" {
   291  						Expect(stat.Mode().String()).To(Equal(os.FileMode(0666).String()))
   292  					} else {
   293  						Expect(stat.Mode().String()).To(Equal(os.FileMode(0600).String()))
   294  					}
   295  				}
   296  			},
   297  
   298  			Entry("CF_TRACE true, config trace file path: enables verbose AND logging to file", "true", "/foo", []string{"/foo"}),
   299  
   300  			Entry("CF_TRACE false, config trace file path: enables logging to file", "false", "/foo", []string{"/foo"}),
   301  			Entry("CF_TRACE false, config trace file path, '-v': enables verbose AND logging to file", "false", "/foo", []string{"/foo"}),
   302  
   303  			Entry("CF_TRACE empty, config trace file path: enables logging to file", "", "/foo", []string{"/foo"}),
   304  			Entry("CF_TRACE empty, config trace file path, '-v': enables verbose AND logging to file", "", "/foo", []string{"/foo"}),
   305  
   306  			Entry("CF_TRACE filepath: enables logging to file", "/foo", "", []string{"/foo"}),
   307  			Entry("CF_TRACE filepath, '-v': enables logging to file", "/foo", "", []string{"/foo"}),
   308  			Entry("CF_TRACE filepath, config trace true: enables verbose AND logging to file", "/foo", "true", []string{"/foo"}),
   309  			Entry("CF_TRACE filepath, config trace filepath: enables logging to file for BOTH paths", "/foo", "/bar", []string{"/foo", "/bar"}),
   310  			Entry("CF_TRACE filepath, config trace filepath, '-v': enables verbose AND logging to file for BOTH paths", "/foo", "/bar", []string{"/foo", "/bar"}),
   311  		)
   312  	})
   313  
   314  	Describe("uaa", func() {
   315  		When("the user does not provide the -v flag, the CF_TRACE env var, or the --trace config option", func() {
   316  			It("should not log requests", func() {
   317  				tmpDir, err := ioutil.TempDir("", "")
   318  				defer os.RemoveAll(tmpDir)
   319  				Expect(err).NotTo(HaveOccurred())
   320  
   321  				helpers.LoginCF()
   322  
   323  				username, password := helpers.GetCredentials()
   324  				command := []string{"auth", username, password}
   325  
   326  				session := helpers.CF(command...)
   327  
   328  				Eventually(session).Should(Exit(0))
   329  				Expect(session).To(Say(`Authenticating...`))
   330  				Expect(session).ToNot(Say(`POST /oauth/token`))
   331  			})
   332  		})
   333  
   334  		When("the user provides the -v flag", func() {
   335  			It("should log requests and redact cookies", func() {
   336  				tmpDir, err := ioutil.TempDir("", "")
   337  				defer os.RemoveAll(tmpDir)
   338  				Expect(err).NotTo(HaveOccurred())
   339  
   340  				helpers.LoginCF()
   341  
   342  				command := []string{"target", "-o", ReadOnlyOrg, "-v"}
   343  
   344  				session := helpers.CF(command...)
   345  				Eventually(session).Should(Exit(0))
   346  				Expect(session).To(Say(`Set-Cookie: \[PRIVATE DATA HIDDEN\]`))
   347  			})
   348  		})
   349  	})
   350  
   351  	Describe("ssh", func() {
   352  		When("the user is not in verbose mode", func() {
   353  			It("should not log requests", func() {
   354  				tmpDir, err := ioutil.TempDir("", "")
   355  				defer os.RemoveAll(tmpDir)
   356  				Expect(err).NotTo(HaveOccurred())
   357  
   358  				helpers.LoginCF()
   359  
   360  				command := []string{"ssh-code"}
   361  
   362  				session := helpers.CF(command...)
   363  
   364  				Eventually(session).Should(Exit(0))
   365  				Expect(session).ToNot(Say(`GET`))
   366  			})
   367  		})
   368  
   369  		When("the user is in verbose mode", func() {
   370  			It("should redact their one time ssh code", func() {
   371  				tmpDir, err := ioutil.TempDir("", "")
   372  				defer os.RemoveAll(tmpDir)
   373  				Expect(err).NotTo(HaveOccurred())
   374  
   375  				helpers.LoginCF()
   376  
   377  				command := []string{"ssh-code", "-v"}
   378  
   379  				session := helpers.CF(command...)
   380  
   381  				Eventually(session).Should(Exit(0))
   382  				Expect(session.Out.Contents()).ToNot(MatchRegexp(`[?&]code=[^\[].*$`))
   383  				Expect(session.Out.Contents()).To(ContainSubstring("/login?code=[PRIVATE DATA HIDDEN]"))
   384  			})
   385  		})
   386  	})
   387  })