Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package config

import (
"encoding/json"
"fmt"
"math/big"
"time"
)

// LoadConfig stores the configuration for load-related settings.
Expand All @@ -16,6 +19,33 @@ type LoadConfig struct {
Settings *Settings `json:"settings,omitempty"`
}

// Duration wraps time.Duration to provide JSON unmarshaling support
type Duration time.Duration

// UnmarshalJSON implements json.Unmarshaler for Duration
func (d *Duration) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
parsed, err := time.ParseDuration(s)
if err != nil {
return fmt.Errorf("invalid duration format: %w", err)
}
*d = Duration(parsed)
return nil
}

// ToDuration converts Duration back to time.Duration
func (d Duration) ToDuration() time.Duration {
return time.Duration(d)
}

// MarshalJSON implements json.Marshaler for Duration
func (d Duration) MarshalJSON() ([]byte, error) {
return json.Marshal(time.Duration(d).String())
}

// GetChainID returns the chain ID as a big.Int.
func (c *LoadConfig) GetChainID() *big.Int {
return big.NewInt(c.ChainID)
Expand Down
8 changes: 4 additions & 4 deletions config/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
type Settings struct {
Workers int `json:"workers"`
TPS float64 `json:"tps"`
StatsInterval time.Duration `json:"statsInterval"`
StatsInterval Duration `json:"statsInterval"`
BufferSize int `json:"bufferSize"`
DryRun bool `json:"dryRun"`
Debug bool `json:"debug"`
Expand All @@ -28,7 +28,7 @@ func DefaultSettings() Settings {
return Settings{
Workers: 1,
TPS: 0.0,
StatsInterval: 10 * time.Second,
StatsInterval: Duration(10 * time.Second),
BufferSize: 1000,
DryRun: false,
Debug: false,
Expand Down Expand Up @@ -65,7 +65,7 @@ func InitializeViper(cmd *cobra.Command) error {

// Set defaults in Viper
defaults := DefaultSettings()
viper.SetDefault("statsInterval", defaults.StatsInterval)
viper.SetDefault("statsInterval", defaults.StatsInterval.ToDuration())
viper.SetDefault("bufferSize", defaults.BufferSize)
viper.SetDefault("tps", defaults.TPS)
viper.SetDefault("dryRun", defaults.DryRun)
Expand Down Expand Up @@ -98,7 +98,7 @@ func ResolveSettings() Settings {
return Settings{
Workers: viper.GetInt("workers"),
TPS: viper.GetFloat64("tps"),
StatsInterval: viper.GetDuration("statsInterval"),
StatsInterval: Duration(viper.GetDuration("statsInterval")),
BufferSize: viper.GetInt("bufferSize"),
DryRun: viper.GetBool("dryRun"),
Debug: viper.GetBool("debug"),
Expand Down
4 changes: 2 additions & 2 deletions config/settings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func TestArgumentPrecedence(t *testing.T) {
settings := ResolveSettings()

// Verify expectations
require.Equal(t, tt.expectedStats, settings.StatsInterval, "StatsInterval: expected %v, got %v", tt.expectedStats, settings.StatsInterval)
require.Equal(t, tt.expectedStats, settings.StatsInterval.ToDuration(), "StatsInterval: expected %v, got %v", tt.expectedStats, settings.StatsInterval.ToDuration())
require.Equal(t, tt.expectedWorkers, settings.Workers, "Workers: expected %d, got %d", tt.expectedWorkers, settings.Workers)
require.Equal(t, tt.expectedTPS, settings.TPS, "TPS: expected %f, got %f", tt.expectedTPS, settings.TPS)
})
Expand All @@ -121,7 +121,7 @@ func TestDefaultSettings(t *testing.T) {
expected := Settings{
Workers: 1,
TPS: 0.0,
StatsInterval: 10 * time.Second,
StatsInterval: Duration(10 * time.Second),
BufferSize: 1000,
DryRun: false,
Debug: false,
Expand Down
8 changes: 4 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func runLoadTest(ctx context.Context, cmd *cobra.Command, args []string) error {
log.Printf("👥 Workers per endpoint: %d", settings.Workers)
log.Printf("🔧 Total workers: %d", len(cfg.Endpoints)*settings.Workers)
log.Printf("📊 Scenarios: %d", len(cfg.Scenarios))
log.Printf("⏱️ Stats interval: %v", settings.StatsInterval)
log.Printf("⏱️ Stats interval: %v", settings.StatsInterval.ToDuration())
log.Printf("📦 Buffer size per worker: %d", settings.BufferSize)
if settings.TPS > 0 {
log.Printf("📈 Transactions per second: %.2f", settings.TPS)
Expand Down Expand Up @@ -148,7 +148,7 @@ func runLoadTest(ctx context.Context, cmd *cobra.Command, args []string) error {

// Create statistics collector and logger
collector := stats.NewCollector()
logger := stats.NewLogger(collector, settings.StatsInterval, settings.Debug)
logger := stats.NewLogger(collector, settings.StatsInterval.ToDuration(), settings.Debug)
var ramper *sender.Ramper

err = service.Run(ctx, func(ctx context.Context, s service.Scope) error {
Expand Down Expand Up @@ -200,7 +200,7 @@ func runLoadTest(ctx context.Context, cmd *cobra.Command, args []string) error {

// Create and start user latency tracker if endpoints are available
if len(cfg.Endpoints) > 0 && settings.TrackUserLatency {
userLatencyTracker := stats.NewUserLatencyTracker(settings.StatsInterval)
userLatencyTracker := stats.NewUserLatencyTracker(settings.StatsInterval.ToDuration())
s.SpawnBgNamed("user latency tracker", func() error {
return userLatencyTracker.Run(ctx, cfg.Endpoints[0])
})
Expand Down Expand Up @@ -261,7 +261,7 @@ func runLoadTest(ctx context.Context, cmd *cobra.Command, args []string) error {
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

log.Printf("📈 Logging statistics every %v (Press Ctrl+C to stop)", settings.StatsInterval)
log.Printf("📈 Logging statistics every %v (Press Ctrl+C to stop)", settings.StatsInterval.ToDuration())
if settings.DryRun {
log.Printf("📝 Dry-run mode: Simulating requests without sending")
}
Expand Down
23 changes: 13 additions & 10 deletions profiles/evm_transfer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,17 @@
"weight": 1
}
],
"workers": 1,
"tps": 0,
"statsInterval": "5s",
"bufferSize": 1000,
"dryRun": false,
"debug": false,
"trackReceipts": false,
"trackBlocks": false,
"trackUserLatency": false,
"prewarm": false
"settings": {
"workers": 1,
"tps": 0,
"statsInterval": "5s",
"bufferSize": 1000,
"dryRun": false,
"debug": false,
"trackReceipts": false,
"trackBlocks": false,
"trackUserLatency": false,
"prewarm": false,
"rampUp": false
}
}
23 changes: 13 additions & 10 deletions profiles/loadtest_default.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,17 @@
"weight": 1
}
],
"workers": 1,
"tps": 0,
"statsInterval": "5s",
"bufferSize": 1000,
"dryRun": false,
"debug": false,
"trackReceipts": false,
"trackBlocks": false,
"trackUserLatency": false,
"prewarm": false
"settings": {
"workers": 1,
"tps": 0,
"statsInterval": "5s",
"bufferSize": 1000,
"dryRun": false,
"debug": false,
"trackReceipts": false,
"trackBlocks": false,
"trackUserLatency": false,
"prewarm": false,
"rampUp": false
}
}
23 changes: 13 additions & 10 deletions profiles/local.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,17 @@
"weight": 1
}
],
"workers": 1,
"tps": 0,
"statsInterval": "5s",
"bufferSize": 1000,
"dryRun": false,
"debug": false,
"trackReceipts": false,
"trackBlocks": false,
"trackUserLatency": false,
"prewarm": false
"settings": {
"workers": 1,
"tps": 0,
"statsInterval": "5s",
"bufferSize": 1000,
"dryRun": false,
"debug": false,
"trackReceipts": false,
"trackBlocks": false,
"trackUserLatency": false,
"prewarm": false,
"rampUp": false
}
}
23 changes: 13 additions & 10 deletions profiles/local_docker.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@
"weight": 1
}
],
"workers": 1,
"tps": 0,
"statsInterval": "5s",
"bufferSize": 1000,
"dryRun": false,
"debug": false,
"trackReceipts": false,
"trackBlocks": false,
"trackUserLatency": false,
"prewarm": false
"settings": {
"workers": 1,
"tps": 0,
"statsInterval": "5s",
"bufferSize": 1000,
"dryRun": false,
"debug": false,
"trackReceipts": false,
"trackBlocks": false,
"trackUserLatency": false,
"prewarm": false,
"rampUp": false
}
}
Loading
Loading