package config_test import ( "os" "path/filepath" "testing" "github.com/uopi/uopi/internal/config" ) func TestDefault(t *testing.T) { cfg := config.Default() if cfg.Server.Listen == "" { t.Error("Default Listen must not be empty") } if cfg.Server.StorageDir == "" { t.Error("Default StorageDir must not be empty") } if !cfg.Datasource.Stub.Enabled { t.Error("Stub should be enabled by default") } if !cfg.Datasource.EPICS.Enabled { t.Error("EPICS should be enabled by default") } if !cfg.Datasource.Synthetic.Enabled { t.Error("Synthetic should be enabled by default") } } func TestLoadEmptyPath(t *testing.T) { // Empty path should return defaults without error. cfg, err := config.Load("") if err != nil { t.Fatalf("Load with empty path: %v", err) } if cfg.Server.Listen != config.Default().Server.Listen { t.Errorf("Listen = %q, want default %q", cfg.Server.Listen, config.Default().Server.Listen) } } func TestLoadTOML(t *testing.T) { toml := ` [server] listen = ":9090" storage_dir = "/tmp/uopi-test" [datasource.stub] enabled = false [datasource.epics] enabled = false ca_addr_list = "192.168.1.1" ` f := filepath.Join(t.TempDir(), "uopi.toml") if err := os.WriteFile(f, []byte(toml), 0o644); err != nil { t.Fatal(err) } cfg, err := config.Load(f) if err != nil { t.Fatalf("Load: %v", err) } if cfg.Server.Listen != ":9090" { t.Errorf("Listen = %q, want :9090", cfg.Server.Listen) } if cfg.Server.StorageDir != "/tmp/uopi-test" { t.Errorf("StorageDir = %q", cfg.Server.StorageDir) } if cfg.Datasource.Stub.Enabled { t.Error("Stub.Enabled should be false") } if cfg.Datasource.EPICS.Enabled { t.Error("EPICS.Enabled should be false") } if cfg.Datasource.EPICS.CAAddrList != "192.168.1.1" { t.Errorf("CAAddrList = %q", cfg.Datasource.EPICS.CAAddrList) } } func TestLoadBadPath(t *testing.T) { _, err := config.Load("/no/such/file.toml") if err == nil { t.Error("expected error for missing file") } } func TestEnvOverrides(t *testing.T) { t.Setenv("UOPI_SERVER_LISTEN", ":7777") t.Setenv("UOPI_SERVER_STORAGE_DIR", "/env/storage") t.Setenv("UOPI_EPICS_CA_ADDR_LIST", "10.0.0.1 10.0.0.2") t.Setenv("UOPI_EPICS_ARCHIVE_URL", "http://archive/") t.Setenv("UOPI_EPICS_CHANNEL_FINDER_URL", "http://cf/") cfg, err := config.Load("") if err != nil { t.Fatalf("Load: %v", err) } if cfg.Server.Listen != ":7777" { t.Errorf("Listen = %q, want :7777", cfg.Server.Listen) } if cfg.Server.StorageDir != "/env/storage" { t.Errorf("StorageDir = %q", cfg.Server.StorageDir) } if cfg.Datasource.EPICS.CAAddrList != "10.0.0.1 10.0.0.2" { t.Errorf("CAAddrList = %q", cfg.Datasource.EPICS.CAAddrList) } if cfg.Datasource.EPICS.ArchiveURL != "http://archive/" { t.Errorf("ArchiveURL = %q", cfg.Datasource.EPICS.ArchiveURL) } if cfg.Datasource.EPICS.ChannelFinderURL != "http://cf/" { t.Errorf("ChannelFinderURL = %q", cfg.Datasource.EPICS.ChannelFinderURL) } } func TestEnvOverridesAuthTLSAndMisc(t *testing.T) { t.Setenv("UOPI_SERVER_MAX_UPDATE_RATE_HZ", "25.5") t.Setenv("UOPI_SERVER_TRUSTED_USER_HEADER", "X-Forwarded-User") t.Setenv("UOPI_SERVER_DEFAULT_USER", "svc") t.Setenv("UOPI_SERVER_KERBEROS_ENABLED", "true") t.Setenv("UOPI_SERVER_KERBEROS_KEYTAB", "/etc/krb.keytab") t.Setenv("UOPI_SERVER_KERBEROS_SERVICE_PRINCIPAL", "HTTP/host") t.Setenv("UOPI_SERVER_BASIC_AUTH_ENABLED", "YES") t.Setenv("UOPI_SERVER_BASIC_AUTH_PAM_SERVICE", "login") t.Setenv("UOPI_SERVER_TLS_ENABLED", "true") t.Setenv("UOPI_SERVER_TLS_CERT", "/c.pem") t.Setenv("UOPI_SERVER_TLS_KEY", "/k.pem") t.Setenv("UOPI_SERVER_LDAP_ENABLED", "true") t.Setenv("UOPI_SERVER_LDAP_URI", "ldaps://a ldaps://b") t.Setenv("UOPI_SERVER_LDAP_SEARCH_BASE", "dc=x,dc=y") t.Setenv("UOPI_SERVER_LDAP_BIND_DN", "cn=svc") t.Setenv("UOPI_SERVER_LDAP_BIND_PASSWORD", "secret") t.Setenv("UOPI_AUDIT_ENABLED", "true") t.Setenv("UOPI_AUDIT_DB_PATH", "/audit.db") t.Setenv("UOPI_EPICS_AUTO_SYNC_FILTER", "area=SR") t.Setenv("UOPI_EPICS_AUTO_SYNC_FROM_ARCHIVER", "true") t.Setenv("EPICS_PVA_ADDR_LIST", "10.1.1.1 10.1.1.2") t.Setenv("UOPI_UI_DEFAULT_ZOOM", "1.5") cfg, err := config.Load("") if err != nil { t.Fatalf("Load: %v", err) } if cfg.Server.MaxUpdateRateHz != 25.5 { t.Errorf("MaxUpdateRateHz = %v, want 25.5", cfg.Server.MaxUpdateRateHz) } if cfg.Server.TrustedUserHeader != "X-Forwarded-User" { t.Errorf("TrustedUserHeader = %q", cfg.Server.TrustedUserHeader) } if cfg.Server.DefaultUser != "svc" { t.Errorf("DefaultUser = %q", cfg.Server.DefaultUser) } if !cfg.Server.Kerberos.Enabled || cfg.Server.Kerberos.Keytab != "/etc/krb.keytab" || cfg.Server.Kerberos.ServicePrincipal != "HTTP/host" { t.Errorf("Kerberos = %+v", cfg.Server.Kerberos) } if !cfg.Server.BasicAuth.Enabled || cfg.Server.BasicAuth.PAMService != "login" { t.Errorf("BasicAuth = %+v", cfg.Server.BasicAuth) } if !cfg.Server.TLS.Enabled || cfg.Server.TLS.Cert != "/c.pem" || cfg.Server.TLS.Key != "/k.pem" { t.Errorf("TLS = %+v", cfg.Server.TLS) } if !cfg.Server.LDAP.Enabled || len(cfg.Server.LDAP.URIs) != 2 || cfg.Server.LDAP.SearchBase != "dc=x,dc=y" || cfg.Server.LDAP.BindDN != "cn=svc" || cfg.Server.LDAP.BindPassword != "secret" { t.Errorf("LDAP = %+v", cfg.Server.LDAP) } if !cfg.Audit.Enabled || cfg.Audit.DBPath != "/audit.db" { t.Errorf("Audit = %+v", cfg.Audit) } if cfg.Datasource.EPICS.AutoSyncFilter != "area=SR" || !cfg.Datasource.EPICS.AutoSyncFromArchiver { t.Errorf("EPICS sync = %+v", cfg.Datasource.EPICS) } if len(cfg.Datasource.PVA.AddrList) != 2 { t.Errorf("PVA AddrList = %+v", cfg.Datasource.PVA.AddrList) } if cfg.UI.DefaultZoom != 1.5 { t.Errorf("UI.DefaultZoom = %v, want 1.5", cfg.UI.DefaultZoom) } } func TestEnvInvalidNumbersIgnored(t *testing.T) { t.Setenv("UOPI_SERVER_MAX_UPDATE_RATE_HZ", "not-a-number") t.Setenv("UOPI_UI_DEFAULT_ZOOM", "xyz") cfg, err := config.Load("") if err != nil { t.Fatalf("Load: %v", err) } // Invalid floats are ignored, leaving the defaults intact. if cfg.Server.MaxUpdateRateHz != config.Default().Server.MaxUpdateRateHz { t.Errorf("invalid MaxUpdateRateHz should be ignored, got %v", cfg.Server.MaxUpdateRateHz) } if cfg.UI.DefaultZoom != config.Default().UI.DefaultZoom { t.Errorf("invalid DefaultZoom should be ignored, got %v", cfg.UI.DefaultZoom) } } func TestEnvTrimsWhitespace(t *testing.T) { t.Setenv("UOPI_SERVER_LISTEN", " :8888 ") cfg, err := config.Load("") if err != nil { t.Fatalf("Load: %v", err) } if cfg.Server.Listen != ":8888" { t.Errorf("Listen = %q, expected whitespace trimmed", cfg.Server.Listen) } }