257 lines
9.5 KiB
Go
257 lines
9.5 KiB
Go
package config
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestLoadFromEnvUsesDefaults(t *testing.T) {
|
|
t.Setenv(redisAddrEnvVar, "127.0.0.1:6379")
|
|
|
|
cfg, err := LoadFromEnv()
|
|
require.NoError(t, err)
|
|
|
|
defaults := DefaultConfig()
|
|
require.Equal(t, defaults.ShutdownTimeout, cfg.ShutdownTimeout)
|
|
require.Equal(t, defaults.Logging, cfg.Logging)
|
|
require.Equal(t, defaults.InternalHTTP, cfg.InternalHTTP)
|
|
require.Equal(t, "127.0.0.1:6379", cfg.Redis.Addr)
|
|
require.Equal(t, defaults.Redis.DB, cfg.Redis.DB)
|
|
require.Equal(t, defaults.Redis.OperationTimeout, cfg.Redis.OperationTimeout)
|
|
require.Equal(t, defaults.Redis.CommandStream, cfg.Redis.CommandStream)
|
|
require.Equal(t, defaults.Redis.AttemptScheduleKey, cfg.Redis.AttemptScheduleKey)
|
|
require.Equal(t, defaults.Redis.DeadLetterPrefix, cfg.Redis.DeadLetterPrefix)
|
|
require.Equal(t, defaults.SMTP, cfg.SMTP)
|
|
require.Equal(t, defaults.Templates, cfg.Templates)
|
|
require.Equal(t, defaults.AttemptWorkerConcurrency, cfg.AttemptWorkerConcurrency)
|
|
require.Equal(t, defaults.StreamBlockTimeout, cfg.StreamBlockTimeout)
|
|
require.Equal(t, defaults.OperatorRequestTimeout, cfg.OperatorRequestTimeout)
|
|
require.Equal(t, defaults.IdempotencyTTL, cfg.IdempotencyTTL)
|
|
require.Equal(t, defaults.DeliveryTTL, cfg.DeliveryTTL)
|
|
require.Equal(t, defaults.AttemptTTL, cfg.AttemptTTL)
|
|
require.Equal(t, defaults.Telemetry, cfg.Telemetry)
|
|
}
|
|
|
|
func TestLoadFromEnvAppliesOverrides(t *testing.T) {
|
|
t.Setenv(shutdownTimeoutEnvVar, "9s")
|
|
t.Setenv(logLevelEnvVar, "debug")
|
|
t.Setenv(internalHTTPAddrEnvVar, "127.0.0.1:18080")
|
|
t.Setenv(internalHTTPReadHeaderTimeoutEnvVar, "3s")
|
|
t.Setenv(internalHTTPReadTimeoutEnvVar, "11s")
|
|
t.Setenv(internalHTTPIdleTimeoutEnvVar, "61s")
|
|
t.Setenv(redisAddrEnvVar, "127.0.0.1:6380")
|
|
t.Setenv(redisUsernameEnvVar, "alice")
|
|
t.Setenv(redisPasswordEnvVar, "secret")
|
|
t.Setenv(redisDBEnvVar, "3")
|
|
t.Setenv(redisTLSEnabledEnvVar, "true")
|
|
t.Setenv(redisOperationTimeoutEnvVar, "750ms")
|
|
t.Setenv(redisCommandStreamEnvVar, "mail:test_commands")
|
|
t.Setenv(redisAttemptScheduleEnvVar, "mail:test_schedule")
|
|
t.Setenv(redisDeadLetterPrefixEnvVar, "mail:test_dead_letters:")
|
|
t.Setenv(smtpModeEnvVar, SMTPModeSMTP)
|
|
t.Setenv(smtpAddrEnvVar, "127.0.0.1:2525")
|
|
t.Setenv(smtpUsernameEnvVar, "mailer")
|
|
t.Setenv(smtpPasswordEnvVar, "smtp-secret")
|
|
t.Setenv(smtpFromEmailEnvVar, "noreply@example.com")
|
|
t.Setenv(smtpFromNameEnvVar, "Galaxy Mail")
|
|
t.Setenv(smtpTimeoutEnvVar, "19s")
|
|
t.Setenv(smtpInsecureSkipVerifyEnvVar, "true")
|
|
t.Setenv(templateDirEnvVar, "/tmp/templates")
|
|
t.Setenv(attemptWorkerConcurrencyEnvVar, "8")
|
|
t.Setenv(streamBlockTimeoutEnvVar, "5s")
|
|
t.Setenv(operatorRequestTimeoutEnvVar, "6s")
|
|
t.Setenv(idempotencyTTLEnvVar, "48h")
|
|
t.Setenv(deliveryTTLEnvVar, "96h")
|
|
t.Setenv(attemptTTLEnvVar, "240h")
|
|
t.Setenv(otelServiceNameEnvVar, "custom-mail")
|
|
t.Setenv(otelTracesExporterEnvVar, "otlp")
|
|
t.Setenv(otelMetricsExporterEnvVar, "otlp")
|
|
t.Setenv(otelExporterOTLPProtocolEnvVar, "grpc")
|
|
t.Setenv(otelStdoutTracesEnabledEnvVar, "true")
|
|
t.Setenv(otelStdoutMetricsEnabledEnvVar, "true")
|
|
|
|
cfg, err := LoadFromEnv()
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 9*time.Second, cfg.ShutdownTimeout)
|
|
require.Equal(t, "debug", cfg.Logging.Level)
|
|
require.Equal(t, InternalHTTPConfig{
|
|
Addr: "127.0.0.1:18080",
|
|
ReadHeaderTimeout: 3 * time.Second,
|
|
ReadTimeout: 11 * time.Second,
|
|
IdleTimeout: 61 * time.Second,
|
|
}, cfg.InternalHTTP)
|
|
require.Equal(t, RedisConfig{
|
|
Addr: "127.0.0.1:6380",
|
|
Username: "alice",
|
|
Password: "secret",
|
|
DB: 3,
|
|
TLSEnabled: true,
|
|
OperationTimeout: 750 * time.Millisecond,
|
|
CommandStream: "mail:test_commands",
|
|
AttemptScheduleKey: "mail:test_schedule",
|
|
DeadLetterPrefix: "mail:test_dead_letters:",
|
|
}, cfg.Redis)
|
|
require.Equal(t, SMTPConfig{
|
|
Mode: SMTPModeSMTP,
|
|
Addr: "127.0.0.1:2525",
|
|
Username: "mailer",
|
|
Password: "smtp-secret",
|
|
FromEmail: "noreply@example.com",
|
|
FromName: "Galaxy Mail",
|
|
Timeout: 19 * time.Second,
|
|
InsecureSkipVerify: true,
|
|
}, cfg.SMTP)
|
|
require.Equal(t, TemplateConfig{Dir: "/tmp/templates"}, cfg.Templates)
|
|
require.Equal(t, 8, cfg.AttemptWorkerConcurrency)
|
|
require.Equal(t, 5*time.Second, cfg.StreamBlockTimeout)
|
|
require.Equal(t, 6*time.Second, cfg.OperatorRequestTimeout)
|
|
require.Equal(t, 48*time.Hour, cfg.IdempotencyTTL)
|
|
require.Equal(t, 96*time.Hour, cfg.DeliveryTTL)
|
|
require.Equal(t, 240*time.Hour, cfg.AttemptTTL)
|
|
require.Equal(t, TelemetryConfig{
|
|
ServiceName: "custom-mail",
|
|
TracesExporter: "otlp",
|
|
MetricsExporter: "otlp",
|
|
TracesProtocol: "grpc",
|
|
MetricsProtocol: "grpc",
|
|
StdoutTracesEnabled: true,
|
|
StdoutMetricsEnabled: true,
|
|
}, cfg.Telemetry)
|
|
}
|
|
|
|
func TestLoadFromEnvRejectsInvalidValues(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
envName string
|
|
envVal string
|
|
}{
|
|
{name: "invalid duration", envName: shutdownTimeoutEnvVar, envVal: "later"},
|
|
{name: "invalid log level", envName: logLevelEnvVar, envVal: "verbose"},
|
|
{name: "invalid redis db", envName: redisDBEnvVar, envVal: "db-three"},
|
|
{name: "invalid redis tls", envName: redisTLSEnabledEnvVar, envVal: "sometimes"},
|
|
{name: "invalid redis timeout", envName: redisOperationTimeoutEnvVar, envVal: "never"},
|
|
{name: "invalid smtp mode", envName: smtpModeEnvVar, envVal: "ses"},
|
|
{name: "invalid smtp timeout", envName: smtpTimeoutEnvVar, envVal: "fast"},
|
|
{name: "invalid smtp insecure skip verify", envName: smtpInsecureSkipVerifyEnvVar, envVal: "sometimes"},
|
|
{name: "invalid worker count", envName: attemptWorkerConcurrencyEnvVar, envVal: "many"},
|
|
{name: "invalid otel traces exporter", envName: otelTracesExporterEnvVar, envVal: "stdout"},
|
|
{name: "invalid otel metrics exporter", envName: otelMetricsExporterEnvVar, envVal: "stdout"},
|
|
{name: "invalid otel traces protocol", envName: otelExporterOTLPTracesProtocolEnvVar, envVal: "udp"},
|
|
{name: "invalid otel metrics protocol", envName: otelExporterOTLPMetricsProtocolEnvVar, envVal: "udp"},
|
|
{name: "invalid otel stdout traces", envName: otelStdoutTracesEnabledEnvVar, envVal: "sometimes"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Setenv(redisAddrEnvVar, "127.0.0.1:6379")
|
|
t.Setenv(tt.envName, tt.envVal)
|
|
if tt.envName == smtpTimeoutEnvVar {
|
|
t.Setenv(smtpModeEnvVar, SMTPModeSMTP)
|
|
t.Setenv(smtpAddrEnvVar, "127.0.0.1:2525")
|
|
t.Setenv(smtpFromEmailEnvVar, "noreply@example.com")
|
|
}
|
|
|
|
_, err := LoadFromEnv()
|
|
require.Error(t, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLoadFromEnvRejectsMissingRequiredRedisAddr(t *testing.T) {
|
|
_, err := LoadFromEnv()
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "redis addr")
|
|
}
|
|
|
|
func TestLoadFromEnvRejectsInvalidRedisAddr(t *testing.T) {
|
|
t.Setenv(redisAddrEnvVar, "127.0.0.1")
|
|
|
|
_, err := LoadFromEnv()
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "redis addr")
|
|
}
|
|
|
|
func TestLoadFromEnvRejectsInvalidSMTPConfiguration(t *testing.T) {
|
|
t.Setenv(redisAddrEnvVar, "127.0.0.1:6379")
|
|
t.Setenv(smtpModeEnvVar, SMTPModeSMTP)
|
|
|
|
t.Run("missing addr", func(t *testing.T) {
|
|
t.Setenv(smtpFromEmailEnvVar, "noreply@example.com")
|
|
|
|
_, err := LoadFromEnv()
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "smtp addr")
|
|
})
|
|
|
|
t.Run("missing from email", func(t *testing.T) {
|
|
t.Setenv(smtpAddrEnvVar, "127.0.0.1:2525")
|
|
|
|
_, err := LoadFromEnv()
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "smtp from email")
|
|
})
|
|
|
|
t.Run("username without password", func(t *testing.T) {
|
|
t.Setenv(smtpAddrEnvVar, "127.0.0.1:2525")
|
|
t.Setenv(smtpFromEmailEnvVar, "noreply@example.com")
|
|
t.Setenv(smtpUsernameEnvVar, "mailer")
|
|
|
|
_, err := LoadFromEnv()
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "smtp username and password")
|
|
})
|
|
|
|
t.Run("password without username", func(t *testing.T) {
|
|
t.Setenv(smtpAddrEnvVar, "127.0.0.1:2525")
|
|
t.Setenv(smtpFromEmailEnvVar, "noreply@example.com")
|
|
t.Setenv(smtpPasswordEnvVar, "secret")
|
|
|
|
_, err := LoadFromEnv()
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "smtp username and password")
|
|
})
|
|
}
|
|
|
|
func TestLoadFromEnvRejectsNonPositiveDurationsAndCounts(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
envName string
|
|
envVal string
|
|
}{
|
|
{name: "shutdown timeout", envName: shutdownTimeoutEnvVar, envVal: "0s"},
|
|
{name: "read header timeout", envName: internalHTTPReadHeaderTimeoutEnvVar, envVal: "0s"},
|
|
{name: "read timeout", envName: internalHTTPReadTimeoutEnvVar, envVal: "0s"},
|
|
{name: "idle timeout", envName: internalHTTPIdleTimeoutEnvVar, envVal: "0s"},
|
|
{name: "redis operation timeout", envName: redisOperationTimeoutEnvVar, envVal: "0s"},
|
|
{name: "smtp timeout", envName: smtpTimeoutEnvVar, envVal: "0s"},
|
|
{name: "attempt worker concurrency", envName: attemptWorkerConcurrencyEnvVar, envVal: "0"},
|
|
{name: "stream block timeout", envName: streamBlockTimeoutEnvVar, envVal: "0s"},
|
|
{name: "operator request timeout", envName: operatorRequestTimeoutEnvVar, envVal: "0s"},
|
|
{name: "idempotency ttl", envName: idempotencyTTLEnvVar, envVal: "0s"},
|
|
{name: "delivery ttl", envName: deliveryTTLEnvVar, envVal: "0s"},
|
|
{name: "attempt ttl", envName: attemptTTLEnvVar, envVal: "0s"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Setenv(redisAddrEnvVar, "127.0.0.1:6379")
|
|
t.Setenv(tt.envName, tt.envVal)
|
|
if tt.envName == smtpTimeoutEnvVar {
|
|
t.Setenv(smtpModeEnvVar, SMTPModeSMTP)
|
|
t.Setenv(smtpAddrEnvVar, "127.0.0.1:2525")
|
|
t.Setenv(smtpFromEmailEnvVar, "noreply@example.com")
|
|
}
|
|
|
|
_, err := LoadFromEnv()
|
|
require.Error(t, err)
|
|
})
|
|
}
|
|
}
|