Ctrl K
ComunidadGuías…

pkg/prune/prune_test.go

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

Archivo original ↗Preguntar a KiBot
package prune

import (
	"strings"
	"testing"

	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

func fixture() *unstructured.Unstructured {
	return &unstructured.Unstructured{Object: map[string]any{
		"metadata": map[string]any{"name": "x", "managedFields": []any{map[string]any{"manager": "kubectl"}}},
		"status": map[string]any{
			"keep":    "value",
			"heavy":   []any{map[string]any{"a": "1"}, map[string]any{"b": "2"}},
			"history": []any{map[string]any{"rev": "1", "deployedAt": "t1"}, map[string]any{"rev": "2", "deployedAt": "t2"}},
		},
	}}
}

func TestApply_DropsAndTrimsWithoutMutatingInput(t *testing.T) {
	in := fixture()
	out := Apply(in, Profile{
		Drop:      [][]string{{"metadata", "managedFields"}, {"status", "heavy"}},
		TailTrims: []TailTrim{{Path: []string{"status", "history"}, KeepField: "deployedAt"}},
	})
	if out == in {
		t.Fatalf("Apply must return a copy")
	}
	if _, found, _ := unstructured.NestedSlice(out.Object, "status", "heavy"); found {
		t.Errorf("heavy not dropped")
	}
	if v, _, _ := unstructured.NestedString(out.Object, "status", "keep"); v != "value" {
		t.Errorf("keep field lost")
	}
	hist, _, _ := unstructured.NestedSlice(out.Object, "status", "history")
	if len(hist) != 1 {
		t.Fatalf("history len = %d, want 1", len(hist))
	}
	if last, _ := hist[0].(map[string]any); last["deployedAt"] != "t2" || last["rev"] != nil {
		t.Errorf("tail trim wrong: %+v", hist[0])
	}
	// Input untouched.
	if _, found, _ := unstructured.NestedSlice(in.Object, "status", "heavy"); !found {
		t.Errorf("input mutated: heavy gone")
	}
	if orig, _, _ := unstructured.NestedSlice(in.Object, "status", "history"); len(orig) != 2 {
		t.Errorf("input mutated: history trimmed")
	}
}

func TestApply_TailTrimEdgeCases(t *testing.T) {
	// Missing slice: untouched, no panic.
	in := &unstructured.Unstructured{Object: map[string]any{"status": map[string]any{}}}
	out := Apply(in, Profile{TailTrims: []TailTrim{{Path: []string{"status", "history"}, KeepField: "deployedAt"}}})
	if _, found, _ := unstructured.NestedSlice(out.Object, "status", "history"); found {
		t.Errorf("missing slice materialized")
	}
	// Tail lacks the field: empty object survives.
	in2 := &unstructured.Unstructured{Object: map[string]any{
		"status": map[string]any{"history": []any{map[string]any{"rev": "1"}}},
	}}
	out2 := Apply(in2, Profile{TailTrims: []TailTrim{{Path: []string{"status", "history"}, KeepField: "deployedAt"}}})
	hist, _, _ := unstructured.NestedSlice(out2.Object, "status", "history")
	if len(hist) != 1 {
		t.Fatalf("want 1 entry, got %d", len(hist))
	}
	if m, _ := hist[0].(map[string]any); len(m) != 0 {
		t.Errorf("want empty object, got %+v", m)
	}
	if Apply(nil, Profile{}) != nil {
		t.Errorf("nil in, nil out")
	}
}

func TestApply_TailTrimNonMapTailLeavesSliceUntouched(t *testing.T) {
	in := &unstructured.Unstructured{Object: map[string]any{
		"status": map[string]any{"history": []any{map[string]any{"deployedAt": "t1"}, "not-a-map"}},
	}}
	out := Apply(in, Profile{TailTrims: []TailTrim{{Path: []string{"status", "history"}, KeepField: "deployedAt"}}})
	hist, _, _ := unstructured.NestedFieldNoCopy(out.Object, "status", "history")
	items, ok := hist.([]any)
	if !ok || len(items) != 2 {
		t.Fatalf("non-map tail must leave the slice untouched, got %v", hist)
	}
	if items[1] != "not-a-map" {
		t.Errorf("tail element rewritten: %v", items[1])
	}
}

func TestApply_ElementDrop(t *testing.T) {
	in := &unstructured.Unstructured{Object: map[string]any{
		"spec": map[string]any{
			"containers": []any{
				map[string]any{"name": "app", "image": "nginx:1.25", "terminationMessagePath": "/dev/tl", "livenessProbe": map[string]any{"httpGet": map[string]any{}}},
				"not-a-map",
				map[string]any{"name": "sidecar", "terminationMessagePath": "/dev/tl"},
			},
		},
	}}
	out := Apply(in, Profile{ElementDrops: []ElementDrop{
		{Path: []string{"spec", "containers"}, Keys: []string{"terminationMessagePath", "livenessProbe"}},
		{Path: []string{"spec", "initContainers"}, Keys: []string{"terminationMessagePath"}},
	}})
	containers, _, _ := unstructured.NestedFieldNoCopy(out.Object, "spec", "containers")
	items := containers.([]any)
	first := items[0].(map[string]any)
	if _, ok := first["terminationMessagePath"]; ok {
		t.Errorf("terminationMessagePath not dropped")
	}
	if _, ok := first["livenessProbe"]; ok {
		t.Errorf("livenessProbe not dropped")
	}
	if first["name"] != "app" || first["image"] != "nginx:1.25" {
		t.Errorf("kept keys damaged: %v", first)
	}
	if items[1] != "not-a-map" {
		t.Errorf("non-map element rewritten: %v", items[1])
	}
	third := items[2].(map[string]any)
	if _, ok := third["terminationMessagePath"]; ok {
		t.Errorf("later elements not processed")
	}
	// Missing path (spec.initContainers) is a silent no-op.
	if _, found, _ := unstructured.NestedFieldNoCopy(out.Object, "spec", "initContainers"); found {
		t.Errorf("missing path materialized")
	}
	// Input untouched (Apply deep-copies).
	origFirst := in.Object["spec"].(map[string]any)["containers"].([]any)[0].(map[string]any)
	if _, ok := origFirst["terminationMessagePath"]; !ok {
		t.Errorf("input mutated")
	}
}

func TestApply_ElementDropNonSlicePathUntouched(t *testing.T) {
	in := &unstructured.Unstructured{Object: map[string]any{
		"spec": map[string]any{"containers": map[string]any{"name": "not-a-slice"}},
	}}
	out := Apply(in, Profile{ElementDrops: []ElementDrop{{Path: []string{"spec", "containers"}, Keys: []string{"name"}}}})
	c, _, _ := unstructured.NestedFieldNoCopy(out.Object, "spec", "containers")
	if m, ok := c.(map[string]any); !ok || m["name"] != "not-a-slice" {
		t.Errorf("non-slice path must be left untouched, got %v", c)
	}
}

func TestApplyInPlace_EmptyPathsDoNotPanic(t *testing.T) {
	m := map[string]any{"spec": map[string]any{"keep": "value"}}
	ApplyInPlace(m, Profile{
		Drop:         [][]string{{}, nil},
		ElementDrops: []ElementDrop{{Path: nil, Keys: []string{"x"}}, {Path: []string{}, Keys: []string{"x"}}},
		TailTrims:    []TailTrim{{Path: nil, KeepField: "x"}, {Path: []string{}, KeepField: "x"}},
	})
	if m["spec"].(map[string]any)["keep"] != "value" {
		t.Errorf("empty-path ops damaged the object: %v", m)
	}
}

func TestApply_DropRunsBeforeElementDrops(t *testing.T) {
	// Drop removes the whole subtree first; ElementDrops targeting inside it
	// must fail open without rematerializing anything.
	in := &unstructured.Unstructured{Object: map[string]any{
		"spec": map[string]any{
			"template": map[string]any{
				"spec": map[string]any{"containers": []any{map[string]any{"name": "app", "junk": "x"}}},
			},
		},
	}}
	out := Apply(in, Profile{
		Drop:         [][]string{{"spec", "template"}},
		ElementDrops: []ElementDrop{{Path: []string{"spec", "template", "spec", "containers"}, Keys: []string{"junk"}}},
	})
	if _, found, _ := unstructured.NestedFieldNoCopy(out.Object, "spec", "template"); found {
		t.Errorf("dropped subtree resurrected by a later ElementDrop")
	}
}

func TestFromDropTables(t *testing.T) {
	p := FromDropTables(map[string]map[string]bool{
		"metadata":           {"uid": true},
		"spec.template.spec": {"nodeName": true, "tolerations": true},
	})
	want := [][]string{
		{"metadata", "uid"},
		{"spec", "template", "spec", "nodeName"},
		{"spec", "template", "spec", "tolerations"},
	}
	if len(p.Drop) != len(want) {
		t.Fatalf("Drop = %v, want %v", p.Drop, want)
	}
	for i := range want {
		if strings.Join(p.Drop[i], ".") != strings.Join(want[i], ".") {
			t.Errorf("Drop[%d] = %v, want %v", i, p.Drop[i], want[i])
		}
	}
}

func TestFromDropTables_PanicsOnMalformedTables(t *testing.T) {
	cases := []struct {
		name   string
		tables map[string]map[string]bool
	}{
		{"empty subtree", map[string]map[string]bool{"": {"key": true}}},
		{"empty path segment", map[string]map[string]bool{"spec..template": {"key": true}}},
		{"empty leaf key", map[string]map[string]bool{"spec": {"": true}}},
	}
	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			defer func() {
				if recover() == nil {
					t.Errorf("FromDropTables(%v) did not panic", tc.tables)
				}
			}()
			FromDropTables(tc.tables)
		})
	}
}

func TestApplyTailTrim_NonJSONScalarDoesNotPanic(t *testing.T) {
	// A hand-built map with a plain Go int in the tail element — the classic
	// trap that made the old NestedSlice path panic via DeepCopyJSONValue.
	m := map[string]any{"status": map[string]any{"history": []any{
		map[string]any{"id": 1, "deployedAt": "t1"},
		map[string]any{"id": 2, "deployedAt": "t2"},
	}}}
	ApplyInPlace(m, Profile{TailTrims: []TailTrim{{Path: []string{"status", "history"}, KeepField: "deployedAt"}}})
	hist, _, _ := unstructured.NestedSlice(m, "status", "history")
	if len(hist) != 1 {
		t.Fatalf("history len = %d, want 1", len(hist))
	}
	last, _ := hist[0].(map[string]any)
	if last["deployedAt"] != "t2" || last["id"] != nil {
		t.Errorf("trim wrong: %+v", last)
	}
}

func TestApplyTailTrim_FreshSliceNoBackingArrayRetention(t *testing.T) {
	m := map[string]any{"status": map[string]any{"history": []any{
		map[string]any{"deployedAt": "t1"}, map[string]any{"deployedAt": "t2"},
		map[string]any{"deployedAt": "t3"}, map[string]any{"deployedAt": "t4"},
	}}}
	ApplyInPlace(m, Profile{TailTrims: []TailTrim{{Path: []string{"status", "history"}, KeepField: "deployedAt"}}})
	hist, _, _ := unstructured.NestedFieldNoCopy(m, "status", "history")
	sl := hist.([]any)
	if len(sl) != 1 || cap(sl) != 1 {
		t.Errorf("trimmed slice len=%d cap=%d, want 1/1 (fresh slice, no retained backing array)", len(sl), cap(sl))
	}
}