internal/helm/detail_test.go
Rama main · réplica de lectura del repositorio original.
package helm
import (
"context"
"encoding/base64"
"errors"
"math"
"strconv"
"strings"
"testing"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
k8sfake "k8s.io/client-go/kubernetes/fake"
k8stesting "k8s.io/client-go/testing"
)
const manifest = `---
# Source: live-check/templates/cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: live-check
namespace: demo
data:
hello: world
---
# Source: live-check/templates/deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: live-check
namespace: demo
spec:
replicas: 1
`
func TestRevisionOrderingDoesNotOverflow(t *testing.T) {
newest := stored{revision: math.MaxInt64}
oldest := stored{revision: math.MinInt64}
if newerRevision(newest, oldest) >= 0 {
t.Fatal("the largest revision was not ordered first")
}
if newerRevision(oldest, newest) <= 0 {
t.Fatal("the smallest revision was not ordered last")
}
}
func detailPayload(spec release) string {
return `{
"name": "` + spec.name + `",
"namespace": "` + spec.namespace + `",
"version": ` + strconv.FormatInt(spec.revision, 10) + `,
"info": {
"status": "` + spec.status + `",
"first_deployed": "2026-08-01T09:00:00Z",
"last_deployed": "` + deployedAt + `",
"description": "Upgrade complete",
"notes": "Thank you for installing live-check."
},
"chart": {"metadata": {"name": "` + spec.chart + `", "version": "` + spec.version + `", "appVersion": "` + spec.appVersion + `"}},
"config": {"replicaCount": 2, "image": {"tag": "1.2.3"}},
"manifest": ` + quote(manifest) + `
}`
}
func quote(body string) string {
replaced := strings.ReplaceAll(body, "\\", "\\\\")
replaced = strings.ReplaceAll(replaced, "\"", "\\\"")
replaced = strings.ReplaceAll(replaced, "\n", "\\n")
return "\"" + replaced + "\""
}
func detailSecret(spec release) *corev1.Secret {
body := []byte(base64.StdEncoding.EncodeToString(gzipped(detailPayload(spec))))
return storedSecret(spec, body)
}
func resolver(apiVersion, kind string) (Kind, bool) {
switch {
case apiVersion == "v1" && kind == "ConfigMap":
return Kind{Version: "v1", Resource: "configmaps", Namespaced: true}, true
case apiVersion == "apps/v1" && kind == "Deployment":
return Kind{Group: "apps", Version: "v1", Resource: "deployments", Namespaced: true}, true
case apiVersion == "v1" && kind == "Namespace":
return Kind{Version: "v1", Resource: "namespaces"}, true
}
return Kind{}, false
}
func TestDetailCarriesValuesNotesAndManifest(t *testing.T) {
spec := sampleRelease()
service := newService(k8sfake.NewClientset(detailSecret(spec)), nil, nil)
got, err := service.Detail(context.Background(), "demo", "podinfo", 0, resolver)
if err != nil {
t.Fatalf("detail: %v", err)
}
if got.Release.ChartVersion != "6.9.2" {
t.Fatalf("chart version = %q, want 6.9.2", got.Release.ChartVersion)
}
if !strings.Contains(got.Values, "replicaCount: 2") {
t.Fatalf("values = %q, want the supplied values as yaml", got.Values)
}
if !strings.Contains(got.Values, "tag: 1.2.3") {
t.Fatalf("values = %q, want nested values kept", got.Values)
}
if got.Notes != "Thank you for installing live-check." {
t.Fatalf("notes = %q, want the release notes", got.Notes)
}
if !strings.Contains(got.Manifest, "kind: Deployment") {
t.Fatalf("manifest = %q, want the rendered manifest", got.Manifest)
}
if got.FirstDeployed != "2026-08-01T09:00:00Z" {
t.Fatalf("first deployed = %q, want the install time", got.FirstDeployed)
}
if got.Driver != DriverSecret {
t.Fatalf("driver = %q, want secret", got.Driver)
}
}
func TestDetailListsTheResourcesTheManifestRenders(t *testing.T) {
service := newService(k8sfake.NewClientset(detailSecret(sampleRelease())), nil, nil)
got, err := service.Detail(context.Background(), "demo", "podinfo", 0, resolver)
if err != nil {
t.Fatalf("detail: %v", err)
}
if len(got.Resources) != 2 {
t.Fatalf("resources = %d, want 2", len(got.Resources))
}
first := got.Resources[0]
if first.Kind != "ConfigMap" || first.Name != "live-check" {
t.Fatalf("first = %+v, want the ConfigMap", first)
}
if first.Resource != "configmaps" {
t.Fatalf("resource = %q, want discovery to have resolved the plural", first.Resource)
}
second := got.Resources[1]
if second.Group != "apps" || second.Resource != "deployments" {
t.Fatalf("second = %+v, want the apps/v1 deployment", second)
}
if second.Namespace != "demo" {
t.Fatalf("namespace = %q, want demo", second.Namespace)
}
}
func TestDetailLeavesAnUnknownKindUnresolved(t *testing.T) {
service := newService(k8sfake.NewClientset(detailSecret(sampleRelease())), nil, nil)
got, err := service.Detail(context.Background(), "demo", "podinfo", 0,
func(string, string) (Kind, bool) {
return Kind{}, false
})
if err != nil {
t.Fatalf("detail: %v", err)
}
if got.Resources[0].Resource != "" {
t.Fatalf("resource = %q, want it unresolved", got.Resources[0].Resource)
}
if got.Resources[0].Kind != "ConfigMap" {
t.Fatalf("kind = %q, want it still named", got.Resources[0].Kind)
}
}
func TestDetailWorksWithNoResolverAtAll(t *testing.T) {
service := newService(k8sfake.NewClientset(detailSecret(sampleRelease())), nil, nil)
got, err := service.Detail(context.Background(), "demo", "podinfo", 0, nil)
if err != nil {
t.Fatalf("detail: %v", err)
}
if len(got.Resources) != 2 {
t.Fatalf("resources = %d, want them listed even unresolved", len(got.Resources))
}
}
func TestHistoryOrdersARequestedPageNewestFirst(t *testing.T) {
first := sampleRelease()
first.revision = 1
first.status = "superseded"
first.version = "6.9.0"
second := sampleRelease()
second.revision = 2
second.status = "superseded"
second.version = "6.9.1"
third := sampleRelease()
service := newService(k8sfake.NewClientset(
detailSecret(second), detailSecret(third), detailSecret(first),
), nil, nil)
got, err := service.History(context.Background(), "demo", "podinfo", 3)
if err != nil {
t.Fatalf("history: %v", err)
}
if len(got.Revisions) != 3 {
t.Fatalf("history = %d, want the requested revisions", len(got.Revisions))
}
if got.Revisions[0].Revision != 3 || got.Revisions[2].Revision != 1 {
t.Fatalf("history = %v, want newest first", got.Revisions)
}
if got.Revisions[1].ChartVersion != "6.9.1" {
t.Fatalf("chart version = %q, want each revision's own", got.Revisions[1].ChartVersion)
}
if got.Next != 0 {
t.Fatalf("next = %d, want the end of history", got.Next)
}
}
func TestDetailRefusesAReleaseThatIsNotThere(t *testing.T) {
service := newService(k8sfake.NewClientset(), nil, nil)
_, err := service.Detail(context.Background(), "demo", "missing", 0, resolver)
if !errors.Is(err, ErrNoRelease) {
t.Fatalf("err = %v, want it to say there is no such release", err)
}
}
func TestDetailRefusesNamesThatCouldBeFlags(t *testing.T) {
service := newService(k8sfake.NewClientset(), nil, nil)
_, err := service.Detail(context.Background(), "demo", "--kubeconfig=/etc/shadow", 0, resolver)
if err == nil {
t.Fatal("a flag-shaped release name was accepted")
}
}
func TestDetailStillAnswersWhenTheNewestPayloadIsUnreadable(t *testing.T) {
spec := sampleRelease()
service := newService(k8sfake.NewClientset(storedSecret(spec, []byte("rubbish"))), nil, nil)
got, err := service.Detail(context.Background(), "demo", "podinfo", 0, resolver)
if err != nil {
t.Fatalf("detail: %v", err)
}
if got.Release.Name != "podinfo" {
t.Fatalf("name = %q, want the label's", got.Release.Name)
}
if !strings.Contains(got.Error, "could not be read") {
t.Fatalf("error = %q, want it to say the payload is unreadable", got.Error)
}
if len(got.History) != 0 {
t.Fatalf("history = %d, want history loaded separately", len(got.History))
}
history, historyErr := service.History(context.Background(), "demo", "podinfo", 3)
if historyErr != nil {
t.Fatalf("history: %v", historyErr)
}
if len(history.Revisions) != 1 {
t.Fatalf("history = %d, want the revision listed separately", len(history.Revisions))
}
if history.Revisions[0].Description != "this revision's payload could not be read" {
t.Fatalf("description = %q, want the unreadable note", history.Revisions[0].Description)
}
}
func TestDetailReportsARefusedList(t *testing.T) {
cs := k8sfake.NewClientset()
cs.PrependReactor("list", "secrets", func(k8stesting.Action) (bool, runtime.Object, error) {
return true, nil, errors.New("secrets is forbidden")
})
service := newService(cs, nil, nil)
_, err := service.Detail(context.Background(), "demo", "podinfo", 0, resolver)
if err == nil {
t.Fatal("a refused list reported success")
}
}
func TestAReleaseWithNoSuppliedValuesReadsEmpty(t *testing.T) {
spec := sampleRelease()
body := []byte(base64.StdEncoding.EncodeToString(gzipped(`{"name":"podinfo","namespace":"demo","version":3,"info":{"status":"deployed"}}`)))
service := newService(k8sfake.NewClientset(storedSecret(spec, body)), nil, nil)
got, err := service.Detail(context.Background(), "demo", "podinfo", 0, resolver)
if err != nil {
t.Fatalf("detail: %v", err)
}
if got.Values != "" {
t.Fatalf("values = %q, want nothing", got.Values)
}
if len(got.Resources) != 0 {
t.Fatalf("resources = %v, want none", got.Resources)
}
}
func TestAManifestDocumentThatIsNotAnObjectIsSkipped(t *testing.T) {
got := resourcesOf("---\njust a string\n---\napiVersion: v1\nkind: ConfigMap\nmetadata:\n name: real\n", "demo", nil)
if len(got) != 1 {
t.Fatalf("resources = %v, want only the real object", got)
}
if got[0].Name != "real" {
t.Fatalf("name = %q, want real", got[0].Name)
}
}
func TestAManifestDocumentWithNoNameIsSkipped(t *testing.T) {
got := resourcesOf("apiVersion: v1\nkind: ConfigMap\nmetadata: {}\n", "demo", nil)
if len(got) != 0 {
t.Fatalf("resources = %v, want none", got)
}
}
func TestDetailReadsAReleaseStoredInAConfigMap(t *testing.T) {
spec := sampleRelease()
entry := &corev1.ConfigMap{
Name: "sh.helm.release.v1.podinfo.v3",
Namespace: "demo",
Labels: map[string]string{
"owner": "helm", "name": "podinfo", "version": "3", "status": "deployed",
},
Data: map[string]string{releaseKey: base64.StdEncoding.EncodeToString(gzipped(detailPayload(spec)))},
}
service := newService(k8sfake.NewClientset(entry), nil, nil)
got, err := service.Detail(context.Background(), "demo", "podinfo", 0, resolver)
if err != nil {
t.Fatalf("detail: %v", err)
}
if got.Driver != DriverConfigMap {
t.Fatalf("driver = %q, want configmap", got.Driver)
}
if got.Release.ChartVersion != "6.9.2" {
t.Fatalf("chart version = %q, want the configmap payload decoded", got.Release.ChartVersion)
}
}
func TestDetailUsesTheNewestRevisionAcrossStorageDrivers(t *testing.T) {
old := sampleRelease()
old.revision = 1
newest := sampleRelease()
newest.revision = 2
newest.version = "6.9.3"
newestSecret := detailSecret(newest)
entry := &corev1.ConfigMap{
ObjectMeta: newestSecret.ObjectMeta,
Data: map[string]string{releaseKey: string(newestSecret.Data[releaseKey])},
}
service := newService(k8sfake.NewClientset(detailSecret(old), entry), nil, nil)
got, err := service.Detail(context.Background(), "demo", "podinfo", 0, resolver)
if err != nil {
t.Fatalf("detail: %v", err)
}
if got.Driver != DriverConfigMap || got.Release.Revision != 2 {
t.Fatalf("detail = %+v, want configmap revision 2", got)
}
if got.Release.ChartVersion != "6.9.3" {
t.Fatalf("chart version = %q, want the newest payload", got.Release.ChartVersion)
}
}
func TestANamespacedResourceInheritsTheReleaseNamespace(t *testing.T) {
manifest := "apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: live-check\n"
got := resourcesOf(manifest, "helm-live", resolver)
if len(got) != 1 {
t.Fatalf("resources = %v, want one", got)
}
if got[0].Namespace != "helm-live" {
t.Fatalf("namespace = %q, want the release's, since helm renders none", got[0].Namespace)
}
}
func TestAResourceKeepsTheNamespaceTheManifestGave(t *testing.T) {
manifest := "apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: cm\n namespace: elsewhere\n"
got := resourcesOf(manifest, "helm-live", resolver)
if got[0].Namespace != "elsewhere" {
t.Fatalf("namespace = %q, want the manifest's own", got[0].Namespace)
}
}
func TestAClusterScopedResourceGetsNoNamespace(t *testing.T) {
manifest := "apiVersion: v1\nkind: Namespace\nmetadata:\n name: made-by-chart\n"
got := resourcesOf(manifest, "helm-live", resolver)
if got[0].Namespace != "" {
t.Fatalf("namespace = %q, want none for a cluster-scoped kind", got[0].Namespace)
}
}
func TestAnUnresolvedKindIsLeftWithoutANamespace(t *testing.T) {
manifest := "apiVersion: acme.io/v1\nkind: Widget\nmetadata:\n name: thing\n"
got := resourcesOf(manifest, "helm-live", resolver)
if got[0].Namespace != "" {
t.Fatalf("namespace = %q, want none when the kind is unknown", got[0].Namespace)
}
}