From f4277255db04f618d75c7924d1f7887a65ffd56a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 21:45:45 +0000 Subject: [PATCH 1/2] Initial plan From 0ae04a67de801596c853333b26975bfc586da808 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 21:48:48 +0000 Subject: [PATCH 2/2] feat(config): validate poll interval is positive Co-authored-by: rmax <26015+rmax@users.noreply.github.com> --- cmd/ratelord-d/config.go | 6 ++ cmd/ratelord-d/config_test.go | 102 ++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 cmd/ratelord-d/config_test.go diff --git a/cmd/ratelord-d/config.go b/cmd/ratelord-d/config.go index 2c8799c..3dac249 100644 --- a/cmd/ratelord-d/config.go +++ b/cmd/ratelord-d/config.go @@ -44,6 +44,9 @@ func LoadConfig(args []string) (Config, error) { if err != nil { return Config{}, fmt.Errorf("invalid RATELORD_POLL_INTERVAL: %w", err) } + if parsed <= 0 { + return Config{}, errors.New("RATELORD_POLL_INTERVAL must be positive") + } pollInterval = parsed } webAssetsMode := envOrDefault("RATELORD_WEB_ASSETS_MODE", defaultWebAssetsMode) @@ -71,6 +74,9 @@ func LoadConfig(args []string) (Config, error) { if err != nil { return Config{}, fmt.Errorf("invalid poll interval: %w", err) } + if pollIntervalParsed <= 0 { + return Config{}, errors.New("poll interval must be positive") + } resolvedDBPath := resolvePath(*flagDB, cwd) resolvedPolicyPath := resolvePath(*flagPolicy, cwd) diff --git a/cmd/ratelord-d/config_test.go b/cmd/ratelord-d/config_test.go new file mode 100644 index 0000000..75c2a7a --- /dev/null +++ b/cmd/ratelord-d/config_test.go @@ -0,0 +1,102 @@ +package main + +import ( + "os" + "strings" + "testing" + "time" +) + +func TestLoadConfig_PollIntervalValidation(t *testing.T) { + tests := []struct { + name string + args []string + envVars map[string]string + expectError bool + errorSubstr string + }{ + { + name: "valid poll interval from flag", + args: []string{"-poll-interval", "5s"}, + expectError: false, + }, + { + name: "zero poll interval from flag", + args: []string{"-poll-interval", "0s"}, + expectError: true, + errorSubstr: "poll interval must be positive", + }, + { + name: "negative poll interval from flag", + args: []string{"-poll-interval", "-5s"}, + expectError: true, + errorSubstr: "poll interval must be positive", + }, + { + name: "valid poll interval from env", + envVars: map[string]string{"RATELORD_POLL_INTERVAL": "5s"}, + expectError: false, + }, + { + name: "zero poll interval from env", + envVars: map[string]string{"RATELORD_POLL_INTERVAL": "0s"}, + expectError: true, + errorSubstr: "RATELORD_POLL_INTERVAL must be positive", + }, + { + name: "negative poll interval from env", + envVars: map[string]string{"RATELORD_POLL_INTERVAL": "-5s"}, + expectError: true, + errorSubstr: "RATELORD_POLL_INTERVAL must be positive", + }, + { + name: "invalid poll interval format from flag", + args: []string{"-poll-interval", "invalid"}, + expectError: true, + errorSubstr: "invalid poll interval", + }, + { + name: "invalid poll interval format from env", + envVars: map[string]string{"RATELORD_POLL_INTERVAL": "invalid"}, + expectError: true, + errorSubstr: "invalid RATELORD_POLL_INTERVAL", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Set up environment variables + for k, v := range tt.envVars { + os.Setenv(k, v) + defer os.Unsetenv(k) + } + + cfg, err := LoadConfig(tt.args) + + if tt.expectError { + if err == nil { + t.Errorf("expected error containing %q, got nil", tt.errorSubstr) + } else if !strings.Contains(err.Error(), tt.errorSubstr) { + t.Errorf("expected error containing %q, got %q", tt.errorSubstr, err.Error()) + } + } else { + if err != nil { + t.Errorf("unexpected error: %v", err) + } else if cfg.PollInterval <= 0 { + t.Errorf("expected positive poll interval, got %v", cfg.PollInterval) + } + } + }) + } +} + +func TestLoadConfig_DefaultPollInterval(t *testing.T) { + cfg, err := LoadConfig([]string{}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if cfg.PollInterval != 10*time.Second { + t.Errorf("expected default poll interval of 10s, got %v", cfg.PollInterval) + } +}