package config import ( "encoding/json" "os" "testing" ) // Changing defaults could be a breaking change, // if this needs to be modified to pass the test, // an item should be added to the changelog. // // This should be maintained, as it is the primary // interface between an app and the app framework. var testDefaultConfig = &AppConfig{ Environment: "development", Version: getVersion(), Logging: &LogConfig{ Enabled: true, Level: "info", Format: LogFormatJSON, Output: "stderr", TimeFormat: TimeFormatLong, }, HTTP: &HTTPConfig{ Enabled: true, Listen: "127.0.0.1:8080", LogRequests: false, ReadTimeout: "10s", WriteTimeout: "10s", IdleTimeout: "1m", }, GRPC: &GRPCConfig{ Enabled: false, Listen: "127.0.0.1:8081", LogRequests: false, EnableReflection: true, EnableInstrumentation: true, }, OTEL: &OTELConfig{ Enabled: true, PrometheusEnabled: true, PrometheusPath: "/metrics", StdoutEnabled: false, MetricIntervalSecs: 30, }, } func Test_loadConfig(t *testing.T) { type args struct { configPath string } tests := []struct { name string args args want *AppConfig wantErr bool }{ { name: "Ensure defaults", args: args{configPath: ""}, want: testDefaultConfig, wantErr: false, }, { name: "Load from file", args: args{configPath: "./testdata/config.yaml"}, want: &AppConfig{ Name: "test-app", Environment: "development", Version: getVersion(), Logging: &LogConfig{ Enabled: true, Level: "debug", Format: LogFormatJSON, Output: "stderr", TimeFormat: TimeFormatLong, }, HTTP: &HTTPConfig{ Enabled: true, Listen: "127.0.0.1:9090", LogRequests: false, ReadTimeout: "10s", WriteTimeout: "10s", IdleTimeout: "1m", }, GRPC: &GRPCConfig{ Enabled: false, Listen: "127.0.0.1:8081", LogRequests: false, EnableReflection: true, EnableInstrumentation: true, }, OTEL: &OTELConfig{ Enabled: true, PrometheusEnabled: true, PrometheusPath: "/metrics", StdoutEnabled: false, MetricIntervalSecs: 30, }, }, }, { name: "Load from env", args: args{configPath: ""}, want: &AppConfig{ Name: "test-app-env", Environment: "production", Version: getVersion(), Logging: &LogConfig{ Enabled: false, Level: "error", Format: LogFormatConsole, Output: "stdout", TimeFormat: TimeFormatUnix, }, HTTP: &HTTPConfig{ Enabled: false, Listen: "0.0.0.0:80", LogRequests: true, ReadTimeout: "15s", WriteTimeout: "15s", IdleTimeout: "2m", }, GRPC: &GRPCConfig{ Enabled: true, Listen: "0.0.0.0:443", LogRequests: true, EnableReflection: false, EnableInstrumentation: false, }, OTEL: &OTELConfig{ Enabled: false, PrometheusEnabled: false, PrometheusPath: "/metricsz", StdoutEnabled: true, MetricIntervalSecs: 60, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.name == "Load from env" { os.Setenv("APP_NAME", "test-app-env") os.Setenv("APP_ENVIRONMENT", "production") os.Setenv("APP_LOG_ENABLED", "false") os.Setenv("APP_LOG_LEVEL", "error") os.Setenv("APP_LOG_FORMAT", "console") os.Setenv("APP_LOG_OUTPUT", "stdout") os.Setenv("APP_LOG_TIME_FORMAT", "unix") os.Setenv("APP_HTTP_ENABLED", "false") os.Setenv("APP_HTTP_LISTEN", "0.0.0.0:80") os.Setenv("APP_HTTP_LOG_REQUESTS", "true") os.Setenv("APP_HTTP_READ_TIMEOUT", "15s") os.Setenv("APP_HTTP_WRITE_TIMEOUT", "15s") os.Setenv("APP_HTTP_IDLE_TIMEOUT", "2m") os.Setenv("APP_GRPC_ENABLED", "true") os.Setenv("APP_GRPC_LISTEN", "0.0.0.0:443") os.Setenv("APP_GRPC_LOG_REQUESTS", "true") os.Setenv("APP_GRPC_ENABLE_REFLECTION", "false") os.Setenv("APP_GRPC_ENABLE_INSTRUMENTATION", "false") os.Setenv("APP_OTEL_ENABLED", "false") os.Setenv("APP_OTEL_PROMETHEUS_ENABLED", "false") os.Setenv("APP_OTEL_PROMETHEUS_PATH", "/metricsz") os.Setenv("APP_OTEL_STDOUT_ENABLED", "true") os.Setenv("APP_OTEL_METRIC_INTERVAL_SECS", "60") } got, err := loadConfig(tt.args.configPath) if (err != nil) != tt.wantErr { t.Errorf("loadConfig() error = %v, wantErr %v", err, tt.wantErr) return } // Marshal both the expected and actual structs to JSON gotJSON, err := json.Marshal(got) if err != nil { t.Fatalf("Failed to marshal got to JSON: %v", err) } wantJSON, err := json.Marshal(tt.want) if err != nil { t.Fatalf("Failed to marshal want to JSON: %v", err) } // Compare the JSON strings if string(gotJSON) != string(wantJSON) { t.Errorf("loadConfig() JSON = %s, want JSON = %s", string(gotJSON), string(wantJSON)) } }) } }