From 4fd61b310501eedb6708009fd9537669a208ea57 Mon Sep 17 00:00:00 2001 From: Nikolai Vladimirov Date: Mon, 4 Mar 2024 21:55:25 +0200 Subject: [PATCH] chore: use golangci-lint & fix formatting --- .github/workflows/ci.yaml | 2 +- .gitignore | 1 + .golangci.yml | 108 ++++++++++++++++++ Makefile | 30 ++--- internal/chart/chart_cmd.go | 25 ++-- internal/chart/chart_cmd_stage_test.go | 5 +- internal/chart/chart_cmd_test.go | 7 -- internal/raterun/runner_test_stage.go | 7 +- internal/run/active_scenario.go | 7 +- internal/run/logging.go | 2 +- internal/run/logging_test.go | 9 +- internal/run/main_test.go | 7 +- internal/run/output.go | 42 ++++--- internal/run/prom_push_gw_test.go | 4 +- internal/run/run_cmd.go | 11 +- internal/run/run_cmd_test.go | 3 - internal/run/run_stage_test.go | 31 ++--- internal/run/test_runner.go | 28 +++-- internal/trace/trace.go | 12 +- internal/trigger/api/api.go | 10 +- .../api/iteration_distribution_test.go | 8 +- internal/trigger/api/iteration_worker.go | 3 +- internal/trigger/constant/constant_rate.go | 10 +- internal/trigger/file/file_parser.go | 25 ++-- internal/trigger/file/file_parser_test.go | 4 +- internal/trigger/file/file_rate.go | 7 +- internal/trigger/file/stages_worker.go | 4 +- internal/trigger/gaussian/gaussian_rate.go | 20 ++-- .../trigger/gaussian/gaussian_rate_test.go | 5 +- internal/trigger/ramp/ramp_rate.go | 20 ++-- internal/trigger/rate/rate.go | 7 +- internal/trigger/staged/stage.go | 2 - internal/trigger/staged/stage_test.go | 10 +- internal/trigger/staged/staged_rate.go | 17 ++- internal/trigger/users/users_rate.go | 3 +- pkg/f1/completions.go | 5 +- pkg/f1/doc.go | 9 +- pkg/f1/f1_scenarios.go | 9 +- pkg/f1/f1_scenarios_stage_test.go | 5 +- pkg/f1/root_cmd.go | 13 +-- pkg/f1/testing/doc.go | 2 +- pkg/f1/testing/t.go | 3 +- pkg/f1/testing/t_test.go | 3 +- scripts/goimportscheck.sh | 13 --- scripts/install-golangci-lint.sh | 31 +++++ 45 files changed, 345 insertions(+), 244 deletions(-) create mode 100644 .golangci.yml delete mode 100755 scripts/goimportscheck.sh create mode 100755 scripts/install-golangci-lint.sh diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c24bb8a4..73f94f4e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -9,5 +9,5 @@ jobs: go-version: "1.20" - name: test run: | - make install-goimports + make lint make test diff --git a/.gitignore b/.gitignore index 485dee64..8fe9ae94 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .idea +/tools diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 00000000..2b15bb96 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,108 @@ +# Using golangci-lint@v1.56.2 +run: + timeout: 5m + tests: true + skip-dirs: + - vendor$ +output: + print-linter-name: true +linters: + enable-all: true + fast: false + disable: + # Deprecated (see https://golangci-lint.run/usage/linters/) + - deadcode + - golint + - ifshort + - interfacer + - maligned + - nosnakecase + - scopelint + - structcheck + - varcheck + - exhaustivestruct + + # Annoying style guides that are very subjective + - funlen + - nlreturn + - wsl + - cyclop + - varnamelen + - maintidx + - gocognit + - godot + - gocyclo + - nestif + - nilnil + - exhaustruct + + # Requires too many changes + - testpackage + + - thelper + - wrapcheck + - testifylint + + # TODO + - usestdlibvars + - paralleltest + - perfsprint + - staticcheck + - gomnd + - nonamedreturns + - goerr113 + - gochecknoglobals + - dupword + - depguard + - unparam + - revive + - stylecheck + - unused + - protogetter + - lll + - prealloc + - forcetypeassert + - gocritic + - forbidigo + - dupl + - errcheck + - gosec + - ineffassign + - wastedassign + +linters-settings: + tagliatelle: + case: + rules: + json: snake + yaml: kebab + depguard: + rules: + main: + deny: + - pkg: "github.com/pkg/errors" + desc: "Please use go built-in error wrapping and handling via `fmt` and `errors` packages" + gci: + sections: + - standard + - default + - prefix(github.com/form3tech-oss/f1) +issues: + max-issues-per-linter: 0 + max-same-issues: 0 + exclude-rules: + # exclude long lines with URLs + - path: \.go + source: https:// + linters: + - lll + # Don't wrap check RoundTrip + - path: \.go + source: RoundTrip + linters: + - wrapcheck + - path: _test\.go + linters: + # unwrapped errors are ok in tests + - wrapcheck + diff --git a/Makefile b/Makefile index 8b663b35..a28eb4da 100644 --- a/Makefile +++ b/Makefile @@ -1,20 +1,22 @@ -GO_FILES?=$$(find ./ -name '*.go' | grep -v /vendor | grep -v /template/ | grep -v /build/ | grep -v swagger-client) +GOLANGCI_VERSION := 1.56.2 -test: goimportscheck +.PHONY: test +test: go test ./... -v -race -failfast -p 1 -mod=readonly -require-travis-env: -ifndef TRAVIS - $(error TRAVIS is undefined) -endif +.PHONY: tools/golangci-lint +tools/golangci-lint: + @echo "==> Installing golangci-lint..." + @./scripts/install-golangci-lint.sh $(GOLANGCI_VERSION) -install-goimports: - @if [ -z "$$(command -v goimports)" ]; then \ - go get golang.org/x/tools/cmd/goimports; \ - fi +.PHONY: lint +lint: tools/golangci-lint + @echo "==> Running golangci-lint..." + @tools/golangci-lint run --timeout 600s + +.PHONY: lint-fix +lint-fix: tools/golangci-lint + @echo "==> Running golangci-lint..." + @tools/golangci-lint run --timeout 600s --fix -goimports: - @goimports -w $(GO_FILES) -goimportscheck: - @sh -c "'$(CURDIR)/scripts/goimportscheck.sh'" diff --git a/internal/chart/chart_cmd.go b/internal/chart/chart_cmd.go index b466f2c8..75e88fd5 100644 --- a/internal/chart/chart_cmd.go +++ b/internal/chart/chart_cmd.go @@ -5,17 +5,12 @@ import ( "os" "time" - "github.com/pkg/errors" + "github.com/guptarohit/asciigraph" + "github.com/spf13/cobra" + "github.com/wcharczuk/go-chart/v2" "github.com/form3tech-oss/f1/v2/internal/support/errorh" - "github.com/form3tech-oss/f1/v2/internal/trigger/api" - - "github.com/wcharczuk/go-chart/v2" - - "github.com/guptarohit/asciigraph" - - "github.com/spf13/cobra" ) func Cmd(builders []api.Builder) *cobra.Command { @@ -46,24 +41,24 @@ func chartCmdExecute(t api.Builder) func(cmd *cobra.Command, args []string) erro startString, err := cmd.Flags().GetString("chart-start") if err != nil { - return errors.Wrap(err, "Invalid chart-start value") + return fmt.Errorf("getting flag: %w", err) } start, err := time.Parse(time.RFC3339, startString) if err != nil { - return err + return fmt.Errorf("parsing start time: %w", err) } duration, err := cmd.Flags().GetDuration("chart-duration") if err != nil { - return err + return fmt.Errorf("getting flag: %w", err) } filename, err := cmd.Flags().GetString("filename") if err != nil { - return err + return fmt.Errorf("getting flag: %w", err) } trig, err := t.New(cmd.Flags()) if err != nil { - return err + return fmt.Errorf("creating builder: %w", err) } if trig.DryRun == nil { @@ -119,13 +114,13 @@ func chartCmdExecute(t api.Builder) func(cmd *cobra.Command, args []string) erro f, err := os.Create(filename) if err != nil { - return err + return fmt.Errorf("creting file: %w", err) } defer errorh.SafeClose(f) err = graph.Render(chart.PNG, f) if err != nil { - return err + return fmt.Errorf("rendering graph: %w", err) } fmt.Printf("Detailed chart written to %s\n", filename) return nil diff --git a/internal/chart/chart_cmd_stage_test.go b/internal/chart/chart_cmd_stage_test.go index 447c1897..6669b4a3 100644 --- a/internal/chart/chart_cmd_stage_test.go +++ b/internal/chart/chart_cmd_stage_test.go @@ -5,9 +5,9 @@ import ( "testing" "time" - "github.com/form3tech-oss/f1/v2/internal/trigger" - "github.com/stretchr/testify/assert" + + "github.com/form3tech-oss/f1/v2/internal/trigger" ) type ChartTestStage struct { @@ -28,6 +28,7 @@ func NewChartTestStage(t *testing.T) (*ChartTestStage, *ChartTestStage, *ChartTe func (s *ChartTestStage) and() *ChartTestStage { return s } + func (s *ChartTestStage) i_execute_the_chart_command() *ChartTestStage { cmd := Cmd(trigger.GetBuilders()) cmd.SetArgs(s.args) diff --git a/internal/chart/chart_cmd_test.go b/internal/chart/chart_cmd_test.go index 0abc5cdd..939beb87 100644 --- a/internal/chart/chart_cmd_test.go +++ b/internal/chart/chart_cmd_test.go @@ -16,7 +16,6 @@ func TestChartConstant(t *testing.T) { then. the_command_is_successful() - } func TestChartConstantNoJitter(t *testing.T) { @@ -30,7 +29,6 @@ func TestChartConstantNoJitter(t *testing.T) { then. the_command_is_successful() - } func TestChartStaged(t *testing.T) { @@ -44,7 +42,6 @@ func TestChartStaged(t *testing.T) { then. the_command_is_successful() - } func TestChartGaussian(t *testing.T) { @@ -59,7 +56,6 @@ func TestChartGaussian(t *testing.T) { then. the_command_is_successful() - } func TestChartGaussianWithJitter(t *testing.T) { @@ -75,7 +71,6 @@ func TestChartGaussianWithJitter(t *testing.T) { then. the_command_is_successful() - } func TestChartRamp(t *testing.T) { @@ -89,7 +84,6 @@ func TestChartRamp(t *testing.T) { then. the_command_is_successful() - } func TestChartFileConfig(t *testing.T) { @@ -103,5 +97,4 @@ func TestChartFileConfig(t *testing.T) { then. the_command_is_successful() - } diff --git a/internal/raterun/runner_test_stage.go b/internal/raterun/runner_test_stage.go index ab61ee51..341be960 100644 --- a/internal/raterun/runner_test_stage.go +++ b/internal/raterun/runner_test_stage.go @@ -5,9 +5,8 @@ import ( "testing" "time" - "go.uber.org/goleak" - "github.com/stretchr/testify/assert" + "go.uber.org/goleak" ) type RatedRunnerStage struct { @@ -19,6 +18,8 @@ type RatedRunnerStage struct { } func NewRatedRunnerStage(t *testing.T) (*RatedRunnerStage, *RatedRunnerStage, *RatedRunnerStage) { + t.Helper() + stage := RatedRunnerStage{ t: t, funcRuns: make(map[time.Duration]int), @@ -69,7 +70,7 @@ func (s *RatedRunnerStage) function_ran_times(expectedRuns int) *RatedRunnerStag totalRuns += timesRunForRate } - assert.Equal(s.t, totalRuns, expectedRuns) + assert.Equal(s.t, expectedRuns, totalRuns) return s } diff --git a/internal/run/active_scenario.go b/internal/run/active_scenario.go index 891a256a..750bba7d 100644 --- a/internal/run/active_scenario.go +++ b/internal/run/active_scenario.go @@ -3,12 +3,11 @@ package run import ( "time" - "github.com/form3tech-oss/f1/v2/pkg/f1/scenarios" - - "github.com/form3tech-oss/f1/v2/pkg/f1/testing" + "github.com/google/uuid" "github.com/form3tech-oss/f1/v2/internal/metrics" - "github.com/google/uuid" + "github.com/form3tech-oss/f1/v2/pkg/f1/scenarios" + "github.com/form3tech-oss/f1/v2/pkg/f1/testing" ) type ActiveScenario struct { diff --git a/internal/run/logging.go b/internal/run/logging.go index 5b26ded1..5cb73750 100644 --- a/internal/run/logging.go +++ b/internal/run/logging.go @@ -36,7 +36,7 @@ func getLogFilePath(scenario string) string { func redirectLoggingToFile(scenario string) string { logFilePath := getLogFilePath(scenario) - file, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) + file, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o600) if err == nil { log.StandardLogger().SetOutput(file) } else { diff --git a/internal/run/logging_test.go b/internal/run/logging_test.go index 898e3659..8d49a73a 100644 --- a/internal/run/logging_test.go +++ b/internal/run/logging_test.go @@ -9,8 +9,7 @@ import ( ) func TestProvidingCustomLogFilePathWithDirectoryThatDoesExist(t *testing.T) { - defer os.Setenv("LOG_FILE_PATH", os.Getenv("LOG_FILE_PATH")) - os.Setenv("LOG_FILE_PATH", "/does-not-exist/my-scenario.log") + t.Setenv("LOG_FILE_PATH", "/does-not-exist/my-scenario.log") expected := getGeneratedLogFilePath("my-scenario") actual := getLogFilePath("my-scenario") @@ -20,9 +19,8 @@ func TestProvidingCustomLogFilePathWithDirectoryThatDoesExist(t *testing.T) { } func TestProvidingCustomLogFilePathWithDirectoryThatDoesNotExistResultsInGeneratedLogFile(t *testing.T) { - defer os.Setenv("LOG_FILE_PATH", os.Getenv("LOG_FILE_PATH")) expected := filepath.Join(os.TempDir(), "my-scenario.log") - os.Setenv("LOG_FILE_PATH", expected) + t.Setenv("LOG_FILE_PATH", expected) actual := getLogFilePath("my-scenario") @@ -31,8 +29,7 @@ func TestProvidingCustomLogFilePathWithDirectoryThatDoesNotExistResultsInGenerat } func TestProvidingCustomLogFilePathWhichIsEmptyResultsInGeneratedLogFile(t *testing.T) { - defer os.Setenv("LOG_FILE_PATH", os.Getenv("LOG_FILE_PATH")) - os.Setenv("LOG_FILE_PATH", "") + t.Setenv("LOG_FILE_PATH", "") expected := getGeneratedLogFilePath("my-scenario") actual := getLogFilePath("my-scenario") diff --git a/internal/run/main_test.go b/internal/run/main_test.go index 1800848b..469a8496 100644 --- a/internal/run/main_test.go +++ b/internal/run/main_test.go @@ -12,11 +12,12 @@ import ( var fakePrometheus FakePrometheus -const fakePrometheusNamespace = "test-namespace" -const fakePrometheusID = "test-run-name" +const ( + fakePrometheusNamespace = "test-namespace" + fakePrometheusID = "test-run-name" +) func TestMain(m *testing.M) { - var err error fakePrometheus.Port, err = freeport.GetFreePort() if err != nil { diff --git a/internal/run/output.go b/internal/run/output.go index c229f3fa..e0f8a8a9 100644 --- a/internal/run/output.go +++ b/internal/run/output.go @@ -9,28 +9,26 @@ import ( "github.com/workanator/go-ataman" ) -var ( - templateFunctions = template.FuncMap{ - "add": func(i, j uint64) uint64 { - return i + j - }, - "rate": func(duration time.Duration, count uint64) uint64 { - if uint64(duration/time.Second) == 0 { - return 0 - } - return count / uint64(duration/time.Second) - }, - "durationSeconds": func(t time.Duration) time.Duration { - return t.Round(time.Second) - }, - "duration": func(t time.Duration) string { - return durafmt.Parse(t).String() - }, - "percent": func(val, total uint64) float64 { - return 100.0 * float64(val) / float64(total) - }, - } -) +var templateFunctions = template.FuncMap{ + "add": func(i, j uint64) uint64 { + return i + j + }, + "rate": func(duration time.Duration, count uint64) uint64 { + if uint64(duration/time.Second) == 0 { + return 0 + } + return count / uint64(duration/time.Second) + }, + "durationSeconds": func(t time.Duration) time.Duration { + return t.Round(time.Second) + }, + "duration": func(t time.Duration) string { + return durafmt.Parse(t).String() + }, + "percent": func(val, total uint64) float64 { + return 100.0 * float64(val) / float64(total) + }, +} func renderTemplate(t *template.Template, r interface{}) string { var builder strings.Builder diff --git a/internal/run/prom_push_gw_test.go b/internal/run/prom_push_gw_test.go index dc72e304..3722fbe7 100644 --- a/internal/run/prom_push_gw_test.go +++ b/internal/run/prom_push_gw_test.go @@ -9,12 +9,10 @@ import ( "sync/atomic" io_prometheus_client "github.com/prometheus/client_model/go" - "github.com/prometheus/common/expfmt" + log "github.com/sirupsen/logrus" "github.com/form3tech-oss/f1/v2/internal/support/errorh" - - log "github.com/sirupsen/logrus" ) type FakePrometheus struct { diff --git a/internal/run/run_cmd.go b/internal/run/run_cmd.go index 8afad95a..79e51165 100644 --- a/internal/run/run_cmd.go +++ b/internal/run/run_cmd.go @@ -4,16 +4,13 @@ import ( "fmt" "time" - "github.com/form3tech-oss/f1/v2/internal/options" - "github.com/form3tech-oss/f1/v2/pkg/f1/scenarios" - "github.com/pkg/errors" + "github.com/spf13/cobra" "github.com/form3tech-oss/f1/v2/internal/logging" - + "github.com/form3tech-oss/f1/v2/internal/options" "github.com/form3tech-oss/f1/v2/internal/trigger/api" - - "github.com/spf13/cobra" + "github.com/form3tech-oss/f1/v2/pkg/f1/scenarios" ) func Cmd(s *scenarios.Scenarios, builders []api.Builder, hookFunc logging.RegisterLogHookFunc) *cobra.Command { @@ -50,7 +47,7 @@ func Cmd(s *scenarios.Scenarios, builders []api.Builder, hookFunc logging.Regist triggerCmd.Flags().DurationP("max-duration", "d", time.Second, "--max-duration 1s (stop after 1 second)") triggerCmd.Flags().IntP("concurrency", "c", 100, "--concurrency 2 (allow at most 2 groups of iterations to run concurrently)") triggerCmd.Flags().Int32P("max-iterations", "i", 0, "--max-iterations 100 (stop after 100 iterations, regardless of remaining duration)") - triggerCmd.Flags().Int("max-failures", 0, "--max-failures 10 (load test will fail if more than 10 errors occured, default is 0)") + triggerCmd.Flags().Int("max-failures", 0, "--max-failures 10 (load test will fail if more than 10 errors occurred, default is 0)") triggerCmd.Flags().Int("max-failures-rate", 0, "--max-failures-rate 5 (load test will fail if more than 5\\% requests failed, default is 0)") triggerCmd.Flags().AddFlagSet(t.Flags) diff --git a/internal/run/run_cmd_test.go b/internal/run/run_cmd_test.go index 4c0af34d..f6c70ba9 100644 --- a/internal/run/run_cmd_test.go +++ b/internal/run/run_cmd_test.go @@ -42,7 +42,6 @@ func TestSimpleFlow(t *testing.T) { the_command_should_have_run_for_approx(test.expectedRunTime).and(). the_number_of_started_iterations_should_be(test.expectedCompletedTests).and(). the_number_of_dropped_iterations_should_be(test.expectedDroppedIterations) - } type TriggerType int @@ -555,7 +554,6 @@ func TestInterruptedRun(t *testing.T) { } func TestFinalRunMetrics(t *testing.T) { - given, when, then := NewRunTestStage(t) given. a_rate_of("100/100ms").and(). @@ -568,7 +566,6 @@ func TestFinalRunMetrics(t *testing.T) { metrics_are_pushed_to_prometheus().and(). the_100th_percentile_is_slow().and(). all_other_percentiles_are_fast() - } func TestSetupMetricsAreRecorded(t *testing.T) { diff --git a/internal/run/run_stage_test.go b/internal/run/run_stage_test.go index 7d10d33e..70f10854 100644 --- a/internal/run/run_stage_test.go +++ b/internal/run/run_stage_test.go @@ -10,32 +10,25 @@ import ( "testing" "time" - "github.com/form3tech-oss/f1/v2/internal/run" - "github.com/form3tech-oss/f1/v2/internal/trigger/ramp" - "github.com/form3tech-oss/f1/v2/pkg/f1" - "github.com/prometheus/common/expfmt" - - "github.com/form3tech-oss/f1/v2/internal/trigger/file" - + "github.com/giantswarm/retry-go" + "github.com/google/uuid" io_prometheus_client "github.com/prometheus/client_model/go" - - "github.com/form3tech-oss/f1/v2/internal/options" - "github.com/form3tech-oss/f1/v2/internal/trigger/users" + "github.com/prometheus/common/expfmt" + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/form3tech-oss/f1/v2/internal/fluentd_hook" - + "github.com/form3tech-oss/f1/v2/internal/options" + "github.com/form3tech-oss/f1/v2/internal/run" "github.com/form3tech-oss/f1/v2/internal/trigger/api" - "github.com/form3tech-oss/f1/v2/internal/trigger/constant" + "github.com/form3tech-oss/f1/v2/internal/trigger/file" + "github.com/form3tech-oss/f1/v2/internal/trigger/ramp" "github.com/form3tech-oss/f1/v2/internal/trigger/staged" - - log "github.com/sirupsen/logrus" - + "github.com/form3tech-oss/f1/v2/internal/trigger/users" + "github.com/form3tech-oss/f1/v2/pkg/f1" f1_testing "github.com/form3tech-oss/f1/v2/pkg/f1/testing" - "github.com/giantswarm/retry-go" - "github.com/google/uuid" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) type RunTestStage struct { diff --git a/internal/run/test_runner.go b/internal/run/test_runner.go index 829f4cc1..c2faf4e7 100644 --- a/internal/run/test_runner.go +++ b/internal/run/test_runner.go @@ -12,27 +12,25 @@ import ( "text/template" "time" - "github.com/form3tech-oss/f1/v2/internal/logging" - "github.com/form3tech-oss/f1/v2/internal/options" - "github.com/form3tech-oss/f1/v2/pkg/f1/scenarios" - "github.com/pkg/errors" - log "github.com/sirupsen/logrus" - - "github.com/form3tech-oss/f1/v2/internal/trace" - - "github.com/form3tech-oss/f1/v2/internal/raterun" - - "github.com/form3tech-oss/f1/v2/internal/trigger/api" - "github.com/aholic/ggtimer" + "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/push" + log "github.com/sirupsen/logrus" + "github.com/form3tech-oss/f1/v2/internal/logging" "github.com/form3tech-oss/f1/v2/internal/metrics" + "github.com/form3tech-oss/f1/v2/internal/options" + "github.com/form3tech-oss/f1/v2/internal/raterun" + "github.com/form3tech-oss/f1/v2/internal/trace" + "github.com/form3tech-oss/f1/v2/internal/trigger/api" + "github.com/form3tech-oss/f1/v2/pkg/f1/scenarios" ) -const NextIterationWindow = 10 * time.Millisecond -const IterationStage = "iteration" +const ( + NextIterationWindow = 10 * time.Millisecond + IterationStage = "iteration" +) func NewRun(options options.RunOptions, t *api.Trigger) (*Run, error) { run := Run{ @@ -281,6 +279,7 @@ func (r *Run) gatherMetrics() { } } } + func (r *Run) gatherProgressMetrics(duration time.Duration) { m, err := metrics.Instance().ProgressRegistry.Gather() if err != nil { @@ -335,7 +334,6 @@ func (r *Run) runWorker(input <-chan int32, stop <-chan struct{}, wg *sync.WaitG } trace.Event("Completed iteration (%v).", iteration) - } } } diff --git a/internal/trace/trace.go b/internal/trace/trace.go index f214ee0c..913f190e 100644 --- a/internal/trace/trace.go +++ b/internal/trace/trace.go @@ -8,11 +8,13 @@ import ( "time" ) -var reset = "\033[0m" -var gray = "\033[37m" -var yellow = "\033[33m" -var blue = "\033[34m" -var red = "\033[31m" +var ( + reset = "\033[0m" + gray = "\033[37m" + yellow = "\033[33m" + blue = "\033[34m" + red = "\033[31m" +) func colorString(s string, c string) string { return c + s + reset diff --git a/internal/trigger/api/api.go b/internal/trigger/api/api.go index b68600d6..a18bd129 100644 --- a/internal/trigger/api/api.go +++ b/internal/trigger/api/api.go @@ -3,13 +3,15 @@ package api import ( "time" - "github.com/form3tech-oss/f1/v2/internal/options" - "github.com/spf13/pflag" + + "github.com/form3tech-oss/f1/v2/internal/options" ) -type WorkTriggerer func(doWork chan<- bool, stop <-chan bool, workDone <-chan bool, options options.RunOptions) -type RateFunction func(time.Time) int +type ( + WorkTriggerer func(doWork chan<- bool, stop <-chan bool, workDone <-chan bool, options options.RunOptions) + RateFunction func(time.Time) int +) type Parameter struct { Name string diff --git a/internal/trigger/api/iteration_distribution_test.go b/internal/trigger/api/iteration_distribution_test.go index 86589653..3bf2e948 100644 --- a/internal/trigger/api/iteration_distribution_test.go +++ b/internal/trigger/api/iteration_distribution_test.go @@ -153,7 +153,7 @@ func TestRegularRateDistributionWithSmallIterationDuration(t *testing.T) { func TestRegularRateDistributionWithVariableRate(t *testing.T) { iterationDuration := 1 * time.Second rates := []int{5, 15, 12, 8} - var idx = -1 + idx := -1 rateFn := func(time time.Time) int { idx++; return rates[idx] } expectedDistributedRates := []int{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, @@ -224,7 +224,7 @@ func TestRandomRateDistribution(t *testing.T) { } { t.Run(fmt.Sprintf("%d: iteration duration %s, rate %d", i, test.iterationDuration, test.rate), func(t *testing.T) { rateFn := func(time time.Time) int { return test.rate } - var idx = -1 + idx := -1 randFn := func(limit int) int { idx++; return test.randomValues[idx] } distributedIterationDuration, distributedRate := withRandomDistribution(test.iterationDuration, rateFn, randFn) @@ -242,7 +242,7 @@ func TestRandomRateDistribution(t *testing.T) { func TestRandomRateDistributionWithVariableRate(t *testing.T) { iterationDuration := 1 * time.Second rates := []int{5, 15, 12, 8} - var idx = -1 + idx := -1 rateFn := func(time time.Time) int { idx++; return rates[idx] } randValues := []int{ 0, 1, 0, 1, 0, 1, 0, 1, 0, @@ -250,7 +250,7 @@ func TestRandomRateDistributionWithVariableRate(t *testing.T) { 1, 1, 1, 1, 2, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, } - var randIdx = -1 + randIdx := -1 randFn := func(limit int) int { randIdx++; return randValues[randIdx] } expectedDistributedRates := []int{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, diff --git a/internal/trigger/api/iteration_worker.go b/internal/trigger/api/iteration_worker.go index a49f6250..cc6361fe 100644 --- a/internal/trigger/api/iteration_worker.go +++ b/internal/trigger/api/iteration_worker.go @@ -3,9 +3,8 @@ package api import ( "time" - "github.com/form3tech-oss/f1/v2/internal/trace" - "github.com/form3tech-oss/f1/v2/internal/options" + "github.com/form3tech-oss/f1/v2/internal/trace" ) // NewIterationWorker produces a WorkTriggerer which triggers work at fixed intervals. diff --git a/internal/trigger/constant/constant_rate.go b/internal/trigger/constant/constant_rate.go index 63c17a39..96fb29b0 100644 --- a/internal/trigger/constant/constant_rate.go +++ b/internal/trigger/constant/constant_rate.go @@ -23,20 +23,20 @@ func ConstantRate() api.Builder { New: func(params *pflag.FlagSet) (*api.Trigger, error) { rateArg, err := params.GetString("rate") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } jitterArg, err := params.GetFloat64("jitter") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } distributionTypeArg, err := params.GetString("distribution") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } rates, err := CalculateConstantRate(jitterArg, rateArg, distributionTypeArg) if err != nil { - return nil, err + return nil, fmt.Errorf("calculating constant rate: %w", err) } return &api.Trigger{ @@ -58,7 +58,7 @@ func CalculateConstantRate(jitterArg float64, rateArg, distributionTypeArg strin rateFn := api.WithJitter(func(time.Time) int { return rate }, jitterArg) distributedIterationDuration, distributedRateFn, err := api.NewDistribution(distributionTypeArg, iterationDuration, rateFn) if err != nil { - return nil, err + return nil, fmt.Errorf("new distribution: %w", err) } return &api.Rates{ diff --git a/internal/trigger/file/file_parser.go b/internal/trigger/file/file_parser.go index 2c37c91f..a7ef6d10 100644 --- a/internal/trigger/file/file_parser.go +++ b/internal/trigger/file/file_parser.go @@ -4,11 +4,12 @@ import ( "fmt" "time" + "gopkg.in/yaml.v3" + "github.com/form3tech-oss/f1/v2/internal/trigger/constant" "github.com/form3tech-oss/f1/v2/internal/trigger/gaussian" "github.com/form3tech-oss/f1/v2/internal/trigger/ramp" "github.com/form3tech-oss/f1/v2/internal/trigger/staged" - "gopkg.in/yaml.v3" ) type ConfigFile struct { @@ -55,7 +56,7 @@ func parseConfigFile(fileContent []byte, now time.Time) (*runnableStages, error) configFile := ConfigFile{} err := yaml.Unmarshal(fileContent, &configFile) if err != nil { - return nil, err + return nil, fmt.Errorf("parsing config file as yaml: %w", err) } validatedConfigFile, err := configFile.validateCommonFields() if err != nil { @@ -98,11 +99,11 @@ func (s *Stage) parseStage(stageIdx int, defaults Stage) (*runnableStage, error) case "constant": validatedConstantStage, err := s.validateConstantStage(stageIdx, defaults) if err != nil { - return nil, err + return nil, fmt.Errorf("validating constant stage: %w", err) } rates, err := constant.CalculateConstantRate(*validatedConstantStage.Jitter, *validatedConstantStage.Rate, *validatedConstantStage.Distribution) if err != nil { - return nil, err + return nil, fmt.Errorf("calculating constant rate: %w", err) } return &runnableStage{ @@ -114,11 +115,11 @@ func (s *Stage) parseStage(stageIdx int, defaults Stage) (*runnableStage, error) case "ramp": validatedRampStage, err := s.validateRampStage(stageIdx, defaults) if err != nil { - return nil, err + return nil, fmt.Errorf("validating ramp stage: %w", err) } rates, err := ramp.CalculateRampRate(*validatedRampStage.StartRate, *validatedRampStage.EndRate, *validatedRampStage.Distribution, *validatedRampStage.Duration, *validatedRampStage.Jitter) if err != nil { - return nil, err + return nil, fmt.Errorf("calculating ramp rate: %w", err) } return &runnableStage{ @@ -130,11 +131,11 @@ func (s *Stage) parseStage(stageIdx int, defaults Stage) (*runnableStage, error) case "staged": validatedStagedStage, err := s.validateStagedStage(stageIdx, defaults) if err != nil { - return nil, err + return nil, fmt.Errorf("validating staged stage: %w", err) } rates, err := staged.CalculateStagedRate(*validatedStagedStage.Jitter, *validatedStagedStage.IterationFrequency, *validatedStagedStage.Stages, *validatedStagedStage.Distribution) if err != nil { - return nil, err + return nil, fmt.Errorf("calculating staged rate: %w", err) } return &runnableStage{ @@ -146,7 +147,7 @@ func (s *Stage) parseStage(stageIdx int, defaults Stage) (*runnableStage, error) case "gaussian": validatedGaussianStage, err := s.validateGaussianStage(stageIdx, defaults) if err != nil { - return nil, err + return nil, fmt.Errorf("validating gaussian stage: %w", err) } rates, err := gaussian.CalculateGaussianRate( *validatedGaussianStage.Volume, *validatedGaussianStage.Jitter, *validatedGaussianStage.Repeat, @@ -154,7 +155,7 @@ func (s *Stage) parseStage(stageIdx int, defaults Stage) (*runnableStage, error) *validatedGaussianStage.Weights, *validatedGaussianStage.Distribution, ) if err != nil { - return nil, err + return nil, fmt.Errorf("calculating gaussian rate: %w", err) } return &runnableStage{ @@ -199,11 +200,11 @@ func (c *ConfigFile) validateCommonFields() (*ConfigFile, error) { } if c.Limits.MaxFailures == nil { - var maxFailures = 0 + maxFailures := 0 c.Limits.MaxFailures = &maxFailures } if c.Limits.MaxFailuresRate == nil { - var maxFailuresRate = 0 + maxFailuresRate := 0 c.Limits.MaxFailuresRate = &maxFailuresRate } if c.Default.Concurrency == nil { diff --git a/internal/trigger/file/file_parser_test.go b/internal/trigger/file/file_parser_test.go index 76ed665c..a0b92ca0 100644 --- a/internal/trigger/file/file_parser_test.go +++ b/internal/trigger/file/file_parser_test.go @@ -385,7 +385,7 @@ stages: stagesToRun, err := parseConfigFile([]byte(test.fileContent), now) require.NoError(t, err) - require.Equal(t, 1, len(stagesToRun.stages)) + require.Len(t, stagesToRun.stages, 1) require.Equal(t, test.expectedScenario, stagesToRun.scenario) require.Equal(t, test.expectedMaxDuration, stagesToRun.maxDuration) require.Equal(t, test.expectedConcurrency, stagesToRun.concurrency) @@ -648,7 +648,7 @@ invalid file content runnableStages, err := parseConfigFile([]byte(test.fileContent), now) require.Nil(t, runnableStages) - require.EqualError(t, err, test.expectedError) + require.ErrorContains(t, err, test.expectedError) }) } } diff --git a/internal/trigger/file/file_rate.go b/internal/trigger/file/file_rate.go index 1b56bdef..83c8aa56 100644 --- a/internal/trigger/file/file_rate.go +++ b/internal/trigger/file/file_rate.go @@ -7,9 +7,10 @@ import ( "path/filepath" "time" - "github.com/form3tech-oss/f1/v2/internal/trigger/api" log "github.com/sirupsen/logrus" "github.com/spf13/pflag" + + "github.com/form3tech-oss/f1/v2/internal/trigger/api" ) type runnableStages struct { @@ -73,7 +74,7 @@ func FileRate() api.Builder { func readFile(filename string) (*[]byte, error) { file, err := os.Open(filepath.Clean(filename)) if err != nil { - return nil, err + return nil, fmt.Errorf("opening file: %w", err) } defer func() { if err = file.Close(); err != nil { @@ -83,7 +84,7 @@ func readFile(filename string) (*[]byte, error) { fileContent, err := io.ReadAll(file) if err != nil { - return nil, err + return nil, fmt.Errorf("reading file: %w", err) } return &fileContent, nil diff --git a/internal/trigger/file/stages_worker.go b/internal/trigger/file/stages_worker.go index 122fb22e..83622a43 100644 --- a/internal/trigger/file/stages_worker.go +++ b/internal/trigger/file/stages_worker.go @@ -5,11 +5,11 @@ import ( "sync" "time" - "github.com/form3tech-oss/f1/v2/internal/trigger/users" + log "github.com/sirupsen/logrus" "github.com/form3tech-oss/f1/v2/internal/options" "github.com/form3tech-oss/f1/v2/internal/trigger/api" - log "github.com/sirupsen/logrus" + "github.com/form3tech-oss/f1/v2/internal/trigger/users" ) func newStagesWorker(stages []runnableStage) api.WorkTriggerer { diff --git a/internal/trigger/gaussian/gaussian_rate.go b/internal/trigger/gaussian/gaussian_rate.go index 515111a9..44bd3b73 100644 --- a/internal/trigger/gaussian/gaussian_rate.go +++ b/internal/trigger/gaussian/gaussian_rate.go @@ -36,39 +36,39 @@ func GaussianRate() api.Builder { New: func(flags *pflag.FlagSet) (*api.Trigger, error) { volume, err := flags.GetFloat64("volume") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } repeat, err := flags.GetDuration("repeat") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } frequency, err := flags.GetDuration("iteration-frequency") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } weights, err := flags.GetString("weights") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } peak, err := flags.GetDuration("peak") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } stddev, err := flags.GetDuration("standard-deviation") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } jitter, err := flags.GetFloat64("jitter") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } distributionTypeArg, err := flags.GetString("distribution") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } peakRate, err := flags.GetString("peak-rate") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } jitterDesc := "" if jitter != 0 { @@ -136,7 +136,7 @@ func CalculateGaussianRate(volume, jitter float64, repeat, frequency, peak, stdd rateFn := api.WithJitter(calculator.For, jitter) distributedIterationDuration, distributedRateFn, err := api.NewDistribution(distributionTypeArg, frequency, rateFn) if err != nil { - return nil, err + return nil, fmt.Errorf("new distribution: %w", err) } return &api.Rates{ diff --git a/internal/trigger/gaussian/gaussian_rate_test.go b/internal/trigger/gaussian/gaussian_rate_test.go index f98a75b4..7701dc57 100644 --- a/internal/trigger/gaussian/gaussian_rate_test.go +++ b/internal/trigger/gaussian/gaussian_rate_test.go @@ -6,10 +6,11 @@ import ( "testing" "time" - "github.com/form3tech-oss/f1/v2/internal/trigger/api" "github.com/guptarohit/asciigraph" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/form3tech-oss/f1/v2/internal/trigger/api" ) func TestTotalVolumes(t *testing.T) { @@ -177,7 +178,7 @@ func TestTotalVolumes(t *testing.T) { diff := math.Abs(total - test.volume) fmt.Printf("Configured for volume %f, triggered %f. Difference of %f (%f%%)\n", test.volume, total, diff, 100*diff/test.volume) acceptableErrorPercent := 0.1 - assert.True(t, diff < test.volume*acceptableErrorPercent/100, "volumes differ by > %f%%", acceptableErrorPercent*100) + assert.Less(t, diff, test.volume*acceptableErrorPercent/100, "volumes differ by > %f%%", acceptableErrorPercent*100) }) } } diff --git a/internal/trigger/ramp/ramp_rate.go b/internal/trigger/ramp/ramp_rate.go index f6653aab..e6d4a31f 100644 --- a/internal/trigger/ramp/ramp_rate.go +++ b/internal/trigger/ramp/ramp_rate.go @@ -25,34 +25,34 @@ func RampRate() api.Builder { New: func(flags *pflag.FlagSet) (*api.Trigger, error) { startRateArg, err := flags.GetString("start-rate") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } endRateArg, err := flags.GetString("end-rate") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } duration, err := flags.GetDuration("ramp-duration") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } if duration == 0 { duration, err = flags.GetDuration("max-duration") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } } jitterArg, err := flags.GetFloat64("jitter") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } distributionTypeArg, err := flags.GetString("distribution") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } rates, err := CalculateRampRate(startRateArg, endRateArg, distributionTypeArg, duration, jitterArg) if err != nil { - return nil, err + return nil, fmt.Errorf("calculating ramp rate: %w", err) } return &api.Trigger{ @@ -69,11 +69,11 @@ func CalculateRampRate(startRateArg, endRateArg, distributionTypeArg string, dur startRate, startUnit, err := rate.ParseRate(startRateArg) if err != nil { - return nil, err + return nil, fmt.Errorf("parsing start rate: %w", err) } endRate, endUnit, err := rate.ParseRate(endRateArg) if err != nil { - return nil, err + return nil, fmt.Errorf("parsing end rate: %w", err) } if startRate == endRate { @@ -105,7 +105,7 @@ func CalculateRampRate(startRateArg, endRateArg, distributionTypeArg string, dur jitterRateFn := api.WithJitter(rateFn, jitterArg) distributedIterationDuration, distributedRateFn, err := api.NewDistribution(distributionTypeArg, startUnit, jitterRateFn) if err != nil { - return nil, err + return nil, fmt.Errorf("new distribution: %w", err) } return &api.Rates{ diff --git a/internal/trigger/rate/rate.go b/internal/trigger/rate/rate.go index 1c278c48..15844ec6 100644 --- a/internal/trigger/rate/rate.go +++ b/internal/trigger/rate/rate.go @@ -12,8 +12,9 @@ import ( func ParseRate(rateArg string) (int, time.Duration, error) { var rate int var unit time.Duration - var err error + if strings.Contains(rateArg, "/") { + var err error rate, err = strconv.Atoi((rateArg)[0:strings.Index(rateArg, "/")]) if err != nil { return rate, unit, fmt.Errorf("unable to parse rate %s: %w", rateArg, err) @@ -30,6 +31,7 @@ func ParseRate(rateArg string) (int, time.Duration, error) { return rate, unit, fmt.Errorf("unable to parse unit %s: %w", rateArg, err) } } else { + var err error rate, err = strconv.Atoi(rateArg) if err != nil { return rate, unit, fmt.Errorf("unable to parse rate %s: %w", rateArg, err) @@ -39,5 +41,6 @@ func ParseRate(rateArg string) (int, time.Duration, error) { } unit = 1 * time.Second } - return rate, unit, err + + return rate, unit, nil } diff --git a/internal/trigger/staged/stage.go b/internal/trigger/staged/stage.go index f8f6a3f2..1aec42d2 100644 --- a/internal/trigger/staged/stage.go +++ b/internal/trigger/staged/stage.go @@ -14,13 +14,11 @@ type stage struct { } func parseStages(value string) ([]stage, error) { - var stages []stage stageElements := strings.Split(value, ",") for i, stageElements := range stageElements { - stageElement := strings.Split(strings.TrimSpace(stageElements), ":") if len(stageElement) != 2 { return nil, fmt.Errorf("unable to parse stage %d: `%s` from `%s`", i, stageElements, value) diff --git a/internal/trigger/staged/stage_test.go b/internal/trigger/staged/stage_test.go index 44c64382..0ce36702 100644 --- a/internal/trigger/staged/stage_test.go +++ b/internal/trigger/staged/stage_test.go @@ -5,10 +5,10 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestParseStages_With_Valid_String(t *testing.T) { - value := "0s:1,10s:1,20s:20,1m:50,1h:200" expected := []stage{ { @@ -39,27 +39,27 @@ func TestParseStages_With_Valid_String(t *testing.T) { } actual, err := parseStages(value) - assert.NoError(t, err) + require.NoError(t, err) assert.ElementsMatch(t, actual, expected) } func TestParseStages_Error_Too_Many_Elements(t *testing.T) { value := "0s:1:2" stages, err := parseStages(value) - assert.NotNil(t, err) + require.Error(t, err) assert.Nil(t, stages) } func TestParseStages_Error_Bad_Duration(t *testing.T) { value := "0BB:1" stages, err := parseStages(value) - assert.NotNil(t, err) + require.Error(t, err) assert.Nil(t, stages) } func TestParseStages_Error_Bad_Target(t *testing.T) { value := "1s:BB" stages, err := parseStages(value) - assert.NotNil(t, err) + require.Error(t, err) assert.Nil(t, stages) } diff --git a/internal/trigger/staged/staged_rate.go b/internal/trigger/staged/staged_rate.go index 5edbd3fa..a465462f 100644 --- a/internal/trigger/staged/staged_rate.go +++ b/internal/trigger/staged/staged_rate.go @@ -4,9 +4,9 @@ import ( "fmt" "time" - "github.com/form3tech-oss/f1/v2/internal/trigger/api" - "github.com/spf13/pflag" + + "github.com/form3tech-oss/f1/v2/internal/trigger/api" ) func StagedRate() api.Builder { @@ -21,22 +21,21 @@ func StagedRate() api.Builder { Description: "triggers iterations at varying rates", Flags: flags, New: func(params *pflag.FlagSet) (*api.Trigger, error) { - jitterArg, err := params.GetFloat64("jitter") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } stg, err := params.GetString("stages") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } frequency, err := params.GetDuration("iterationFrequency") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } distributionTypeArg, err := params.GetString("distribution") if err != nil { - return nil, err + return nil, fmt.Errorf("getting flag: %w", err) } rates, err := CalculateStagedRate(jitterArg, frequency, stg, distributionTypeArg) @@ -58,14 +57,14 @@ func StagedRate() api.Builder { func CalculateStagedRate(jitterArg float64, frequency time.Duration, stg, distributionTypeArg string) (*api.Rates, error) { stages, err := parseStages(stg) if err != nil { - return nil, err + return nil, fmt.Errorf("parsing stages: %w", err) } calculator := newRateCalculator(stages) rateFn := api.WithJitter(calculator.Rate, jitterArg) distributedIterationDuration, distributedRateFn, err := api.NewDistribution(distributionTypeArg, frequency, rateFn) if err != nil { - return nil, err + return nil, fmt.Errorf("new distribution: %w", err) } return &api.Rates{ diff --git a/internal/trigger/users/users_rate.go b/internal/trigger/users/users_rate.go index 87b56801..b66b63c0 100644 --- a/internal/trigger/users/users_rate.go +++ b/internal/trigger/users/users_rate.go @@ -3,9 +3,10 @@ package users import ( "time" + "github.com/spf13/pflag" + "github.com/form3tech-oss/f1/v2/internal/options" "github.com/form3tech-oss/f1/v2/internal/trigger/api" - "github.com/spf13/pflag" ) func UsersRate() api.Builder { diff --git a/pkg/f1/completions.go b/pkg/f1/completions.go index 71c87f36..459fcb66 100644 --- a/pkg/f1/completions.go +++ b/pkg/f1/completions.go @@ -3,10 +3,10 @@ package f1 import ( "os" + "github.com/spf13/cobra" + "github.com/form3tech-oss/f1/v2/internal/support/errorh" "github.com/form3tech-oss/f1/v2/pkg/f1/scenarios" - - "github.com/spf13/cobra" ) func completionsCmd(s *scenarios.Scenarios, p *profiling) *cobra.Command { @@ -38,6 +38,7 @@ To configure your bash shell to load completions for each session add to your ba }, } } + func zshCmd(s *scenarios.Scenarios, p *profiling) *cobra.Command { return &cobra.Command{ Use: "zsh", diff --git a/pkg/f1/doc.go b/pkg/f1/doc.go index 0e722868..896bf3bd 100644 --- a/pkg/f1/doc.go +++ b/pkg/f1/doc.go @@ -7,9 +7,7 @@ However, it can also be used to write more complex scenarios which might trigger action and then await asynchronous feedback (e.g. making an HTTP request, and then waiting for a message to arrive via a message broker). - -Writing load tests - +# Writing load tests Test scenarios consist of two stages: @@ -67,9 +65,7 @@ Writing tests is simply a case of implementing the types and registering them wi return runFn } - -Running load tests - +# Running load tests Once you have written a load test and compiled a binary test runner, you can use the various "trigger modes" (See here for more details: https://github.com/form3tech-oss/f1/tree/master/internal/trigger) that F1 supports. These are available as subcommands to the "f1 run" command, so trying "f1 run --help" will provide more information. The trigger modes currently implemented are as follows: @@ -94,6 +90,5 @@ You can of course also compile an "F1" binary, as follows: go build -o f1 main.go ./f1 --help ./f1 run constant -r 1/s -d 10s mySuperFastLoadTest - */ package f1 diff --git a/pkg/f1/f1_scenarios.go b/pkg/f1/f1_scenarios.go index fbddb37f..f0eca075 100644 --- a/pkg/f1/f1_scenarios.go +++ b/pkg/f1/f1_scenarios.go @@ -30,9 +30,12 @@ func New() *F1 { // Registers a new test scenario with the given name. This is the name used when running // load test scenarios. For example, calling the function with the following arguments: -// f.Add("myTest", myScenario) +// +// f.Add("myTest", myScenario) +// // will result in the test "myTest" being runnable from the command line: -// f1 run constant -r 1/s -d 10s myTest +// +// f1 run constant -r 1/s -d 10s myTest func (f *F1) Add(name string, scenarioFn testing.ScenarioFn, options ...scenarios.ScenarioOption) *F1 { info := &scenarios.Scenario{ Name: name, @@ -47,7 +50,7 @@ func (f *F1) Add(name string, scenarioFn testing.ScenarioFn, options ...scenario return f } -// Syncronously runs the F1 CLI. This function is the blocking entrypoint to the CLI, +// Synchronously runs the F1 CLI. This function is the blocking entrypoint to the CLI, // so you should register your test scenarios with the Add function prior to calling this // function. func (f *F1) Execute() { diff --git a/pkg/f1/f1_scenarios_stage_test.go b/pkg/f1/f1_scenarios_stage_test.go index 5d063ac8..6fe90ecf 100644 --- a/pkg/f1/f1_scenarios_stage_test.go +++ b/pkg/f1/f1_scenarios_stage_test.go @@ -4,10 +4,11 @@ import ( "sync/atomic" "testing" - "github.com/form3tech-oss/f1/v2/pkg/f1" - f1_testing "github.com/form3tech-oss/f1/v2/pkg/f1/testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/form3tech-oss/f1/v2/pkg/f1" + f1_testing "github.com/form3tech-oss/f1/v2/pkg/f1/testing" ) type f1ScenariosStage struct { diff --git a/pkg/f1/root_cmd.go b/pkg/f1/root_cmd.go index b4fbcb4c..6b247027 100644 --- a/pkg/f1/root_cmd.go +++ b/pkg/f1/root_cmd.go @@ -6,18 +6,15 @@ import ( "runtime" "runtime/pprof" - "github.com/form3tech-oss/f1/v2/internal/support/errorh" - - "github.com/form3tech-oss/f1/v2/internal/fluentd_hook" - - "github.com/form3tech-oss/f1/v2/pkg/f1/scenarios" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" "github.com/form3tech-oss/f1/v2/internal/chart" + "github.com/form3tech-oss/f1/v2/internal/fluentd_hook" "github.com/form3tech-oss/f1/v2/internal/run" + "github.com/form3tech-oss/f1/v2/internal/support/errorh" "github.com/form3tech-oss/f1/v2/internal/trigger" - - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" + "github.com/form3tech-oss/f1/v2/pkg/f1/scenarios" ) func buildRootCmd(s *scenarios.Scenarios, p *profiling) *cobra.Command { diff --git a/pkg/f1/testing/doc.go b/pkg/f1/testing/doc.go index ea6ee1f6..d3fd6b69 100644 --- a/pkg/f1/testing/doc.go +++ b/pkg/f1/testing/doc.go @@ -1,4 +1,4 @@ /* -F1's testing package is analagous to Go's built-in testing package. It provides a "t" type which ise injected into setup and iteration run functions, which also provides some common testing functionality such as the ability to perform assertions. +F1's testing package is analogous to Go's built-in testing package. It provides a "t" type which ise injected into setup and iteration run functions, which also provides some common testing functionality such as the ability to perform assertions. */ package testing diff --git a/pkg/f1/testing/t.go b/pkg/f1/testing/t.go index 21b3154c..cb630018 100644 --- a/pkg/f1/testing/t.go +++ b/pkg/f1/testing/t.go @@ -7,10 +7,9 @@ import ( "time" log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" "github.com/form3tech-oss/f1/v2/internal/metrics" - - "github.com/stretchr/testify/require" ) // T is a type passed to Scenario functions to manage test state and support formatted test logs. diff --git a/pkg/f1/testing/t_test.go b/pkg/f1/testing/t_test.go index cec39913..8b66d126 100644 --- a/pkg/f1/testing/t_test.go +++ b/pkg/f1/testing/t_test.go @@ -7,8 +7,9 @@ import ( "regexp" go_testing "testing" - "github.com/form3tech-oss/f1/v2/pkg/f1/testing" "github.com/stretchr/testify/require" + + "github.com/form3tech-oss/f1/v2/pkg/f1/testing" ) func TestNewTIsNotFailed(t *go_testing.T) { diff --git a/scripts/goimportscheck.sh b/scripts/goimportscheck.sh deleted file mode 100755 index f33b0158..00000000 --- a/scripts/goimportscheck.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -# Check goimports -echo "==> Checking that code complies with goimports requirements..." -goimports_files=$("$GOPATH"/bin/goimports -l `find . -name '*.go' | grep -v vendor`) -if [[ -n ${goimports_files} ]]; then - echo 'goimports needs running on the following files:' - echo "${goimports_files}" - echo "You can use the command: \`make goimports\` to reformat code." - exit 1 -fi - -exit 0 diff --git a/scripts/install-golangci-lint.sh b/scripts/install-golangci-lint.sh new file mode 100755 index 00000000..9f0b5ec0 --- /dev/null +++ b/scripts/install-golangci-lint.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +set -euo pipefail + +version="$1" +readonly version + +os=$(uname -s | tr '[:upper:]' '[:lower:]') +readonly os + +arch=$(go env GOARCH) # note that uname -m gives unexpected results in an f3 shell + +asset="golangci-lint-$version-$os-$arch" +readonly asset + +url="https://github.com/golangci/golangci-lint/releases/download/v${version}/$asset.tar.gz" +readonly url + +tarball="$(mktemp)" +readonly tarball + +if [[ -x tools/golangci-lint && $(tools/golangci-lint version) == *"$version"* ]]; then + echo "$version already installed" + exit 0 +fi + +mkdir -p tools/ +curl -sSfL "$url" -o "$tarball" +tar xf "$tarball" -C tools --strip-components 1 "$asset/golangci-lint" +rm -rf "$tarball" +tools/golangci-lint version