Ctrl K
ComunidadGuías…

internal/issues/conditions_test.go

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

Archivo original ↗Preguntar a KiBot
package issues

import (
	"testing"
	"time"

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

	"github.com/sophotechlabs/spinoza/internal/api"
	"github.com/sophotechlabs/spinoza/internal/unstr"
)

func certificateDescriptor() api.ResourceDescriptor {
	return descriptor("cert-manager.io", "v1", "certificates", "Certificate")
}

func custom(kind, name string, status map[string]any) *unstructured.Unstructured {
	return &unstructured.Unstructured{Object: map[string]any{
		"apiVersion": "cert-manager.io/v1",
		"kind":       kind,
		"metadata": map[string]any{
			"name":              name,
			"namespace":         "default",
			"uid":               "uid-" + name,
			"creationTimestamp": testNow.Format(time.RFC3339),
		},
		"status": status,
	}}
}

func cachedItems(objs ...*unstructured.Unstructured) map[string][]*unstructured.Unstructured {
	return map[string][]*unstructured.Unstructured{"certificates": objs}
}

func TestACustomResourceThatIsNotReadyIsReported(t *testing.T) {
	obj := custom("Certificate", "wildcard", map[string]any{
		"conditions": []any{condition("Ready", "False", map[string]any{
			"reason":  "Failed",
			"message": "the order failed: DNS01 challenge timed out",
		})},
	})
	lister := &stubLister{
		items:  cachedItems(obj),
		cached: []api.ResourceDescriptor{certificateDescriptor()},
	}

	row, ok := rowNamed(build(t, lister, catalog()), "wildcard")
	if !ok || row.Detector != detectorCondition || row.Severity != api.SeverityMedium {
		t.Fatalf("row = %+v, want a degraded condition row", row)
	}
	if !contains(row.Detail, "DNS01 challenge") {
		t.Fatalf("detail = %q, want the condition message", row.Detail)
	}
}

func TestAnUnknownConditionIsMarkedUncertain(t *testing.T) {
	obj := custom("Certificate", "wildcard", map[string]any{
		"conditions": []any{condition("Ready", "Unknown", nil)},
	})
	lister := &stubLister{
		items:  cachedItems(obj),
		cached: []api.ResourceDescriptor{certificateDescriptor()},
	}

	row, _ := rowNamed(build(t, lister, catalog()), "wildcard")
	if !row.Uncertain {
		t.Fatalf("row = %+v, want the uncertainty stated", row)
	}
	if !contains(row.Detail, "Ready=Unknown") {
		t.Fatalf("detail = %q, want the condition spelled out", row.Detail)
	}
}

func TestAReadyCustomResourceIsNotAnIssue(t *testing.T) {
	obj := custom("Certificate", "wildcard", map[string]any{
		"conditions": []any{condition("Ready", "True", nil)},
	})
	lister := &stubLister{
		items:  cachedItems(obj),
		cached: []api.ResourceDescriptor{certificateDescriptor()},
	}

	if queue := build(t, lister, catalog()); len(queue.Rows) != 0 {
		t.Fatalf("rows = %+v, want none", queue.Rows)
	}
}

func TestANegativeConditionThatIsTrueIsReported(t *testing.T) {
	obj := custom("Certificate", "wildcard", map[string]any{
		"conditions": []any{condition("Degraded", "True", map[string]any{"reason": "Backlogged"})},
	})
	lister := &stubLister{
		items:  cachedItems(obj),
		cached: []api.ResourceDescriptor{certificateDescriptor()},
	}

	row, _ := rowNamed(build(t, lister, catalog()), "wildcard")
	if row.Title != "Backlogged" {
		t.Fatalf("row = %+v, want the negative condition reported", row)
	}
}

func TestANegativeConditionThatIsFalseIsQuiet(t *testing.T) {
	obj := custom("Certificate", "wildcard", map[string]any{
		"conditions": []any{condition("Degraded", "False", nil)},
	})
	lister := &stubLister{
		items:  cachedItems(obj),
		cached: []api.ResourceDescriptor{certificateDescriptor()},
	}

	if queue := build(t, lister, catalog()); len(queue.Rows) != 0 {
		t.Fatalf("rows = %+v, want none", queue.Rows)
	}
}

func TestAnObjectWithoutConditionsIsQuiet(t *testing.T) {
	obj := custom("Certificate", "wildcard", map[string]any{})
	lister := &stubLister{
		items:  cachedItems(obj),
		cached: []api.ResourceDescriptor{certificateDescriptor()},
	}

	if queue := build(t, lister, catalog()); len(queue.Rows) != 0 {
		t.Fatalf("rows = %+v, want none", queue.Rows)
	}
}

func TestATerminatingCustomResourceIsQuiet(t *testing.T) {
	obj := custom("Certificate", "wildcard", map[string]any{
		"conditions": []any{condition("Ready", "False", nil)},
	})
	stamp := metaNow()
	obj.SetDeletionTimestamp(&stamp)
	lister := &stubLister{
		items:  cachedItems(obj),
		cached: []api.ResourceDescriptor{certificateDescriptor()},
	}

	if queue := build(t, lister, catalog()); len(queue.Rows) != 0 {
		t.Fatalf("rows = %+v, want none", queue.Rows)
	}
}

func TestKindsWithTheirOwnDetectorAreLeftToIt(t *testing.T) {
	deployment := deploymentWith("web", map[string]any{
		"readyReplicas": int64(0),
		"conditions":    []any{condition("Available", "False", nil)},
	}, map[string]any{"replicas": int64(2)})
	lister := &stubLister{items: deploymentItems(deployment)}

	queue := build(t, lister, catalog(deploymentDescriptor()))

	if len(queue.Rows) != 1 {
		t.Fatalf("rows = %+v, want one row from the workload detector alone", queue.Rows)
	}
	if queue.Rows[0].Detector != detectorWorkload {
		t.Fatalf("detector = %q, want the workload detector", queue.Rows[0].Detector)
	}
}

func TestACachedTypeAlreadyCollectedIsNotReadTwice(t *testing.T) {
	deployment := deploymentWith("web", map[string]any{
		"readyReplicas": int64(0),
		"conditions":    []any{condition("Available", "True", nil)},
	}, map[string]any{"replicas": int64(2)})
	lister := &stubLister{
		items:  deploymentItems(deployment),
		cached: []api.ResourceDescriptor{deploymentDescriptor()},
	}

	queue := build(t, lister, catalog(deploymentDescriptor()))

	if len(queue.Rows) != 1 {
		t.Fatalf("rows = %+v, want the deployment counted once", queue.Rows)
	}
	if queue.Rows[0].Folded != 0 {
		t.Fatalf("folded = %d, want nothing folded under a single object", queue.Rows[0].Folded)
	}
}

func TestADuplicateCachedTypeIsListedOnce(t *testing.T) {
	obj := custom("Certificate", "wildcard", map[string]any{
		"conditions": []any{condition("Ready", "False", nil)},
	})
	lister := &stubLister{
		items:  cachedItems(obj),
		cached: []api.ResourceDescriptor{certificateDescriptor(), certificateDescriptor()},
	}

	if queue := build(t, lister, catalog()); len(queue.Rows) != 1 {
		t.Fatalf("rows = %+v, want one row", queue.Rows)
	}
}

func TestACustomKindThatOnlySharesANameIsStillJudged(t *testing.T) {
	obj := &unstructured.Unstructured{Object: map[string]any{
		"apiVersion": "batch.volcano.sh/v1alpha1",
		"kind":       kindJob,
		"metadata": map[string]any{
			"name":              "train",
			"namespace":         "default",
			"uid":               "uid-train",
			"creationTimestamp": testNow.Format(time.RFC3339),
		},
		"status": map[string]any{
			"conditions": []any{condition("Ready", "False", map[string]any{"reason": "Unschedulable"})},
		},
	}}
	desc := descriptor("batch.volcano.sh", "v1alpha1", "jobs", kindJob)
	lister := &stubLister{
		items:  map[string][]*unstructured.Unstructured{"jobs": {obj}},
		cached: []api.ResourceDescriptor{desc},
	}

	queue := build(t, lister, catalog())

	row, ok := rowNamed(queue, "train")
	if !ok || row.Detector != detectorCondition {
		t.Fatalf("rows = %+v, want a custom Job judged by its conditions", queue.Rows)
	}
}

func TestWhichConditionsCountAsBroken(t *testing.T) {
	cases := []struct {
		name       string
		conditions []any
		want       string
	}{
		{name: "no status at all", conditions: nil, want: ""},
		{name: "ready", conditions: []any{condition("Ready", "True", nil)}, want: ""},
		{name: "not ready", conditions: []any{condition("Ready", "False", nil)}, want: "Ready"},
		{name: "ready unknown", conditions: []any{condition("Ready", "Unknown", nil)}, want: "Ready"},
		{name: "available is read when ready is absent", conditions: []any{condition("Available", "False", nil)}, want: "Available"},
		{name: "healthy is read when the two above are absent", conditions: []any{condition("Healthy", "False", nil)}, want: "Healthy"},
		{name: "synced is read last of the positives", conditions: []any{condition("Synced", "False", nil)}, want: "Synced"},
		{
			name:       "a ready object is not judged on a later positive",
			conditions: []any{condition("Ready", "True", nil), condition("Synced", "False", nil)},
			want:       "",
		},
		{name: "stalled", conditions: []any{condition("Stalled", "True", nil)}, want: "Stalled"},
		{name: "not stalled", conditions: []any{condition("Stalled", "False", nil)}, want: ""},
		{name: "medium", conditions: []any{condition("Degraded", "True", nil)}, want: "Degraded"},
		{name: "failed", conditions: []any{condition("Failed", "True", nil)}, want: "Failed"},
		{
			name:       "a vocabulary this fallback does not know",
			conditions: []any{condition("Established", "False", nil)},
			want:       "",
		},
		{
			name:       "noise among the conditions",
			conditions: []any{"not a condition", condition("Ready", "False", nil)},
			want:       "Ready",
		},
	}

	for _, item := range cases {
		t.Run(item.name, func(t *testing.T) {
			obj := custom("Certificate", "wildcard", map[string]any{"conditions": item.conditions})
			entry, ok := badCondition(obj)
			if item.want == "" {
				if ok {
					t.Fatalf("condition = %v, want the object judged healthy", entry)
				}
				return
			}
			if !ok {
				t.Fatalf("condition = none, want %q reported", item.want)
			}
			if got := unstr.At(entry, "type"); got != item.want {
				t.Fatalf("condition = %q, want %q", got, item.want)
			}
		})
	}
}