Ctrl K
ComunidadGuías…

internal/helm/repos_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package helm

import (
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
	"time"

	"github.com/sophotechlabs/spinoza/internal/charts"
)

func writeConfig(t *testing.T, body string) string {
	t.Helper()
	path := filepath.Join(t.TempDir(), "repositories.yaml")
	err := os.WriteFile(path, []byte(body), 0o600)
	if err != nil {
		t.Fatalf("write config: %v", err)
	}
	return path
}

func TestRepositoriesReadsTheHelmConfig(t *testing.T) {
	path := writeConfig(t, `apiVersion: ""
repositories:
  - name: bitnami
    url: https://charts.bitnami.com/bitnami
  - name: private
    url: oci://ghcr.io/acme/charts
`)

	got := Repositories(path)

	if len(got) != 2 {
		t.Fatalf("repositories = %d, want 2", len(got))
	}
	if got[0].Repo.URL != "https://charts.bitnami.com/bitnami" {
		t.Fatalf("url = %q, want the bitnami index", got[0].Repo.URL)
	}
	if got[0].Name != "bitnami" {
		t.Fatalf("name = %q, want the alias helm keeps", got[0].Name)
	}
	if got[0].Repo.OCI {
		t.Fatal("an https repo was marked as oci")
	}
	if !got[1].Repo.OCI {
		t.Fatal("an oci:// repo was not marked as oci")
	}
}

func TestRepositoriesSkipsAnEntryWithNoUrl(t *testing.T) {
	path := writeConfig(t, "repositories:\n  - name: broken\n  - name: fine\n    url: https://one.example.com\n")

	got := Repositories(path)

	if len(got) != 1 {
		t.Fatalf("repositories = %d, want the one with a url", len(got))
	}
}

func TestRepositoriesIsEmptyWhenHelmWasNeverUsed(t *testing.T) {
	if len(Repositories(filepath.Join(t.TempDir(), "missing.yaml"))) != 0 {
		t.Fatal("a missing config produced repositories")
	}
	if len(Repositories("")) != 0 {
		t.Fatal("an empty path produced repositories")
	}
}

func TestRepositoriesIgnoresAConfigItCannotParse(t *testing.T) {
	path := writeConfig(t, "repositories: [this is not: valid: yaml\n")

	if len(Repositories(path)) != 0 {
		t.Fatal("a broken config produced repositories")
	}
}

func TestRepositoriesIgnoresAConfigAboveItsSizeLimit(t *testing.T) {
	body := "ignored: " + strings.Repeat("x", maxRepositoryConfigSize) + `
repositories:
  - name: too-large
    url: https://charts.example.com
`
	path := writeConfig(t, body)

	if len(Repositories(path)) != 0 {
		t.Fatal("an oversized repository config was loaded")
	}
}

func TestTheConfigPathFollowsHelmsOwnEnvironment(t *testing.T) {
	t.Setenv(repoConfigEnv, "/somewhere/repositories.yaml")

	if RepositoryConfig() != "/somewhere/repositories.yaml" {
		t.Fatalf("path = %q, want the environment's", RepositoryConfig())
	}
}

func TestTheConfigPathFollowsXdgWhenItIsSet(t *testing.T) {
	t.Setenv(repoConfigEnv, "")
	xdg := t.TempDir()
	t.Setenv("XDG_CONFIG_HOME", xdg)

	if RepositoryConfig() != filepath.Join(xdg, "helm", "repositories.yaml") {
		t.Fatalf("path = %q, want it under XDG_CONFIG_HOME", RepositoryConfig())
	}
}

func TestTheConfigPathIsWhereHelmKeepsItOnThisPlatform(t *testing.T) {
	t.Setenv(repoConfigEnv, "")
	t.Setenv("XDG_CONFIG_HOME", "")
	home := t.TempDir()
	t.Setenv("HOME", home)

	got := RepositoryConfig()

	want := filepath.Join(home, ".config", "helm", "repositories.yaml")
	if runtime.GOOS == "darwin" {
		want = filepath.Join(home, "Library", "Preferences", "helm", "repositories.yaml")
	}
	if got != want {
		t.Fatalf("path = %q, want %q", got, want)
	}
}

func TestTheConfigPathIsEmptyWithoutAHome(t *testing.T) {
	t.Setenv(repoConfigEnv, "")
	t.Setenv("XDG_CONFIG_HOME", "")
	t.Setenv("HOME", "")

	if runtime.GOOS == "darwin" || runtime.GOOS == "linux" {
		if RepositoryConfig() != "" {
			t.Fatalf("path = %q, want it empty with no home to look in", RepositoryConfig())
		}
	}
}

func TestTheRepositoryCachePathFollowsHelmsEnvironment(t *testing.T) {
	t.Setenv(repoCacheEnv, "/somewhere/repository")

	if RepositoryCache() != "/somewhere/repository" {
		t.Fatalf("path = %q, want the environment's", RepositoryCache())
	}
}

func TestTheRepositoryCachePathIsWhereHelmKeepsIt(t *testing.T) {
	t.Setenv(repoCacheEnv, "")
	t.Setenv("XDG_CACHE_HOME", "")
	home := t.TempDir()
	t.Setenv("HOME", home)

	got := RepositoryCache()

	want := filepath.Join(home, ".cache", "helm", "repository")
	if runtime.GOOS == "darwin" {
		want = filepath.Join(home, "Library", "Caches", "helm", "repository")
	}
	if got != want {
		t.Fatalf("path = %q, want %q", got, want)
	}
}

func TestTheRepositoryCachePathIsEmptyWithoutACacheHome(t *testing.T) {
	t.Setenv(repoCacheEnv, "")
	t.Setenv("XDG_CACHE_HOME", "")
	t.Setenv("HOME", "")

	if runtime.GOOS == "darwin" || runtime.GOOS == "linux" {
		if RepositoryCache() != "" {
			t.Fatalf("path = %q, want it empty with no cache home", RepositoryCache())
		}
	}
}

func TestAConfiguredRepositoryUsesHelmsCachedIndex(t *testing.T) {
	dir := t.TempDir()
	path := filepath.Join(dir, "platform-index.yaml")
	body := "entries:\n  podinfo:\n    - version: 6.15.1\n    - version: 6.14.0\n"
	writeErr := os.WriteFile(path, []byte(body), 0o600)
	if writeErr != nil {
		t.Fatalf("write cache: %v", writeErr)
	}
	index := charts.New(t.Context(), nil, time.Hour)
	repo := charts.Repo{URL: "https://charts.example.com"}

	err := SeedRepositoryCache(index, []RepoEntry{{Name: "platform", Repo: repo}}, dir)
	if err != nil {
		t.Fatalf("seed: %v", err)
	}
	versions, versionsErr := index.Versions(t.Context(), repo, "podinfo")
	if versionsErr != nil {
		t.Fatalf("versions: %v", versionsErr)
	}
	if strings.Join(versions, ",") != "6.15.1,6.14.0" {
		t.Fatalf("versions = %v, want Helm's cached versions", versions)
	}
}

func TestMissingAndOCIRepositoryCachesNeedNoIndexFile(t *testing.T) {
	index := charts.New(t.Context(), nil, time.Hour)
	repos := []RepoEntry{
		{Name: "missing", Repo: charts.Repo{URL: "https://charts.example.com"}},
		{Name: "oci", Repo: charts.Repo{URL: "oci://registry.example.com/charts", OCI: true}},
	}

	if err := SeedRepositoryCache(index, repos, t.TempDir()); err != nil {
		t.Fatalf("seed: %v", err)
	}
}

func TestSeedingNeedsAnIndexAndACacheDirectory(t *testing.T) {
	index := charts.New(t.Context(), nil, time.Hour)
	repos := []RepoEntry{{Name: "platform", Repo: charts.Repo{URL: "https://charts.example.com"}}}

	if err := SeedRepositoryCache(nil, repos, t.TempDir()); err != nil {
		t.Fatalf("nil index: %v", err)
	}
	if err := SeedRepositoryCache(index, repos, ""); err != nil {
		t.Fatalf("empty directory: %v", err)
	}
}

func TestARepositoryNameCannotEscapeTheCacheDirectory(t *testing.T) {
	index := charts.New(t.Context(), nil, time.Hour)
	repos := []RepoEntry{{Name: "../outside", Repo: charts.Repo{URL: "https://charts.example.com"}}}

	err := SeedRepositoryCache(index, repos, t.TempDir())
	if err == nil {
		t.Fatal("a repository name escaped the cache directory")
	}
	if !strings.Contains(err.Error(), "not a cache filename") {
		t.Fatalf("error = %q, want the unsafe name explained", err.Error())
	}
}

func TestABrokenRepositoryCacheIsReported(t *testing.T) {
	dir := t.TempDir()
	path := filepath.Join(dir, "broken-index.yaml")
	writeErr := os.WriteFile(path, []byte("entries: [not closed"), 0o600)
	if writeErr != nil {
		t.Fatalf("write cache: %v", writeErr)
	}
	index := charts.New(t.Context(), nil, time.Hour)
	repos := []RepoEntry{{Name: "broken", Repo: charts.Repo{URL: "https://charts.example.com"}}}

	err := SeedRepositoryCache(index, repos, dir)
	if err == nil {
		t.Fatal("a malformed cached index was ignored")
	}
	if !strings.Contains(err.Error(), path) {
		t.Fatalf("error = %q, want it to name %q", err.Error(), path)
	}
}