package config import ( "testing" "time" ) func TestLoadRejectsMissingRequiredEnv(t *testing.T) { t.Setenv("LUCI_DATA_DIR", "/tmp/luci") t.Setenv("LUCI_REPO_ROOTS", "") t.Setenv("LUCI_HTTP_ADDR", "") t.Setenv("LUCI_BASE_URL", "") t.Setenv("LUCI_INBOX_DIR", "") t.Setenv("LUCI_PODMAN_SOCKET", "") _, err := Load() if err == nil { t.Fatal("expected missing env error") } if got := err.Error(); got != "missing required env LUCI_REPO_ROOTS" { t.Fatalf("unexpected error: %s", got) } } func TestLoadAcceptsRequiredAndOptionalEnv(t *testing.T) { t.Setenv("LUCI_DATA_DIR", "/data/ci") t.Setenv("LUCI_REPO_ROOTS", "/data/vcs/public/repos:/extra/repos") t.Setenv("LUCI_HTTP_ADDR", "127.0.0.1:8080") t.Setenv("LUCI_BASE_URL", "https://ci.example.invalid") t.Setenv("LUCI_INBOX_DIR", "/data/ci/inbox") t.Setenv("LUCI_PODMAN_SOCKET", "unix:///run/podman/podman.sock") t.Setenv("LUCI_SSH_ADDR", "127.0.0.1:2223") t.Setenv("LUCI_SSH_AUTHORIZED_KEYS", "/data/ci/authorized_keys") t.Setenv("LUCI_THEME_CSS", "/etc/luci/theme.css") t.Setenv("LUCI_DEFAULT_TIMEOUT", "30m") t.Setenv("LUCI_DEFAULT_MEMORY", "3g") t.Setenv("LUCI_DEFAULT_CPUS", "4") t.Setenv("LUCI_LOG_LEVEL", "debug") t.Setenv("LUCI_PUBLISH_REGISTRY_AUTH_FILE", "/run/secrets/registry.json") t.Setenv("LUCI_PUBLISH_PKG_ROOT", "/srv/pkg") t.Setenv("LUCI_PUBLISH_SITE_ROOT", "/srv/sites") t.Setenv("LUCI_CACHE_MAX_VERSIONS", "5") t.Setenv("LUCI_CACHE_MAX_BYTES", "2GiB") cfg, err := Load() if err != nil { t.Fatalf("Load() error = %v", err) } if cfg.DataDir != "/data/ci" { t.Fatalf("DataDir = %q", cfg.DataDir) } if len(cfg.RepoRoots) != 2 || cfg.RepoRoots[0] != "/data/vcs/public/repos" || cfg.RepoRoots[1] != "/extra/repos" { t.Fatalf("RepoRoots = %#v", cfg.RepoRoots) } if cfg.HTTPAddr != "127.0.0.1:8080" || cfg.BaseURL != "https://ci.example.invalid" { t.Fatalf("HTTP/BaseURL = %q %q", cfg.HTTPAddr, cfg.BaseURL) } if cfg.InboxDir != "/data/ci/inbox" || cfg.PodmanSocket != "unix:///run/podman/podman.sock" { t.Fatalf("Inbox/Podman = %q %q", cfg.InboxDir, cfg.PodmanSocket) } if cfg.SSHAddr != "127.0.0.1:2223" || cfg.SSHAuthorizedKeys != "/data/ci/authorized_keys" { t.Fatalf("SSH = %q %q", cfg.SSHAddr, cfg.SSHAuthorizedKeys) } if cfg.ThemeCSS != "/etc/luci/theme.css" { t.Fatalf("ThemeCSS = %q", cfg.ThemeCSS) } if cfg.DefaultTimeout != 30*time.Minute || cfg.DefaultMemory != "3g" || cfg.DefaultCPUs != "4" { t.Fatalf("defaults = %#v", cfg) } if cfg.CacheMaxVersions != 5 || cfg.CacheMaxBytes != 2<<30 { t.Fatalf("cache limits = %#v", cfg) } if cfg.PublishRegistryAuthFile != "/run/secrets/registry.json" || cfg.PublishPkgRoot != "/srv/pkg" || cfg.PublishSiteRoot != "/srv/sites" { t.Fatalf("publish env = %#v", cfg) } } func TestLoadUsesOptionalDefaultsAndSkipsEmptyRepoRoots(t *testing.T) { t.Setenv("LUCI_DATA_DIR", "/data/ci") t.Setenv("LUCI_REPO_ROOTS", " /repos::/more ") t.Setenv("LUCI_HTTP_ADDR", "127.0.0.1:8080") t.Setenv("LUCI_BASE_URL", "https://ci.example.invalid") t.Setenv("LUCI_INBOX_DIR", "/data/ci/inbox") t.Setenv("LUCI_PODMAN_SOCKET", "unix:///run/podman/podman.sock") cfg, err := Load() if err != nil { t.Fatalf("Load() error = %v", err) } if len(cfg.RepoRoots) != 2 || cfg.RepoRoots[0] != "/repos" || cfg.RepoRoots[1] != "/more" { t.Fatalf("RepoRoots = %#v", cfg.RepoRoots) } if cfg.DefaultTimeout != 20*time.Minute || cfg.DefaultMemory != "2g" || cfg.DefaultCPUs != "2" || cfg.LogLevel != "info" { t.Fatalf("defaults = %#v", cfg) } if cfg.CacheMaxVersions != 3 || cfg.CacheMaxBytes != 2<<30 { t.Fatalf("cache defaults = %#v", cfg) } if cfg.SSHAddr != "" || cfg.SSHAuthorizedKeys != "" || cfg.ThemeCSS != "" || cfg.PublishRegistryAuthFile != "" || cfg.PublishPkgRoot != "" || cfg.PublishSiteRoot != "" { t.Fatalf("optional defaults = %#v", cfg) } } func TestLoadRejectsInvalidTimeout(t *testing.T) { t.Setenv("LUCI_DATA_DIR", "/data/ci") t.Setenv("LUCI_REPO_ROOTS", "/repos") t.Setenv("LUCI_HTTP_ADDR", "127.0.0.1:8080") t.Setenv("LUCI_BASE_URL", "https://ci.example.invalid") t.Setenv("LUCI_INBOX_DIR", "/data/ci/inbox") t.Setenv("LUCI_PODMAN_SOCKET", "unix:///run/podman/podman.sock") t.Setenv("LUCI_DEFAULT_TIMEOUT", "soon") _, err := Load() if err == nil { t.Fatal("expected timeout error") } if got := err.Error(); got != "invalid LUCI_DEFAULT_TIMEOUT: time: invalid duration \"soon\"" { t.Fatalf("unexpected error: %s", got) } } func TestParseBytes(t *testing.T) { for text, want := range map[string]int64{ "1024": 1024, "1k": 1 << 10, "2KiB": 2 << 10, "1m": 1 << 20, "3MiB": 3 << 20, "1g": 1 << 30, "2GiB": 2 << 30, "1t": 1 << 40, "1TiB": 1 << 40, "512b": 512, "512B": 512, } { got, err := parseBytes(text) if err != nil || got != want { t.Fatalf("parseBytes(%q) = %d, %v; want %d", text, got, err, want) } } for _, bad := range []string{"", "soon", "-1k", "1.5g", "9999999999999999999k"} { if got, err := parseBytes(bad); err == nil { t.Fatalf("parseBytes(%q) = %d; want error", bad, got) } } } func TestLoadRejectsEachMissingRequiredEnv(t *testing.T) { required := []string{"LUCI_DATA_DIR", "LUCI_REPO_ROOTS", "LUCI_HTTP_ADDR", "LUCI_BASE_URL", "LUCI_INBOX_DIR", "LUCI_PODMAN_SOCKET"} for _, missing := range required { t.Run(missing, func(t *testing.T) { for _, name := range required { t.Setenv(name, "/x") } t.Setenv(missing, " ") _, err := Load() if err == nil || err.Error() != "missing required env "+missing { t.Fatalf("err = %v", err) } }) } }