From b01715f511fd7b2ea7cb00e17a10e4f17272c9ea Mon Sep 17 00:00:00 2001 From: Max Leske <250711+theseion@users.noreply.github.com> Date: Sat, 14 Dec 2024 13:05:07 +0100 Subject: [PATCH] fix: use correct names for flags (#420) Fixes #419 --- README.md | 6 +- cmd/quantitative.go | 77 ++++++++++++++---------- cmd/root.go | 18 ++++-- cmd/run.go | 141 ++++++++++++++++++++++++++------------------ cmd/run_test.go | 127 ++++++++++++++++++++++++++++++++++++--- 5 files changed, 267 insertions(+), 102 deletions(-) diff --git a/README.md b/README.md index 0aea485..3e9ecd1 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,9 @@ Flags: --fail-fast Fail on first failed test -f, --file string output file path for ftw tests. Prints to standard output by default. -h, --help help for run - -i, --include string include only tests matching this Go regular expression (e.g. to include only tests beginning with "91", use "^91.*"). \nIf you want more permanent inclusion, check the 'include' option in the config file." + -i, --include string include only tests matching this Go regular expression (e.g. to include only tests beginning with "91", use "^91.*"). + If you want more permanent inclusion, check the 'include' option in the config file. + -T, --include-tags string include tests tagged with labels matching this Go regular expression (e.g. to include all tests being tagged with "cookie", use "^cookie$"). -l, --log-file string path to log file to watch for WAF events --max-marker-log-lines int maximum number of lines to search for a marker before aborting (default 500) --max-marker-retries int maximum number of times the search for log markers will be repeated. @@ -133,7 +135,6 @@ Flags: -r, --rate-limit duration Limit the request rate to the server to 1 request per specified duration. 0 is the default, and disables rate limiting. --read-timeout duration timeout for receiving responses during test execution (default 10s) --show-failures-only shows only the results of failed tests - -T, --include-tags string include tests tagged with labels matching this Go regular expression (e.g. to include all tests being tagged with "cookie", use "^cookie$"). -t, --time show time spent per test --wait-delay duration Time to wait between retries for all wait operations. (default 1s) --wait-for-connection-timeout duration Http connection timeout, The timeout includes connection time, any redirects, and reading the response body. (default 3s) @@ -411,7 +412,6 @@ You can configure the name of the HTTP header by setting the `logmarkerheadernam Sometimes you need to wait for a backend service to be ready before running the tests. For example, you may need to wait for an additional container to be ready before running the tests. Now you can do that by passing the `--wait-for-host` flag. The value of this option is a URL that will be requested, and you can configure the expected result using the following additional flags: - `--wait-for-host`: Wait for host to be available before running tests. -- `--wait-delay`: Time to wait between retries for all wait operations. (default 1s) - `--wait-for-connection-timeout` Http connection timeout, The timeout includes connection time, any redirects, and reading the response body. (default 3s) - `--wait-for-expect-body-json` Expect response body JSON pattern. - `--wait-for-expect-body-regex` Expect response body pattern. diff --git a/cmd/quantitative.go b/cmd/quantitative.go index 33279dd..6c09693 100644 --- a/cmd/quantitative.go +++ b/cmd/quantitative.go @@ -15,6 +15,23 @@ import ( "github.com/coreruleset/go-ftw/output" ) +const ( + corpusFlag = "corpus" + corpusLangFlag = "corpus-lang" + corpusLineFlag = "corpus-line" + corpusSizeFlag = "corpus-size" + corpusSourceFlag = "corpus-source" + corpusYearFlag = "corpus-year" + crsPathFlag = "crs-path" + corpusFileFlag = "file" + linesFlag = "lines" + maxConcurrencyFlag = "max-concurrency" + corpusOutputFlag = "output" + paranoiaLevelFlag = "paranoia-level" + payloadFlag = "payload" + ruleFlag = "rule" +) + // NewQuantitativeCmd // Returns a new cobra command for running quantitative tests func NewQuantitativeCmd() *cobra.Command { @@ -26,20 +43,20 @@ func NewQuantitativeCmd() *cobra.Command { RunE: runQuantitativeE, } - runCmd.Flags().IntP("lines", "l", 0, "Number of lines of input to process before stopping.") - runCmd.Flags().IntP("paranoia-level", "P", 1, "Paranoia level used to run the quantitative tests.") - runCmd.Flags().IntP("corpus-line", "n", 0, "Number is the payload line from the corpus to exclusively send.") - runCmd.Flags().StringP("payload", "p", "", "Payload is a string you want to test using quantitative tests. Will not use the corpus.") - runCmd.Flags().IntP("rule", "r", 0, "Rule ID of interest: only show false positives for specified rule ID.") - runCmd.Flags().IntP("max-concurrency", "", 10, "maximum number of goroutines. Defaults to 10, or 1 if log level is debug/trace.") - runCmd.Flags().StringP("corpus", "c", "leipzig", "Corpus to use for the quantitative tests.") - runCmd.Flags().StringP("corpus-lang", "L", "eng", "Corpus language to use for the quantitative tests.") - runCmd.Flags().StringP("corpus-size", "s", "100K", "Corpus size to use for the quantitative tests. Most corpora will have sizes like \"100K\", \"1M\", etc.") - runCmd.Flags().StringP("corpus-year", "y", "2023", "Corpus year to use for the quantitative tests. Most corpus will have a year like \"2023\", \"2022\", etc.") - runCmd.Flags().StringP("corpus-source", "S", "news", "Corpus source to use for the quantitative tests. Most corpus will have a source like \"news\", \"web\", \"wikipedia\", etc.") - runCmd.Flags().StringP("crs-path", "C", ".", "Path to top folder of local CRS installation.") - runCmd.Flags().StringP("file", "f", "", "Output file path for quantitative tests. Prints to standard output by default.") - runCmd.Flags().StringP("output", "o", "normal", "Output type for quantitative tests. \"normal\" is the default.") + runCmd.Flags().IntP(linesFlag, "l", 0, "Number of lines of input to process before stopping.") + runCmd.Flags().IntP(paranoiaLevelFlag, "P", 1, "Paranoia level used to run the quantitative tests.") + runCmd.Flags().IntP(corpusLineFlag, "n", 0, "Number is the payload line from the corpus to exclusively send.") + runCmd.Flags().StringP(payloadFlag, "p", "", "Payload is a string you want to test using quantitative tests. Will not use the corpus.") + runCmd.Flags().IntP(ruleFlag, "r", 0, "Rule ID of interest: only show false positives for specified rule ID.") + runCmd.Flags().IntP(maxConcurrencyFlag, "", 10, "maximum number of goroutines. Defaults to 10, or 1 if log level is debug/trace.") + runCmd.Flags().StringP(corpusFlag, "c", "leipzig", "Corpus to use for the quantitative tests.") + runCmd.Flags().StringP(corpusLangFlag, "L", "eng", "Corpus language to use for the quantitative tests.") + runCmd.Flags().StringP(corpusSizeFlag, "s", "100K", "Corpus size to use for the quantitative tests. Most corpora will have sizes like \"100K\", \"1M\", etc.") + runCmd.Flags().StringP(corpusYearFlag, "y", "2023", "Corpus year to use for the quantitative tests. Most corpus will have a year like \"2023\", \"2022\", etc.") + runCmd.Flags().StringP(corpusSourceFlag, "S", "news", "Corpus source to use for the quantitative tests. Most corpus will have a source like \"news\", \"web\", \"wikipedia\", etc.") + runCmd.Flags().StringP(crsPathFlag, "C", ".", "Path to top folder of local CRS installation.") + runCmd.Flags().StringP(corpusFileFlag, "f", "", "Output file path for quantitative tests. Prints to standard output by default.") + runCmd.Flags().StringP(corpusOutputFlag, "o", "normal", "Output type for quantitative tests. \"normal\" is the default.") return runCmd } @@ -47,24 +64,23 @@ func NewQuantitativeCmd() *cobra.Command { func runQuantitativeE(cmd *cobra.Command, _ []string) error { cmd.SilenceUsage = true - corpusTypeAsString, _ := cmd.Flags().GetString("corpus") - corpusSize, _ := cmd.Flags().GetString("corpus-size") - corpusLang, _ := cmd.Flags().GetString("corpus-lang") - corpusYear, _ := cmd.Flags().GetString("corpus-year") - corpusSource, _ := cmd.Flags().GetString("corpus-source") - directory, _ := cmd.Flags().GetString("crs-path") - fast, _ := cmd.Flags().GetInt("fast") - lines, _ := cmd.Flags().GetInt("lines") - outputFilename, _ := cmd.Flags().GetString("file") - paranoiaLevel, _ := cmd.Flags().GetInt("paranoia-level") - payload, _ := cmd.Flags().GetString("payload") - number, _ := cmd.Flags().GetInt("corpus-line") - rule, _ := cmd.Flags().GetInt("rule") - wantedOutput, _ := cmd.Flags().GetString("output") - maxConcurrency, _ := cmd.Flags().GetInt("max-concurrency") + corpusTypeAsString, _ := cmd.Flags().GetString(corpusFlag) + corpusSize, _ := cmd.Flags().GetString(corpusSizeFlag) + corpusLang, _ := cmd.Flags().GetString(corpusLangFlag) + corpusYear, _ := cmd.Flags().GetString(corpusYearFlag) + corpusSource, _ := cmd.Flags().GetString(corpusSourceFlag) + directory, _ := cmd.Flags().GetString(crsPathFlag) + lines, _ := cmd.Flags().GetInt(linesFlag) + outputFilename, _ := cmd.Flags().GetString(corpusFileFlag) + paranoiaLevel, _ := cmd.Flags().GetInt(paranoiaLevelFlag) + payload, _ := cmd.Flags().GetString(payloadFlag) + number, _ := cmd.Flags().GetInt(corpusLineFlag) + rule, _ := cmd.Flags().GetInt(ruleFlag) + wantedOutput, _ := cmd.Flags().GetString(corpusOutputFlag) + maxConcurrency, _ := cmd.Flags().GetInt(maxConcurrencyFlag) // --max-concurrency defaults to 1 if debug/trace is enabled, but if set explicitly, it should override this - if !cmd.Flags().Changed("max-concurrency") && zerolog.GlobalLevel() <= zerolog.DebugLevel { + if !cmd.Flags().Changed(maxConcurrencyFlag) && zerolog.GlobalLevel() <= zerolog.DebugLevel { maxConcurrency = 1 } @@ -100,7 +116,6 @@ func runQuantitativeE(cmd *cobra.Command, _ []string) error { CorpusLang: corpusLang, CorpusSource: corpusSource, Directory: directory, - Fast: fast, Lines: lines, ParanoiaLevel: paranoiaLevel, Number: number, diff --git a/cmd/root.go b/cmd/root.go index c1a8b19..1b8e024 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -13,6 +13,14 @@ import ( "github.com/coreruleset/go-ftw/config" ) +const ( + cloudFlag = "cloud" + configFlag = "config" + debugFlag = "debug" + overridesFlag = "overrides" + traceFlag = "trace" +) + var ( cfgFile string overridesFile string @@ -29,11 +37,11 @@ func NewRootCommand() *cobra.Command { Use: "ftw run", Short: "Framework for Testing WAFs - Go Version", } - rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "specify config file (default is $PWD/.ftw.yaml)") - rootCmd.PersistentFlags().StringVar(&overridesFile, "overrides", "", "specify file with platform specific overrides") - rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "", false, "debug output") - rootCmd.PersistentFlags().BoolVarP(&trace, "trace", "", false, "trace output: really, really verbose") - rootCmd.PersistentFlags().BoolVarP(&cloud, "cloud", "", false, "cloud mode: rely only on HTTP status codes for determining test success or failure (will not process any logs)") + rootCmd.PersistentFlags().StringVar(&cfgFile, configFlag, "", "specify config file (default is $PWD/.ftw.yaml)") + rootCmd.PersistentFlags().StringVar(&overridesFile, overridesFlag, "", "specify file with platform specific overrides") + rootCmd.PersistentFlags().BoolVarP(&debug, debugFlag, "", false, "debug output") + rootCmd.PersistentFlags().BoolVarP(&trace, traceFlag, "", false, "trace output: really, really verbose") + rootCmd.PersistentFlags().BoolVarP(&cloud, cloudFlag, "", false, "cloud mode: rely only on HTTP status codes for determining test success or failure (will not process any logs)") return rootCmd } diff --git a/cmd/run.go b/cmd/run.go index 4ec1402..26a4b67 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -22,6 +22,35 @@ import ( "github.com/coreruleset/go-ftw/test" ) +const ( + connectTimeoutFlag = "connect-timeout" + dirFlag = "dir" + excludeFlag = "exclude" + failFastFlag = "fail-fast" + fileFlag = "file" + includeFlag = "include" + includeTagsFlag = "include-tags" + logFileFlag = "log-file" + maxMarkerRetriesFlag = "max-marker-retries" + maxMarkerLogLinesFlag = "max-marker-log-lines" + outputFlag = "output" + readTimeoutFlag = "read-timeout" + rateLimitFlag = "rate-limit" + showFailuresOnlyFlag = "show-failures-only" + timeFlag = "time" + waitDelayFlag = "wait-delay" + waitForConnectionTimeoutFlag = "wait-for-connection-timeout" + waitForExpectBodyJsonFlag = "wait-for-expect-body-json" + waitForExpectBodyRegexFlag = "wait-for-expect-body-regex" + waitForExpectBodyXpathFlag = "wait-for-expect-body-xpath" + waitForExpectHeaderFlag = "wait-for-expect-header" + waitForExpectStatusCodeFlag = "wait-for-expect-status-code" + waitForHostFlag = "wait-for-host" + waitForInsecureSkipTlsVerifyFlag = "wait-for-insecure-skip-tls-verify" + waitForNoRedirectFlag = "wait-for-no-redirect" + waitForTimeoutFlag = "wait-for-timeout" +) + // NewRunCmd represents the run command func NewRunCommand() *cobra.Command { runCmd := &cobra.Command{ @@ -31,32 +60,32 @@ func NewRunCommand() *cobra.Command { RunE: runE, } - runCmd.Flags().StringP("exclude", "e", "", "exclude tests matching this Go regular expression (e.g. to exclude all tests beginning with \"91\", use \"^91.*\"). \nIf you want more permanent exclusion, check the 'exclude' option in the config file.") - runCmd.Flags().StringP("include", "i", "", "include only tests matching this Go regular expression (e.g. to include only tests beginning with \"91\", use \"^91.*\"). \\nIf you want more permanent inclusion, check the 'include' option in the config file.\"") - runCmd.Flags().StringP("include-tags", "T", "", "include tests tagged with labels matching this Go regular expression (e.g. to include all tests being tagged with \"cookie\", use \"^cookie$\").") - runCmd.Flags().StringP("dir", "d", ".", "recursively find yaml tests in this directory") - runCmd.Flags().StringP("output", "o", "normal", "output type for ftw tests. \"normal\" is the default.") - runCmd.Flags().StringP("file", "f", "", "output file path for ftw tests. Prints to standard output by default.") - runCmd.Flags().StringP("log-file", "l", "", "path to log file to watch for WAF events") - runCmd.Flags().BoolP("time", "t", false, "show time spent per test") - runCmd.Flags().BoolP("show-failures-only", "", false, "shows only the results of failed tests") - runCmd.Flags().Duration("connect-timeout", 3*time.Second, "timeout for connecting to endpoints during test execution") - runCmd.Flags().Duration("read-timeout", 10*time.Second, "timeout for receiving responses during test execution") - runCmd.Flags().Int("max-marker-retries", 20, "maximum number of times the search for log markers will be repeated.\nEach time an additional request is sent to the web server, eventually forcing the log to be flushed") - runCmd.Flags().Int("max-marker-log-lines", 500, "maximum number of lines to search for a marker before aborting") - runCmd.Flags().String("wait-for-host", "", "Wait for host to be available before running tests.") - runCmd.Flags().Duration("wait-delay", 1*time.Second, "Time to wait between retries for all wait operations.") - runCmd.Flags().Duration("wait-for-timeout", 10*time.Second, "Sets the timeout for all wait operations, 0 is unlimited.") - runCmd.Flags().Int("wait-for-expect-status-code", 0, "Expect response code e.g. 200, 204, ... .") - runCmd.Flags().String("wait-for-expect-body-regex", "", "Expect response body pattern.") - runCmd.Flags().String("wait-for-expect-body-json", "", "Expect response body JSON pattern.") - runCmd.Flags().String("wait-for-expect-body-xpath", "", "Expect response body XPath pattern.") - runCmd.Flags().String("wait-for-expect-header", "", "Expect response header pattern.") - runCmd.Flags().Duration("wait-for-connection-timeout", http.DefaultConnectionTimeout, "Http connection timeout, The timeout includes connection time, any redirects, and reading the response body.") - runCmd.Flags().Bool("wait-for-insecure-skip-tls-verify", http.DefaultInsecureSkipTLSVerify, "Skips tls certificate checks for the HTTPS request.") - runCmd.Flags().Bool("wait-for-no-redirect", http.DefaultNoRedirect, "Do not follow HTTP 3xx redirects.") - runCmd.Flags().DurationP("rate-limit", "r", 0, "Limit the request rate to the server to 1 request per specified duration. 0 is the default, and disables rate limiting.") - runCmd.Flags().Bool("fail-fast", false, "Fail on first failed test") + runCmd.Flags().StringP(excludeFlag, "e", "", "exclude tests matching this Go regular expression (e.g. to exclude all tests beginning with \"91\", use \"^91.*\"). \nIf you want more permanent exclusion, check the 'exclude' option in the config file.") + runCmd.Flags().StringP(includeFlag, "i", "", "include only tests matching this Go regular expression (e.g. to include only tests beginning with \"91\", use \"^91.*\"). \nIf you want more permanent inclusion, check the 'include' option in the config file.") + runCmd.Flags().StringP(includeTagsFlag, "T", "", "include tests tagged with labels matching this Go regular expression (e.g. to include all tests being tagged with \"cookie\", use \"^cookie$\").") + runCmd.Flags().StringP(dirFlag, "d", ".", "recursively find yaml tests in this directory") + runCmd.Flags().StringP(outputFlag, "o", "normal", "output type for ftw tests. \"normal\" is the default.") + runCmd.Flags().StringP(fileFlag, "f", "", "output file path for ftw tests. Prints to standard output by default.") + runCmd.Flags().StringP(logFileFlag, "l", "", "path to log file to watch for WAF events") + runCmd.Flags().BoolP(timeFlag, "t", false, "show time spent per test") + runCmd.Flags().BoolP(showFailuresOnlyFlag, "", false, "shows only the results of failed tests") + runCmd.Flags().Duration(connectTimeoutFlag, 3*time.Second, "timeout for connecting to endpoints during test execution") + runCmd.Flags().Duration(readTimeoutFlag, 10*time.Second, "timeout for receiving responses during test execution") + runCmd.Flags().Int(maxMarkerRetriesFlag, 20, "maximum number of times the search for log markers will be repeated.\nEach time an additional request is sent to the web server, eventually forcing the log to be flushed") + runCmd.Flags().Int(maxMarkerLogLinesFlag, 500, "maximum number of lines to search for a marker before aborting") + runCmd.Flags().String(waitForHostFlag, "", "Wait for host to be available before running tests.") + runCmd.Flags().Duration(waitDelayFlag, 1*time.Second, "Time to wait between retries for all wait operations.") + runCmd.Flags().Duration(waitForTimeoutFlag, 10*time.Second, "Sets the timeout for all wait operations, 0 is unlimited.") + runCmd.Flags().Int(waitForExpectStatusCodeFlag, 0, "Expect response code e.g. 200, 204, ... .") + runCmd.Flags().String(waitForExpectBodyRegexFlag, "", "Expect response body pattern.") + runCmd.Flags().String(waitForExpectBodyJsonFlag, "", "Expect response body JSON pattern.") + runCmd.Flags().String(waitForExpectBodyXpathFlag, "", "Expect response body XPath pattern.") + runCmd.Flags().String(waitForExpectHeaderFlag, "", "Expect response header pattern.") + runCmd.Flags().Duration(waitForConnectionTimeoutFlag, http.DefaultConnectionTimeout, "Http connection timeout, The timeout includes connection time, any redirects, and reading the response body.") + runCmd.Flags().Bool(waitForInsecureSkipTlsVerifyFlag, http.DefaultInsecureSkipTLSVerify, "Skips tls certificate checks for the HTTPS request.") + runCmd.Flags().Bool(waitForNoRedirectFlag, http.DefaultNoRedirect, "Do not follow HTTP 3xx redirects.") + runCmd.Flags().DurationP(rateLimitFlag, "r", 0, "Limit the request rate to the server to 1 request per specified duration. 0 is the default, and disables rate limiting.") + runCmd.Flags().Bool(failFastFlag, false, "Fail on first failed test") return runCmd } @@ -64,37 +93,37 @@ func NewRunCommand() *cobra.Command { //gocyclo:ignore func runE(cmd *cobra.Command, _ []string) error { cmd.SilenceUsage = true - exclude, _ := cmd.Flags().GetString("exclude") - include, _ := cmd.Flags().GetString("include") - includeTags, _ := cmd.Flags().GetString("include-tags") - dir, _ := cmd.Flags().GetString("dir") - outputFilename, _ := cmd.Flags().GetString("file") - logFilePath, _ := cmd.Flags().GetString("log-file") - showTime, _ := cmd.Flags().GetBool("time") - showOnlyFailed, _ := cmd.Flags().GetBool("show-failures-only") - wantedOutput, _ := cmd.Flags().GetString("output") - connectTimeout, _ := cmd.Flags().GetDuration("connect-timeout") - readTimeout, _ := cmd.Flags().GetDuration("read-timeout") - maxMarkerRetries, _ := cmd.Flags().GetUint("max-marker-retries") - maxMarkerLogLines, _ := cmd.Flags().GetUint("max-marker-log-lines") + exclude, _ := cmd.Flags().GetString(excludeFlag) + include, _ := cmd.Flags().GetString(includeFlag) + includeTags, _ := cmd.Flags().GetString(includeTagsFlag) + dir, _ := cmd.Flags().GetString(dirFlag) + outputFilename, _ := cmd.Flags().GetString(fileFlag) + logFilePath, _ := cmd.Flags().GetString(logFileFlag) + showTime, _ := cmd.Flags().GetBool(timeFlag) + showOnlyFailed, _ := cmd.Flags().GetBool(showFailuresOnlyFlag) + wantedOutput, _ := cmd.Flags().GetString(outputFlag) + connectTimeout, _ := cmd.Flags().GetDuration(connectTimeoutFlag) + readTimeout, _ := cmd.Flags().GetDuration(readTimeoutFlag) + maxMarkerRetries, _ := cmd.Flags().GetUint(maxMarkerRetriesFlag) + maxMarkerLogLines, _ := cmd.Flags().GetUint(maxMarkerLogLinesFlag) // wait4x flags - waitForHost, _ := cmd.Flags().GetString("wait-for-host") - timeout, _ := cmd.Flags().GetDuration("wait-for-timeout") - interval, _ := cmd.Flags().GetDuration("wait-for-interval") - expectStatusCode, _ := cmd.Flags().GetInt("wait-for-expect-status-code") - expectBodyRegex, _ := cmd.Flags().GetString("wait-for-expect-body-regex") - expectBodyJSON, _ := cmd.Flags().GetString("wait-for-expect-body-json") - expectBodyXPath, _ := cmd.Flags().GetString("wait-for-expect-body-xpath") - expectHeader, _ := cmd.Flags().GetString("wait-for-expect-header") - connectionTimeout, _ := cmd.Flags().GetDuration("wait-for-connection-timeout") - insecureSkipTLSVerify, _ := cmd.Flags().GetBool("wait-for-insecure-skip-tls-verify") - noRedirect, _ := cmd.Flags().GetBool("wait-for-no-redirect") - rateLimit, _ := cmd.Flags().GetDuration("rate-limit") - failFast, _ := cmd.Flags().GetBool("fail-fast") + waitForHost, _ := cmd.Flags().GetString(waitForHostFlag) + timeout, _ := cmd.Flags().GetDuration(waitForTimeoutFlag) + interval, _ := cmd.Flags().GetDuration(waitDelayFlag) + expectStatusCode, _ := cmd.Flags().GetInt(waitForExpectStatusCodeFlag) + expectBodyRegex, _ := cmd.Flags().GetString(waitForExpectBodyRegexFlag) + expectBodyJSON, _ := cmd.Flags().GetString(waitForExpectBodyJsonFlag) + expectBodyXPath, _ := cmd.Flags().GetString(waitForExpectBodyXpathFlag) + expectHeader, _ := cmd.Flags().GetString(waitForExpectHeaderFlag) + connectionTimeout, _ := cmd.Flags().GetDuration(waitForConnectionTimeoutFlag) + insecureSkipTLSVerify, _ := cmd.Flags().GetBool(waitForInsecureSkipTlsVerifyFlag) + noRedirect, _ := cmd.Flags().GetBool(waitForNoRedirectFlag) + rateLimit, _ := cmd.Flags().GetDuration(rateLimitFlag) + failFast, _ := cmd.Flags().GetBool(failFastFlag) if exclude != "" && include != "" { cmd.SilenceUsage = false - return fmt.Errorf("you need to choose one: use --include (%s) or --exclude (%s)", include, exclude) + return fmt.Errorf("you need to choose one: use --%s (%s) or --%s (%s)", includeFlag, include, excludeFlag, exclude) } if maxMarkerRetries != 0 { cfg.WithMaxMarkerRetries(maxMarkerRetries) @@ -116,19 +145,19 @@ func runE(cmd *cobra.Command, _ []string) error { var includeRE *regexp.Regexp if include != "" { if includeRE, err = regexp.Compile(include); err != nil { - return fmt.Errorf("invalid --include regular expression: %w", err) + return fmt.Errorf("invalid --%s regular expression: %w", includeFlag, err) } } var excludeRE *regexp.Regexp if exclude != "" { if excludeRE, err = regexp.Compile(exclude); err != nil { - return fmt.Errorf("invalid --exclude regular expression: %w", err) + return fmt.Errorf("invalid --%s regular expression: %w", excludeFlag, err) } } var includeTagsRE *regexp.Regexp if includeTags != "" { if includeTagsRE, err = regexp.Compile(includeTags); err != nil { - return fmt.Errorf("invalid --include-tags regular expression: %w", err) + return fmt.Errorf("invalid --%s regular expression: %w", includeTagsFlag, err) } } diff --git a/cmd/run_test.go b/cmd/run_test.go index b5a3915..c158848 100644 --- a/cmd/run_test.go +++ b/cmd/run_test.go @@ -15,6 +15,7 @@ import ( "strconv" "testing" "text/template" + "time" "github.com/spf13/cobra" "github.com/stretchr/testify/suite" @@ -102,7 +103,7 @@ func TestRunChoreTestSuite(t *testing.T) { } func (s *runCmdTestSuite) TestHTTPCommandInvalidAddress() { - s.rootCmd.SetArgs([]string{"run", "-d", s.tempDir, "--wait-for-host", "http://local host"}) + s.rootCmd.SetArgs([]string{"run", "-d", s.tempDir, "--" + waitForHostFlag, "http://local host"}) cmd, err := s.rootCmd.ExecuteContextC(context.Background()) s.Equal("run", cmd.Name()) @@ -111,27 +112,139 @@ func (s *runCmdTestSuite) TestHTTPCommandInvalidAddress() { } func (s *runCmdTestSuite) TestHTTPConnectionSuccess() { - s.rootCmd.SetArgs([]string{"run", "--cloud", "-d", s.tempDir, "--wait-for-host", s.testHTTPServer.URL}) + s.rootCmd.SetArgs([]string{"run", "--" + cloudFlag, "-d", s.tempDir, "--" + waitForHostFlag, s.testHTTPServer.URL}) _, err := s.rootCmd.ExecuteContextC(context.Background()) s.Require().NoError(err) } func (s *runCmdTestSuite) TestHTTPConnectionFail() { - s.rootCmd.SetArgs([]string{"run", "--cloud", "-d", s.tempDir, "--wait-for-timeout", "2s", "--wait-for-host", "http://not-exists-doomain.tld"}) + s.rootCmd.SetArgs([]string{"run", "--" + cloudFlag, "-d", s.tempDir, "--" + waitForTimeoutFlag, "2s", "--" + waitForHostFlag, "http://not-exists-doomain.tld"}) _, err := s.rootCmd.ExecuteContextC(context.Background()) s.Equal(context.DeadlineExceeded, err) } -// func TestHTTPRequestHeaderSuccess(t *testing.T) { func (s *runCmdTestSuite) TestHTTPRequestHeaderSuccess() { s.rootCmd.SetArgs([]string{ - "run", "--cloud", "-d", s.tempDir, - "--wait-for-host", s.testHTTPServer.URL, - "--wait-for-expect-body-regex", "(.*User-Agent=\\[Go-http-client/1.1\\].*)", + "run", "--" + cloudFlag, "-d", s.tempDir, + "--" + waitForHostFlag, s.testHTTPServer.URL, + "--" + waitForExpectBodyRegexFlag, `.*User-Agent=\[Go-http-client/1\.1\].*`, }) _, err := s.rootCmd.ExecuteContextC(context.Background()) s.Require().NoError(err) } + +func (s *runCmdTestSuite) TestFlags() { + s.rootCmd.SetArgs([]string{ + "run", + "--" + excludeFlag, "123456", + "--" + includeFlag, "789012", + "--" + includeTagsFlag, "^a-tag.*$", + "--" + dirFlag, "/foo/bar", + "--" + outputFlag, "github", + "--" + fileFlag, "out.out", + "--" + logFileFlag, "/path/to/log.log", + "--" + timeFlag, + "--" + showFailuresOnlyFlag, + "--" + connectTimeoutFlag, "4s", + "--" + readTimeoutFlag, "5s", + "--" + maxMarkerRetriesFlag, "6", + "--" + maxMarkerLogLinesFlag, "7", + "--" + waitForHostFlag, "https://some-host.com", + "--" + waitDelayFlag, "9s", + "--" + waitForTimeoutFlag, "10s", + "--" + waitForExpectStatusCodeFlag, "204", + "--" + waitForExpectBodyRegexFlag, "^some-body$", + "--" + waitForExpectBodyJsonFlag, `{"some": "attribute"}`, + "--" + waitForExpectBodyXpathFlag, "count(//p)", + "--" + waitForExpectHeaderFlag, "X-Some-Header", + "--" + waitForConnectionTimeoutFlag, "11s", + "--" + waitForInsecureSkipTlsVerifyFlag, + "--" + waitForNoRedirectFlag, + "--" + rateLimitFlag, "12s", + "--" + failFastFlag, + }) + cmd, _ := s.rootCmd.ExecuteC() + + exclude, err := cmd.Flags().GetString(excludeFlag) + s.NoError(err) + include, err := cmd.Flags().GetString(includeFlag) + s.NoError(err) + includeTags, err := cmd.Flags().GetString(includeTagsFlag) + s.NoError(err) + dir, err := cmd.Flags().GetString(dirFlag) + s.NoError(err) + output, err := cmd.Flags().GetString(outputFlag) + s.NoError(err) + file, err := cmd.Flags().GetString(fileFlag) + s.NoError(err) + logFile, err := cmd.Flags().GetString(logFileFlag) + s.NoError(err) + _time, err := cmd.Flags().GetBool(timeFlag) + s.NoError(err) + showFailuresOnly, err := cmd.Flags().GetBool(showFailuresOnlyFlag) + s.NoError(err) + connectTimeout, err := cmd.Flags().GetDuration(connectTimeoutFlag) + s.NoError(err) + readTimeout, err := cmd.Flags().GetDuration(readTimeoutFlag) + s.NoError(err) + maxMarkerRetries, err := cmd.Flags().GetInt(maxMarkerRetriesFlag) + s.NoError(err) + maxMarkerLogLines, err := cmd.Flags().GetInt(maxMarkerLogLinesFlag) + s.NoError(err) + waitForHost, err := cmd.Flags().GetString(waitForHostFlag) + s.NoError(err) + waitDelay, err := cmd.Flags().GetDuration(waitDelayFlag) + s.NoError(err) + waitForTimeout, err := cmd.Flags().GetDuration(waitForTimeoutFlag) + s.NoError(err) + waitForExpectStatusCode, err := cmd.Flags().GetInt(waitForExpectStatusCodeFlag) + s.NoError(err) + waitForExpectBodyRegex, err := cmd.Flags().GetString(waitForExpectBodyRegexFlag) + s.NoError(err) + waitForExpectBodyJson, err := cmd.Flags().GetString(waitForExpectBodyJsonFlag) + s.NoError(err) + waitForeExpectBodyXpath, err := cmd.Flags().GetString(waitForExpectBodyXpathFlag) + s.NoError(err) + waitForExpectHeader, err := cmd.Flags().GetString(waitForExpectHeaderFlag) + s.NoError(err) + waitForConnectionTimeout, err := cmd.Flags().GetDuration(waitForConnectionTimeoutFlag) + s.NoError(err) + waitForInsecureSkipTlsVerify, err := cmd.Flags().GetBool(waitForInsecureSkipTlsVerifyFlag) + s.NoError(err) + waitForNoRedirect, err := cmd.Flags().GetBool(waitForNoRedirectFlag) + s.NoError(err) + rateLimit, err := cmd.Flags().GetDuration(rateLimitFlag) + s.NoError(err) + failFast, err := cmd.Flags().GetBool(failFastFlag) + s.NoError(err) + + s.Equal("123456", exclude) + s.Equal("789012", include) + s.Equal("^a-tag.*$", includeTags) + s.Equal("/foo/bar", dir) + s.Equal("github", output) + s.Equal("out.out", file) + s.Equal("/path/to/log.log", logFile) + s.Equal(true, _time) + s.Equal(true, showFailuresOnly) + s.Equal(4*time.Second, connectTimeout) + s.Equal(5*time.Second, readTimeout) + s.Equal(6, maxMarkerRetries) + s.Equal(7, maxMarkerLogLines) + s.Equal("https://some-host.com", waitForHost) + s.Equal(9*time.Second, waitDelay) + s.Equal(10*time.Second, waitForTimeout) + s.Equal(204, waitForExpectStatusCode) + s.Equal("^some-body$", waitForExpectBodyRegex) + s.Equal(`{"some": "attribute"}`, waitForExpectBodyJson) + s.Equal("count(//p)", waitForeExpectBodyXpath) + s.Equal("X-Some-Header", waitForExpectHeader) + s.Equal(11*time.Second, waitForConnectionTimeout) + s.Equal(true, waitForInsecureSkipTlsVerify) + s.Equal(true, waitForNoRedirect) + s.Equal(12*time.Second, rateLimit) + s.Equal(true, failFast) +}