package config import ( "path/filepath" "testing" "time" ) func TestLoadUsesSafeDefaults(t *testing.T) { cfg, err := Load(emptyEnvironment) if err != nil { t.Fatalf("Load() error = %v", err) } if cfg.HTTPAddress != "127.0.0.1:8080" { t.Fatalf("HTTPAddress = %q", cfg.HTTPAddress) } if cfg.DatabasePath != filepath.FromSlash("var/cmroubao.db") { t.Fatalf("DatabasePath = %q", cfg.DatabasePath) } if cfg.AssetDirectory != filepath.FromSlash("var/assets") { t.Fatalf("AssetDirectory = %q", cfg.AssetDirectory) } if cfg.ReadHeaderTimeout <= 0 || cfg.ReadTimeout <= 0 || cfg.WriteTimeout <= 0 || cfg.IdleTimeout <= 0 || cfg.ShutdownTimeout <= 0 || cfg.MaxHeaderBytes <= 0 { t.Fatal("server safety limits must all be positive") } if cfg.ShutdownTimeout > 30*time.Second { t.Fatalf("ShutdownTimeout = %s", cfg.ShutdownTimeout) } } func TestLoadAcceptsExplicitConfiguration(t *testing.T) { values := map[string]string{ HTTPAddressEnvironment: "192.0.2.10:9090", DatabasePathEnvironment: "tmp/test.db", AssetDirectoryEnvironment: "tmp/assets", TLSCertificateEnvironment: "tmp/server.crt", TLSPrivateKeyEnvironment: "tmp/server.key", } cfg, err := Load(mapEnvironment(values)) if err != nil { t.Fatalf("Load() error = %v", err) } if cfg.HTTPAddress != values[HTTPAddressEnvironment] { t.Fatalf("HTTPAddress = %q", cfg.HTTPAddress) } if cfg.DatabasePath != filepath.Clean(values[DatabasePathEnvironment]) { t.Fatalf("DatabasePath = %q", cfg.DatabasePath) } if cfg.AssetDirectory != filepath.Clean(values[AssetDirectoryEnvironment]) { t.Fatalf("AssetDirectory = %q", cfg.AssetDirectory) } if cfg.TLSCertificate != filepath.Clean(values[TLSCertificateEnvironment]) || cfg.TLSPrivateKey != filepath.Clean(values[TLSPrivateKeyEnvironment]) { t.Fatalf( "TLS files = %q / %q", cfg.TLSCertificate, cfg.TLSPrivateKey, ) } } func TestLoadRejectsUnsafeOrInvalidValues(t *testing.T) { tests := []struct { name string values map[string]string }{ { name: "blank explicit address", values: map[string]string{ HTTPAddressEnvironment: " ", }, }, { name: "address without host", values: map[string]string{ HTTPAddressEnvironment: ":8080", }, }, { name: "invalid port", values: map[string]string{ HTTPAddressEnvironment: "127.0.0.1:70000", }, }, { name: "memory database", values: map[string]string{ DatabasePathEnvironment: ":memory:", }, }, { name: "database DSN", values: map[string]string{ DatabasePathEnvironment: "file:test.db?mode=memory", }, }, { name: "database directory", values: map[string]string{ DatabasePathEnvironment: "./", }, }, { name: "non SQLite extension", values: map[string]string{ DatabasePathEnvironment: "var/database.txt", }, }, { name: "asset root directory", values: map[string]string{ AssetDirectoryEnvironment: string(filepath.Separator), }, }, { name: "asset current directory", values: map[string]string{ AssetDirectoryEnvironment: ".", }, }, { name: "non loopback without TLS", values: map[string]string{ HTTPAddressEnvironment: "0.0.0.0:8080", }, }, { name: "TLS certificate without key", values: map[string]string{ TLSCertificateEnvironment: "tmp/server.crt", }, }, { name: "blank TLS key", values: map[string]string{ TLSCertificateEnvironment: "tmp/server.crt", TLSPrivateKeyEnvironment: " ", }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { if _, err := Load(mapEnvironment(test.values)); err == nil { t.Fatal("Load() error = nil") } }) } } func TestLoadDatabasePathIgnoresHTTPConfiguration(t *testing.T) { path, err := LoadDatabasePath(mapEnvironment(map[string]string{ HTTPAddressEnvironment: "invalid", DatabasePathEnvironment: "tmp/migration.sqlite", })) if err != nil { t.Fatalf("LoadDatabasePath() error = %v", err) } if path != filepath.Clean("tmp/migration.sqlite") { t.Fatalf("path = %q", path) } } func emptyEnvironment(string) (string, bool) { return "", false } func mapEnvironment(values map[string]string) LookupEnvironment { return func(name string) (string, bool) { value, exists := values[name] return value, exists } }