Skip to content

Commit 7cb1b4e

Browse files
committed
feat!: NewRun accepts ...RunOption directly
Replace options.Apply(...) with NewRun(scenarios, trigger, ..., opts ...RunOption). Matches f1.New pattern and removes the extra Apply indirection. BREAKING CHANGE: NewRun signature changed from (options.RunOptions, scenarios, trigger, ...) to (scenarios, trigger, ..., opts ...RunOption). Remove options.Apply() from call sites.
1 parent 70dbc72 commit 7cb1b4e

7 files changed

Lines changed: 108 additions & 51 deletions

File tree

internal/options/run_options.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,52 @@ type RunOptions struct {
1616
WaitForCompletionTimeout time.Duration
1717
}
1818

19+
type RunOption func(*RunOptions)
20+
21+
func WithScenario(s string) RunOption {
22+
return func(o *RunOptions) { o.Scenario = s }
23+
}
24+
25+
func WithMaxDuration(d time.Duration) RunOption {
26+
return func(o *RunOptions) { o.MaxDuration = d }
27+
}
28+
29+
func WithConcurrency(n int) RunOption {
30+
return func(o *RunOptions) { o.Concurrency = n }
31+
}
32+
33+
func WithMaxIterations(n uint64) RunOption {
34+
return func(o *RunOptions) { o.MaxIterations = n }
35+
}
36+
37+
func WithMaxFailures(n uint64) RunOption {
38+
return func(o *RunOptions) { o.MaxFailures = n }
39+
}
40+
41+
func WithMaxFailuresRate(n int) RunOption {
42+
return func(o *RunOptions) { o.MaxFailuresRate = n }
43+
}
44+
45+
func WithVerbose(v bool) RunOption {
46+
return func(o *RunOptions) { o.Verbose = v }
47+
}
48+
49+
func WithIgnoreDropped(v bool) RunOption {
50+
return func(o *RunOptions) { o.IgnoreDropped = v }
51+
}
52+
53+
func WithWaitForCompletionTimeout(d time.Duration) RunOption {
54+
return func(o *RunOptions) { o.WaitForCompletionTimeout = d }
55+
}
56+
57+
func DefaultRunOptions() RunOptions {
58+
return RunOptions{
59+
MaxDuration: time.Second,
60+
Concurrency: 100,
61+
WaitForCompletionTimeout: 10 * time.Second,
62+
}
63+
}
64+
1965
func (o *RunOptions) LogToFile() bool {
2066
return !o.Verbose
2167
}

internal/run/run_cmd.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -186,17 +186,17 @@ func runCmdExecute(
186186
return fmt.Errorf("getting flag: %w", err)
187187
}
188188

189-
run, err := NewRun(options.RunOptions{
190-
Scenario: scenarioName,
191-
MaxDuration: duration,
192-
Concurrency: concurrency,
193-
Verbose: verbose,
194-
MaxIterations: maxIterations,
195-
MaxFailures: maxFailures,
196-
MaxFailuresRate: maxFailuresRate,
197-
IgnoreDropped: ignoreDropped,
198-
WaitForCompletionTimeout: waitForCompletionTimeout,
199-
}, s, trig, settings, metricsInstance, output)
189+
run, err := NewRun(s, trig, settings, metricsInstance, output,
190+
options.WithScenario(scenarioName),
191+
options.WithMaxDuration(duration),
192+
options.WithConcurrency(concurrency),
193+
options.WithVerbose(verbose),
194+
options.WithMaxIterations(maxIterations),
195+
options.WithMaxFailures(maxFailures),
196+
options.WithMaxFailuresRate(maxFailuresRate),
197+
options.WithIgnoreDropped(ignoreDropped),
198+
options.WithWaitForCompletionTimeout(waitForCompletionTimeout),
199+
)
200200
if err != nil {
201201
return fmt.Errorf("new run: %w", err)
202202
}

internal/run/run_stage_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -197,16 +197,16 @@ func (s *RunTestStage) setupRun() {
197197
logger := log.NewLogger(&s.stdout, logutils.NewLogConfigFromSettings(s.settings))
198198
outputer := ui.NewOutput(logger, printer, s.interactive, false)
199199

200-
r, err := run.NewRun(options.RunOptions{
201-
Scenario: s.scenario,
202-
MaxDuration: s.duration,
203-
Concurrency: s.concurrency,
204-
MaxIterations: s.maxIterations,
205-
MaxFailures: s.maxFailures,
206-
MaxFailuresRate: s.maxFailuresRate,
207-
Verbose: s.verbose,
208-
WaitForCompletionTimeout: s.waitForCompletionTimeout,
209-
}, s.f1.GetScenarios(), s.build_trigger(), s.settings, s.metrics, outputer)
200+
r, err := run.NewRun(s.f1.GetScenarios(), s.build_trigger(), s.settings, s.metrics, outputer,
201+
options.WithScenario(s.scenario),
202+
options.WithMaxDuration(s.duration),
203+
options.WithConcurrency(s.concurrency),
204+
options.WithMaxIterations(s.maxIterations),
205+
options.WithMaxFailures(s.maxFailures),
206+
options.WithMaxFailuresRate(s.maxFailuresRate),
207+
options.WithVerbose(s.verbose),
208+
options.WithWaitForCompletionTimeout(s.waitForCompletionTimeout),
209+
)
210210

211211
s.require.NoError(err)
212212
s.runInstance = r

internal/run/test_runner.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,36 +43,41 @@ type Run struct {
4343
}
4444

4545
func NewRun(
46-
options options.RunOptions,
4746
scenarios *scenarios.Scenarios,
4847
trigger *api.Trigger,
4948
settings envsettings.Settings,
5049
metricsInstance *metrics.Metrics,
5150
parentOutput *ui.Output,
51+
opts ...options.RunOption,
5252
) (*Run, error) {
53+
runOptions := options.DefaultRunOptions()
54+
for _, opt := range opts {
55+
opt(&runOptions)
56+
}
57+
5358
progressStats := &progress.Stats{}
5459
viewsInstance := views.New()
5560

56-
scenario := scenarios.GetScenario(options.Scenario)
61+
scenario := scenarios.GetScenario(runOptions.Scenario)
5762
if scenario == nil {
58-
return nil, fmt.Errorf("scenario not defined: %s", options.Scenario)
63+
return nil, fmt.Errorf("scenario not defined: %s", runOptions.Scenario)
5964
}
6065

61-
result := NewResult(options, viewsInstance, progressStats)
66+
result := NewResult(runOptions, viewsInstance, progressStats)
6267

6368
outputer := ui.NewOutput(
6469
parentOutput.Logger.With(log.ScenarioAttr(scenario.Name)),
6570
parentOutput.Printer,
6671
parentOutput.Interactive,
67-
options.LogToFile(),
72+
runOptions.LogToFile(),
6873
)
6974

7075
scenarioLogger := NewScenarioLogger(outputer)
7176
result.LogFilePath = scenarioLogger.Open(
7277
LogFilePathOrDefault(settings.Log.FilePath, scenario.Name),
7378
logutils.NewLogConfigFromSettings(settings),
7479
scenario.Name,
75-
options.LogToFile(),
80+
runOptions.LogToFile(),
7681
)
7782

7883
progressRunner, err := newProgressRunner(result, outputer)
@@ -90,7 +95,7 @@ func NewRun(
9095
pusher := newMetricsPusher(settings, scenario.Name, metricsInstance)
9196

9297
return &Run{
93-
options: options,
98+
options: runOptions,
9499
trigger: trigger,
95100
metrics: metricsInstance,
96101
views: viewsInstance,

pkg/f1/f1.go

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,34 +38,40 @@ type f1Options struct {
3838
staticMetrics map[string]string
3939
}
4040

41-
// New instantiates a new instance of an F1 CLI.
42-
func New() *F1 {
41+
// Option configures an F1 instance at construction.
42+
type Option func(*F1)
43+
44+
// WithLogger specifies the logger for internal and scenario logs.
45+
// This disables F1_LOG_LEVEL and F1_LOG_FORMAT.
46+
func WithLogger(logger *slog.Logger) Option {
47+
return func(f *F1) {
48+
f.options.output = ui.NewDefaultOutputWithLogger(logger)
49+
}
50+
}
51+
52+
// WithStaticMetrics registers additional labels with fixed values for f1 metrics.
53+
func WithStaticMetrics(labels map[string]string) Option {
54+
return func(f *F1) {
55+
f.options.staticMetrics = labels
56+
}
57+
}
58+
59+
// New instantiates a new F1 CLI. Pass options to configure logger, metrics, etc.
60+
func New(opts ...Option) *F1 {
4361
settings := envsettings.Get()
4462

45-
return &F1{
63+
f := &F1{
4664
scenarios: scenarios.New(),
4765
profiling: &profiling{},
4866
settings: settings,
4967
options: &f1Options{
50-
output: ui.NewDefaultOutput(settings.Log.SlogLevel(), settings.Log.IsFormatJSON()),
68+
output: ui.NewDefaultOutput(settings.Log.SlogLevel(), settings.Log.IsFormatJSON()),
69+
staticMetrics: nil,
5170
},
5271
}
53-
}
54-
55-
// WithLogger allows specifying logger to be used for all internal and scenario logs
56-
//
57-
// This will disable the F1_LOG_LEVEL and F1_LOG_FORMAT options, as they only relate to the built-in
58-
// logger.
59-
//
60-
// The logger will be used for non-interactive output, file logs or when `--verbose` is specified.
61-
func (f *F1) WithLogger(logger *slog.Logger) *F1 {
62-
f.options.output = ui.NewDefaultOutputWithLogger(logger)
63-
return f
64-
}
65-
66-
// WithStaticMetrics registers additional labels with fixed values to the f1 metrics
67-
func (f *F1) WithStaticMetrics(labels map[string]string) *F1 {
68-
f.options.staticMetrics = labels
72+
for _, opt := range opts {
73+
opt(f)
74+
}
6975
return f
7076
}
7177

pkg/f1/f1_stage_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func (s *f1Stage) and() *f1Stage {
5252

5353
func (s *f1Stage) a_custom_logger_is_configured_with_attr(key, value string) *f1Stage {
5454
logger := log.NewTestLogger(&s.logOutput).With(key, value)
55-
s.f1 = f1.New().WithLogger(logger)
55+
s.f1 = f1.New(f1.WithLogger(logger))
5656

5757
return s
5858
}

pkg/f1/scenarios/scenario_builder.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ type ScenarioParameter struct {
3030

3131
type ScenarioOption func(info *Scenario)
3232

33-
func Description(d string) ScenarioOption {
33+
func WithDescription(d string) ScenarioOption {
3434
return func(i *Scenario) {
3535
i.Description = d
3636
}
3737
}
3838

39-
func Parameter(parameter ScenarioParameter) ScenarioOption {
39+
func WithParameter(parameter ScenarioParameter) ScenarioOption {
4040
return func(i *Scenario) {
4141
i.Parameters = append(i.Parameters, parameter)
4242
}

0 commit comments

Comments
 (0)