Skip to content
Open
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
40 changes: 40 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package config

import (
"os"
"time"
)

// Config holds runtime configuration for the server, sourced from the
// environment.
type Config struct {
Addr string
ReadTimeout time.Duration
WriteTimeout time.Duration
}

// Load reads configuration from environment variables, falling back to
// sensible defaults when a variable is unset.
func Load() Config {
return Config{
Addr: getString("ADDR", ":8080"),
ReadTimeout: getDuration("READ_TIMEOUT", 5*time.Second),
WriteTimeout: getDuration("WRITE_TIMEOUT", 10*time.Second),
}
}

func getString(key, fallback string) string {
if v := os.Getenv(key); v != "" {
return v
}
return fallback
}

func getDuration(key string, fallback time.Duration) time.Duration {
if v := os.Getenv(key); v != "" {
if d, err := time.ParseDuration(v); err == nil {
return d
}
}
return fallback
}
49 changes: 49 additions & 0 deletions internal/config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package config

import (
"testing"
"time"
)

func TestLoadDefaults(t *testing.T) {
t.Setenv("ADDR", "")
t.Setenv("READ_TIMEOUT", "")
t.Setenv("WRITE_TIMEOUT", "")

cfg := Load()
if cfg.Addr != ":8080" {
t.Errorf("Addr = %q, want :8080", cfg.Addr)
}
if cfg.ReadTimeout != 5*time.Second {
t.Errorf("ReadTimeout = %v, want 5s", cfg.ReadTimeout)
}
if cfg.WriteTimeout != 10*time.Second {
t.Errorf("WriteTimeout = %v, want 10s", cfg.WriteTimeout)
}
}

func TestLoadOverrides(t *testing.T) {
t.Setenv("ADDR", ":9090")
t.Setenv("READ_TIMEOUT", "2s")
t.Setenv("WRITE_TIMEOUT", "20s")

cfg := Load()
if cfg.Addr != ":9090" {
t.Errorf("Addr = %q, want :9090", cfg.Addr)
}
if cfg.ReadTimeout != 2*time.Second {
t.Errorf("ReadTimeout = %v, want 2s", cfg.ReadTimeout)
}
if cfg.WriteTimeout != 20*time.Second {
t.Errorf("WriteTimeout = %v, want 20s", cfg.WriteTimeout)
}
}

func TestLoadInvalidDurationFallsBack(t *testing.T) {
t.Setenv("READ_TIMEOUT", "not-a-duration")

cfg := Load()
if cfg.ReadTimeout != 5*time.Second {
t.Errorf("ReadTimeout = %v, want fallback 5s", cfg.ReadTimeout)
}
}
Loading