Luigit
repositories / bugabinga.net

bugabinga.net

personal infrastructure for bugabinga!

owned by admin

services/luci/internal/config/config_test.go

Raw
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)
			}
		})
	}
}