306 lines
9.0 KiB
Go
306 lines
9.0 KiB
Go
package config_test
|
|
|
|
import (
|
|
"math"
|
|
"net/netip"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.misaka.ren/M1saka/token_thief/config"
|
|
)
|
|
|
|
func TestLoadTimeoutDefaults(t *testing.T) {
|
|
t.Setenv("UPSTREAM_URL", "https://example.com")
|
|
t.Setenv("CLICKHOUSE_URL", "clickhouse://user:pass@localhost:9000/db")
|
|
|
|
cfg, err := config.Load()
|
|
if err != nil {
|
|
t.Fatalf("Load: %v", err)
|
|
}
|
|
|
|
if cfg.ReadTimeout != 30*time.Second {
|
|
t.Fatalf("ReadTimeout=%s want 30s", cfg.ReadTimeout)
|
|
}
|
|
if cfg.WriteTimeout != 10*time.Minute {
|
|
t.Fatalf("WriteTimeout=%s want 10m", cfg.WriteTimeout)
|
|
}
|
|
if cfg.IdleTimeout != 5*time.Minute {
|
|
t.Fatalf("IdleTimeout=%s want 5m", cfg.IdleTimeout)
|
|
}
|
|
if cfg.UpstreamTimeout != 30*time.Second {
|
|
t.Fatalf("UpstreamTimeout=%s want 30s", cfg.UpstreamTimeout)
|
|
}
|
|
if cfg.UpstreamResponseTimeout != 30*time.Second {
|
|
t.Fatalf("UpstreamResponseTimeout=%s want 30s", cfg.UpstreamResponseTimeout)
|
|
}
|
|
if cfg.UpstreamStreamIdleTimeout != 2*time.Minute {
|
|
t.Fatalf("UpstreamStreamIdleTimeout=%s want 2m", cfg.UpstreamStreamIdleTimeout)
|
|
}
|
|
}
|
|
|
|
func TestLoadQueueDefaults(t *testing.T) {
|
|
t.Setenv("UPSTREAM_URL", "https://example.com")
|
|
t.Setenv("CLICKHOUSE_URL", "clickhouse://user:pass@localhost:9000/db")
|
|
|
|
cfg, err := config.Load()
|
|
if err != nil {
|
|
t.Fatalf("Load: %v", err)
|
|
}
|
|
|
|
if cfg.MaxBodyBytes != 1<<20 {
|
|
t.Fatalf("MaxBodyBytes=%d want %d", cfg.MaxBodyBytes, 1<<20)
|
|
}
|
|
if cfg.MaxRequestBytes != 16<<20 {
|
|
t.Fatalf("MaxRequestBytes=%d want %d", cfg.MaxRequestBytes, 16<<20)
|
|
}
|
|
if cfg.LogQueueSize != 256 {
|
|
t.Fatalf("LogQueueSize=%d want 256", cfg.LogQueueSize)
|
|
}
|
|
if cfg.LogQueueBytes != 64<<20 {
|
|
t.Fatalf("LogQueueBytes=%d want %d", cfg.LogQueueBytes, 64<<20)
|
|
}
|
|
}
|
|
|
|
func TestLoadTimeoutOverrides(t *testing.T) {
|
|
t.Setenv("UPSTREAM_URL", "https://example.com")
|
|
t.Setenv("CLICKHOUSE_URL", "clickhouse://user:pass@localhost:9000/db")
|
|
t.Setenv("READ_TIMEOUT", "10s")
|
|
t.Setenv("WRITE_TIMEOUT", "20s")
|
|
t.Setenv("IDLE_TIMEOUT", "30s")
|
|
t.Setenv("UPSTREAM_TIMEOUT", "40s")
|
|
t.Setenv("UPSTREAM_RESPONSE_TIMEOUT", "50s")
|
|
t.Setenv("UPSTREAM_STREAM_IDLE_TIMEOUT", "60s")
|
|
|
|
cfg, err := config.Load()
|
|
if err != nil {
|
|
t.Fatalf("Load: %v", err)
|
|
}
|
|
|
|
if cfg.ReadTimeout != 10*time.Second {
|
|
t.Fatalf("ReadTimeout=%s want 10s", cfg.ReadTimeout)
|
|
}
|
|
if cfg.WriteTimeout != 20*time.Second {
|
|
t.Fatalf("WriteTimeout=%s want 20s", cfg.WriteTimeout)
|
|
}
|
|
if cfg.IdleTimeout != 30*time.Second {
|
|
t.Fatalf("IdleTimeout=%s want 30s", cfg.IdleTimeout)
|
|
}
|
|
if cfg.UpstreamTimeout != 40*time.Second {
|
|
t.Fatalf("UpstreamTimeout=%s want 40s", cfg.UpstreamTimeout)
|
|
}
|
|
if cfg.UpstreamResponseTimeout != 50*time.Second {
|
|
t.Fatalf("UpstreamResponseTimeout=%s want 50s", cfg.UpstreamResponseTimeout)
|
|
}
|
|
if cfg.UpstreamStreamIdleTimeout != 60*time.Second {
|
|
t.Fatalf("UpstreamStreamIdleTimeout=%s want 60s", cfg.UpstreamStreamIdleTimeout)
|
|
}
|
|
}
|
|
|
|
func TestLoadRejectsInvalidTypedValues(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
key string
|
|
value string
|
|
}{
|
|
{name: "int", key: "LOG_QUEUE_SIZE", value: "not-an-int"},
|
|
{name: "int64", key: "MAX_BODY_BYTES", value: "1.5"},
|
|
{name: "duration", key: "READ_TIMEOUT", value: "30"},
|
|
{name: "bool", key: "UPSTREAM_TLS_INSECURE_SKIP_VERIFY", value: "yes"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Setenv("UPSTREAM_URL", "https://example.com")
|
|
t.Setenv("CLICKHOUSE_URL", "clickhouse://user:pass@localhost:9000/db")
|
|
t.Setenv(tt.key, tt.value)
|
|
|
|
_, err := config.Load()
|
|
if err == nil {
|
|
t.Fatalf("Load succeeded with %s=%q", tt.key, tt.value)
|
|
}
|
|
if !strings.Contains(err.Error(), tt.key) {
|
|
t.Fatalf("err=%q does not identify %s", err, tt.key)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLoadRejectsNonPositiveNumericAndDurationValues(t *testing.T) {
|
|
tests := []struct {
|
|
key string
|
|
value string
|
|
}{
|
|
{key: "MAX_BODY_BYTES", value: "0"},
|
|
{key: "LOG_QUEUE_SIZE", value: "-1"},
|
|
{key: "LOG_QUEUE_BYTES", value: "0"},
|
|
{key: "LOG_BATCH_SIZE", value: "0"},
|
|
{key: "LOG_BATCH_INTERVAL", value: "-1s"},
|
|
{key: "LOG_WORKERS", value: "0"},
|
|
{key: "DB_RECONNECT_INTERVAL", value: "0s"},
|
|
{key: "READ_TIMEOUT", value: "0s"},
|
|
{key: "WRITE_TIMEOUT", value: "0s"},
|
|
{key: "IDLE_TIMEOUT", value: "0s"},
|
|
{key: "UPSTREAM_TIMEOUT", value: "0s"},
|
|
{key: "UPSTREAM_RESPONSE_TIMEOUT", value: "0s"},
|
|
{key: "UPSTREAM_STREAM_IDLE_TIMEOUT", value: "0s"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.key, func(t *testing.T) {
|
|
t.Setenv("UPSTREAM_URL", "https://example.com")
|
|
t.Setenv("CLICKHOUSE_URL", "clickhouse://user:pass@localhost:9000/db")
|
|
t.Setenv(tt.key, tt.value)
|
|
|
|
_, err := config.Load()
|
|
if err == nil {
|
|
t.Fatalf("Load succeeded with %s=%q", tt.key, tt.value)
|
|
}
|
|
if !strings.Contains(err.Error(), tt.key) {
|
|
t.Fatalf("err=%q does not identify %s", err, tt.key)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLoadTrustedProxies(t *testing.T) {
|
|
t.Setenv("UPSTREAM_URL", "https://example.com")
|
|
t.Setenv("CLICKHOUSE_URL", "clickhouse://user:pass@localhost:9000/db")
|
|
t.Setenv("TRUSTED_PROXIES", "10.0.0.0/8, 192.0.2.1,2001:db8::/32, 2001:db8::1")
|
|
|
|
cfg, err := config.Load()
|
|
if err != nil {
|
|
t.Fatalf("Load: %v", err)
|
|
}
|
|
|
|
want := []netip.Prefix{
|
|
netip.MustParsePrefix("10.0.0.0/8"),
|
|
netip.MustParsePrefix("192.0.2.1/32"),
|
|
netip.MustParsePrefix("2001:db8::/32"),
|
|
netip.MustParsePrefix("2001:db8::1/128"),
|
|
}
|
|
if len(cfg.TrustedProxies) != len(want) {
|
|
t.Fatalf("TrustedProxies=%v want %v", cfg.TrustedProxies, want)
|
|
}
|
|
for i := range want {
|
|
if cfg.TrustedProxies[i] != want[i] {
|
|
t.Fatalf("TrustedProxies[%d]=%v want %v", i, cfg.TrustedProxies[i], want[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLoadRejectsInvalidTrustedProxies(t *testing.T) {
|
|
for _, value := range []string{"not-an-ip", "10.0.0.0/33", "10.0.0.1/8", "10.0.0.1,,192.0.2.1"} {
|
|
t.Run(value, func(t *testing.T) {
|
|
t.Setenv("UPSTREAM_URL", "https://example.com")
|
|
t.Setenv("CLICKHOUSE_URL", "clickhouse://user:pass@localhost:9000/db")
|
|
t.Setenv("TRUSTED_PROXIES", value)
|
|
|
|
_, err := config.Load()
|
|
if err == nil {
|
|
t.Fatalf("Load succeeded with TRUSTED_PROXIES=%q", value)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLoadUpstreamTLSInsecureSkipVerifyDefault(t *testing.T) {
|
|
t.Setenv("UPSTREAM_URL", "https://example.com")
|
|
t.Setenv("CLICKHOUSE_URL", "clickhouse://user:pass@localhost:9000/db")
|
|
|
|
cfg, err := config.Load()
|
|
if err != nil {
|
|
t.Fatalf("Load: %v", err)
|
|
}
|
|
|
|
if cfg.UpstreamTLSInsecureSkipVerify {
|
|
t.Fatal("UpstreamTLSInsecureSkipVerify=true want false")
|
|
}
|
|
}
|
|
|
|
func TestLoadUpstreamTLSInsecureSkipVerifyOverride(t *testing.T) {
|
|
t.Setenv("UPSTREAM_URL", "https://example.com")
|
|
t.Setenv("CLICKHOUSE_URL", "clickhouse://user:pass@localhost:9000/db")
|
|
t.Setenv("UPSTREAM_TLS_INSECURE_SKIP_VERIFY", "true")
|
|
|
|
cfg, err := config.Load()
|
|
if err != nil {
|
|
t.Fatalf("Load: %v", err)
|
|
}
|
|
|
|
if !cfg.UpstreamTLSInsecureSkipVerify {
|
|
t.Fatal("UpstreamTLSInsecureSkipVerify=false want true")
|
|
}
|
|
}
|
|
|
|
func TestLoadRequiresClickHouseURL(t *testing.T) {
|
|
t.Setenv("UPSTREAM_URL", "https://example.com")
|
|
t.Setenv("DATABASE_URL", "postgres://user:pass@localhost/db")
|
|
|
|
_, err := config.Load()
|
|
if err == nil {
|
|
t.Fatal("Load succeeded without CLICKHOUSE_URL")
|
|
}
|
|
if err.Error() != "CLICKHOUSE_URL is required" {
|
|
t.Fatalf("err=%q want CLICKHOUSE_URL is required", err.Error())
|
|
}
|
|
}
|
|
|
|
func TestLoadRejectsUnsupportedUpstreamScheme(t *testing.T) {
|
|
t.Setenv("UPSTREAM_URL", "ftp://example.com")
|
|
t.Setenv("CLICKHOUSE_URL", "clickhouse://user:pass@localhost:9000/db")
|
|
if _, err := config.Load(); err == nil {
|
|
t.Fatal("Load succeeded with unsupported UPSTREAM_URL scheme")
|
|
}
|
|
}
|
|
|
|
func TestLoadRejectsMaxRequestBytesOverflowBoundary(t *testing.T) {
|
|
t.Setenv("UPSTREAM_URL", "https://example.com")
|
|
t.Setenv("CLICKHOUSE_URL", "clickhouse://user:pass@localhost:9000/db")
|
|
t.Setenv("MAX_REQUEST_BYTES", strconv.FormatInt(math.MaxInt64, 10))
|
|
if _, err := config.Load(); err == nil || !strings.Contains(err.Error(), "MAX_REQUEST_BYTES") {
|
|
t.Fatalf("Load error=%v, want MAX_REQUEST_BYTES rejection", err)
|
|
}
|
|
}
|
|
|
|
func TestLoadValidatesClickHouseURL(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
dsn string
|
|
}{
|
|
{name: "missing port", dsn: "clickhouse://user:pass@localhost/db"},
|
|
{name: "unsupported scheme", dsn: "https://localhost:9440/db"},
|
|
{name: "plaintext skip verify", dsn: "clickhouse://localhost:9000/db?skip_verify=true"},
|
|
{name: "conflicting secure parameter", dsn: "clickhouses://localhost:9440/db?secure=false"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Setenv("UPSTREAM_URL", "https://example.com")
|
|
t.Setenv("CLICKHOUSE_URL", tt.dsn)
|
|
|
|
_, err := config.Load()
|
|
if err == nil {
|
|
t.Fatalf("Load succeeded with CLICKHOUSE_URL=%q", tt.dsn)
|
|
}
|
|
if !strings.Contains(err.Error(), "CLICKHOUSE_URL") {
|
|
t.Fatalf("err=%q does not identify CLICKHOUSE_URL", err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLoadAcceptsSecureClickHouseURL(t *testing.T) {
|
|
t.Setenv("UPSTREAM_URL", "https://example.com")
|
|
t.Setenv("CLICKHOUSE_URL", "clickhouses://user:pass@localhost:9440/db?skip_verify=false")
|
|
|
|
cfg, err := config.Load()
|
|
if err != nil {
|
|
t.Fatalf("Load: %v", err)
|
|
}
|
|
if cfg.ClickHouseURL != "clickhouses://user:pass@localhost:9440/db?skip_verify=false" {
|
|
t.Fatalf("ClickHouseURL=%q", cfg.ClickHouseURL)
|
|
}
|
|
}
|