@@ -18,8 +18,9 @@ This guide documents all breaking changes in F1 v3 and how to migrate your code.
181810 . [ Metrics Package Removal] ( #10-metrics-package-removal )
191911 . [ CLI and Flag Changes] ( #11-cli-and-flag-changes )
202012 . [ Removed Features] ( #12-removed-features )
21- 13 . [ Complete Before/After Example] ( #13-complete-beforeafter-example )
22- 14 . [ Migration Checklist] ( #14-migration-checklist )
21+ 13 . [ Configuration Changes] ( #13-configuration-changes )
22+ 14 . [ Complete Before/After Example] ( #14-complete-beforeafter-example )
23+ 15 . [ Migration Checklist] ( #15-migration-checklist )
2324
2425---
2526
@@ -36,8 +37,10 @@ This guide documents all breaking changes in F1 v3 and how to migrate your code.
3637| Scenario/Run signatures | ` func(t *T) ` | ` func(ctx context.Context, t *T) ` |
3738| T.Error / T.Fatal | ` Error(err error) ` , ` Fatal(err error) ` | ` Error(args ...any) ` , ` Fatal(args ...any) ` |
3839| T.Logger | ` *logrus.Logger ` | ` *slog.Logger ` |
39- | T.Iteration | ` string ` | ` uint64 ` (IterationSetup=0 for setup) |
40+ | T.Iteration | ` string ` | ` uint64 ` (` IterationSetup=0 ` for setup) |
41+ | T.VUID | not available | ` int ` (Virtual User ID: -1 for setup, 0-based for workers) |
4042| Metrics | ` metrics.GetMetrics() ` | Removed; use ` WithStaticMetrics ` |
43+ | Logging | logrus | ` log/slog ` |
4144
4245---
4346
@@ -57,13 +60,6 @@ Update your dependency:
5760go get github.com/form3tech-oss/f1/v3@latest
5861```
5962
60- Or in ` go.mod ` :
61-
62- ``` diff
63- - github.com/form3tech-oss/f1/v2 v2.x.x
64- + github.com/form3tech-oss/f1/v3 v3.x.x
65- ```
66-
6763---
6864
6965## 3. Import Path Changes
@@ -148,6 +144,16 @@ f.Run(context.Background(), nil) // equivalent to Execute() but returns error
148144+ )
149145```
150146
147+ ** New in v3** : Additional constructor options for programmatic configuration:
148+
149+ ``` go
150+ f1.New (
151+ f1.WithLogLevel (slog.LevelDebug ),
152+ f1.WithLogFormat (f1.LogFormatJSON ),
153+ f1.WithPrometheusPushGateway (" http://pushgateway:9091" ),
154+ )
155+ ```
156+
151157---
152158
153159## 6. Scenario Registration
@@ -194,6 +200,12 @@ f.Run(context.Background(), nil) // equivalent to Execute() but returns error
194200| ----| -----|
195201| ` func(t *T) RunFn ` | ` func(ctx context.Context, t *T) RunFn ` |
196202
203+ ### RunFn
204+
205+ | v2 | v3 |
206+ | ----| -----|
207+ | ` func(t *T) ` | ` func(ctx context.Context, t *T) ` |
208+
197209``` diff
198210// v2
199211- func myScenario(t *f1testing.T) f1testing.RunFn {
@@ -204,12 +216,6 @@ f.Run(context.Background(), nil) // equivalent to Execute() but returns error
204216 }
205217```
206218
207- ### RunFn
208-
209- | v2 | v3 |
210- | ----| -----|
211- | ` func(t *T) ` | ` func(ctx context.Context, t *T) ` |
212-
213219** Using context** for cancellation or timeouts:
214220
215221``` go
@@ -250,7 +256,7 @@ Type references:
250256
251257### 9.1 Error and Fatal Signatures
252258
253- ** Change** : ` Error ` and ` Fatal ` now accept ` args ...any ` (matching ` testing.T ` ), instead of ` err error ` . This enables sharing test helpers between ` go test ` and f1 scenarios.
259+ ** Change** : ` Error ` and ` Fatal ` now accept ` args ...any ` (matching ` testing.T ` ), instead of ` err error ` .
254260
255261| v2 | v3 |
256262| ----| -----|
@@ -287,22 +293,21 @@ t.Fatalf("iteration %d failed: %v", t.Iteration, err)
287293
288294### 9.4 T.Time() Removed
289295
290- ** Change** : ` T.Time(stageName string, f func()) ` is removed. Internal metrics are no longer exposed via the testing package. If you need timing, record it yourself:
296+ ** Change** : ` T.Time(stageName string, f func()) ` is removed. Internal metrics are no longer exposed via the testing package.
291297
292- ``` go
298+ ``` diff
293299// v2
294300- t.Time("http_request", func() { doRequest() })
295301
296302// v3 — record timing yourself if needed
297303+ start := time.Now()
298304+ doRequest()
299305+ duration := time.Since(start)
300- + // use duration as needed (e.g. custom metrics, logging)
301306```
302307
303308### 9.5 NewT() Removed
304309
305- ** Change** : ` NewT(iter, scenarioName string) ` is removed. Use ` NewTWithOptions ` only. The framework creates ` T ` instances internally; you typically only need ` NewTWithOptions ` for tests.
310+ ** Change** : ` NewT(iter, scenarioName string) ` is removed. Use ` NewTWithOptions ` only.
306311
307312``` diff
308313// v2
@@ -319,16 +324,14 @@ t.Fatalf("iteration %d failed: %v", t.Iteration, err)
319324``` diff
320325// v2
321326- t.Logf("Iteration: %s", t.Iteration)
322- - t.Logger().With("iteration", t.Iteration).Info("msg")
323327
324328// v3
325329+ t.Logf("Iteration: %d", t.Iteration)
326- + t.Logger().With("iteration", t.Iteration).Info("msg")
327330```
328331
329332### 9.7 WithLogrusLogger Removed
330333
331- ** Change** : ` WithLogrusLogger(logrusLogger *logrus.Logger) ` is removed. Use ` WithLogger(*slog.Logger) ` when constructing ` T ` via ` NewTWithOptions ` .
334+ ** Change** : ` WithLogrusLogger(logrusLogger *logrus.Logger) ` is removed. Use ` WithLogger(*slog.Logger) ` .
332335
333336``` diff
334337// v2
@@ -342,6 +345,20 @@ t.Fatalf("iteration %d failed: %v", t.Iteration, err)
342345+ )
343346```
344347
348+ ### 9.8 T.VUID (New in v3)
349+
350+ ** New** : ` T.VUID ` is a ` int ` field representing the Virtual User ID. It's -1 during setup and 0-based for pool workers. Useful for per-user state in ` users ` trigger mode.
351+
352+ ``` go
353+ func myScenario (ctx context .Context , t *f1testing .T ) f1testing .RunFn {
354+ userAccounts := loadUserAccounts ()
355+ return func (ctx context.Context , t *f1testing.T ) {
356+ account := userAccounts[t.VUID ]
357+ // use account for this virtual user
358+ }
359+ }
360+ ```
361+
345362---
346363
347364## 10. Metrics Package Removal
@@ -355,16 +372,6 @@ t.Fatalf("iteration %d failed: %v", t.Iteration, err)
355372
356373// v3 — no replacement for GetMetrics
357374+ // Use f1.New(WithStaticMetrics(map[string]string{"env": "prod"})) for labels
358- + // Internal metrics (iteration counts, latency, etc.) are not exposed
359- ```
360-
361- If you used ` GetMetrics() ` for custom labels, migrate to ` WithStaticMetrics ` :
362-
363- ``` go
364- f1.New (WithStaticMetrics (map [string ]string {
365- " environment" : " staging" ,
366- " service" : " my-api" ,
367- }))
368375```
369376
370377---
@@ -407,15 +414,53 @@ Run command flags are now grouped in help output (Output, Duration & limits, Con
407414
408415---
409416
410- ## 13. Complete Before/After Example
417+ ## 13. Configuration Changes
418+
419+ ### 13.1 Programmatic Configuration (New in v3)
420+
421+ v3 adds typed, programmatic configuration options as an alternative to environment variables:
422+
423+ ``` go
424+ f1.New (
425+ f1.WithLogLevel (slog.LevelDebug ),
426+ f1.WithLogFormat (f1.LogFormatJSON ),
427+ f1.WithPrometheusPushGateway (" http://pushgateway:9091" ),
428+ f1.WithPrometheusNamespace (" my-namespace" ),
429+ )
430+ ```
431+
432+ Environment variables continue to work as the default baseline (backward compatible).
433+
434+ ### 13.2 ` WithSettings ` for Full Control
435+
436+ Use ` WithSettings(Settings{}) ` to ignore all environment variables:
437+
438+ ``` go
439+ f1.New (
440+ f1.WithSettings (f1.Settings {}),
441+ f1.WithLogLevel (slog.LevelWarn ),
442+ )
443+ ```
444+
445+ ### 13.3 Precedence
446+
447+ Settings are resolved in this order (highest to lowest):
448+ 1 . Programmatic options (applied in order)
449+ 2 . Environment variables (baseline when no ` WithSettings ` is used)
450+ 3 . Defaults (` slog.LevelInfo ` , ` LogFormatText ` , no Prometheus push)
451+
452+ ` WithLogger ` takes absolute precedence for logging.
453+
454+ ---
455+
456+ ## 14. Complete Before/After Example
411457
412458### v2
413459
414460``` go
415461package main
416462
417463import (
418- " context"
419464 " fmt"
420465 " log/slog"
421466
@@ -482,7 +527,7 @@ func myScenario(ctx context.Context, t *f1testing.T) f1testing.RunFn {
482527
483528---
484529
485- ## 14 . Migration Checklist
530+ ## 15 . Migration Checklist
486531
487532Use this checklist when migrating from v2 to v3:
488533
@@ -493,11 +538,11 @@ Use this checklist when migrating from v2 to v3:
493538- [ ] Replace ` Description( ` → ` WithDescription( ` , ` Parameter( ` → ` WithParameter( `
494539- [ ] Replace ` New().WithLogger(l) ` → ` New(WithLogger(l)) ` , ` New().WithStaticMetrics(m) ` → ` New(WithStaticMetrics(m)) `
495540- [ ] Replace ` ExecuteWithArgs(args) ` → ` Run(context.Background(), args) ` (or ` Run(ctx, args) ` with a context)
496- - [ ] Replace ` NewT() ` with ` NewTWithOptions() ` if used (e.g. in tests)
541+ - [ ] Replace ` NewT() ` with ` NewTWithOptions() ` if used
497542- [ ] Replace ` WithLogrusLogger() ` with ` WithLogger(*slog.Logger) ` if used
498543- [ ] Remove ` metrics.GetMetrics() ` usage; use ` WithStaticMetrics ` for labels
499544- [ ] Remove ` T.Time() ` usage; record timing manually if needed
500- - [ ] Update ` T.Logger() ` call sites: it now returns ` *slog.Logger ` (not ` *logrus.Logger ` )
545+ - [ ] Update ` T.Logger() ` call sites: returns ` *slog.Logger ` (not ` *logrus.Logger ` )
501546- [ ] (Optional) ` Error ` /` Fatal ` now use ` args ...any ` ; existing ` Error(err) ` /` Fatal(err) ` calls remain valid
502547- [ ] Replace ` t.Logf("Iteration: %s", t.Iteration) ` with ` t.Logf("Iteration: %d", t.Iteration) ` if used
503548- [ ] Update CLI invocations: ` --cpuprofile ` → ` --cpu-profile ` , ` --memprofile ` → ` --mem-profile ` , ` --iterationFrequency ` → ` --iteration-frequency `
0 commit comments