internal/compare/kinds_test.go
Rama main · réplica de lectura del repositorio original.
package compare
import (
"testing"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"github.com/sophotechlabs/spinoza/internal/api"
)
func deploy(namespace, name string, replicas int64) *unstructured.Unstructured {
return &unstructured.Unstructured{Object: map[string]any{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]any{
"name": name,
"namespace": namespace,
"uid": "uid-" + namespace + "-" + name,
"resourceVersion": "1",
},
"spec": map[string]any{"replicas": replicas},
"status": map[string]any{"readyReplicas": replicas},
}}
}
func verdicts(objects []api.KindDiff) map[string]string {
out := map[string]string{}
for _, object := range objects {
out[object.Namespace+"/"+object.Name] = object.Verdict
}
return out
}
func TestObjectsOnBothSidesAreComparedNotJustCounted(t *testing.T) {
left := []*unstructured.Unstructured{
deploy("prod", "web", 2),
deploy("prod", "api", 3),
}
right := []*unstructured.Unstructured{
deploy("prod", "web", 2),
deploy("prod", "api", 13),
}
found := Kinds(left, right, false, false)
got := verdicts(found)
if got["prod/web"] != api.VerdictSame {
t.Fatalf("web = %q, want same", got["prod/web"])
}
if got["prod/api"] != api.VerdictDiffers {
t.Fatalf("api = %q, want differs", got["prod/api"])
}
}
func TestTheServerSideFieldsDoNotCountAsDrift(t *testing.T) {
here := deploy("prod", "web", 2)
there := deploy("prod", "web", 2)
there.SetUID("a-different-uid")
there.SetResourceVersion("9999")
there.SetCreationTimestamp(metav1.NewTime(time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)))
_ = unstructured.SetNestedField(there.Object, int64(7), "status", "readyReplicas")
found := Kinds([]*unstructured.Unstructured{here}, []*unstructured.Unstructured{there}, false, false)
if found[0].Verdict != api.VerdictSame {
t.Fatalf("verdict = %q, want same: only what a person wrote should count", found[0].Verdict)
}
}
func TestAnObjectOnlyOneSideHasIsNamedAsSuch(t *testing.T) {
left := []*unstructured.Unstructured{deploy("prod", "web", 2), deploy("prod", "here-only", 1)}
right := []*unstructured.Unstructured{deploy("prod", "web", 2), deploy("prod", "there-only", 1)}
found := Kinds(left, right, false, false)
got := verdicts(found)
if got["prod/here-only"] != api.VerdictOnlyHere {
t.Fatalf("here-only = %q", got["prod/here-only"])
}
if got["prod/there-only"] != api.VerdictOnlyThere {
t.Fatalf("there-only = %q", got["prod/there-only"])
}
if len(found) != 3 {
t.Fatalf("objects = %d, want both sides' names once each", len(found))
}
}
func TestTheSameNameInTwoNamespacesIsTwoObjects(t *testing.T) {
left := []*unstructured.Unstructured{deploy("prod", "web", 2)}
right := []*unstructured.Unstructured{deploy("staging", "web", 2)}
found := Kinds(left, right, false, false)
if len(found) != 2 {
t.Fatalf("objects = %+v, want the namespace to keep them apart", found)
}
}
func TestNamespacesOfTheirOwnAreMatchedByNameAlone(t *testing.T) {
left := []*unstructured.Unstructured{deploy("prod", "web", 2)}
right := []*unstructured.Unstructured{deploy("staging", "web", 2)}
found := Kinds(left, right, true, false)
if len(found) != 1 {
t.Fatalf("objects = %+v, want one pair", found)
}
if found[0].Verdict != api.VerdictDiffers {
t.Fatalf("verdict = %q, want differs: the namespace itself is a difference", found[0].Verdict)
}
if found[0].Lines == 0 {
t.Fatal("a differing pair counted no lines")
}
}
func TestTheLineCountMatchesWhatChanged(t *testing.T) {
left := []*unstructured.Unstructured{deploy("prod", "web", 2)}
right := []*unstructured.Unstructured{deploy("prod", "web", 3)}
found := Kinds(left, right, false, false)
if found[0].Lines != 2 {
t.Fatalf("lines = %d, want the replicas line on each side", found[0].Lines)
}
}
func TestObjectsComeBackInAStableOrder(t *testing.T) {
left := []*unstructured.Unstructured{
deploy("prod", "web", 1),
deploy("apps", "zeta", 1),
deploy("apps", "alpha", 1),
}
found := Kinds(left, nil, false, false)
order := make([]string, 0, len(found))
for _, object := range found {
order = append(order, object.Namespace+"/"+object.Name)
}
want := []string{"apps/alpha", "apps/zeta", "prod/web"}
for i := range want {
if order[i] != want[i] {
t.Fatalf("order = %v, want %v", order, want)
}
}
}
func TestTwoEmptySidesCompareToNothing(t *testing.T) {
found := Kinds(nil, nil, false, false)
if len(found) != 0 {
t.Fatalf("objects = %+v, want none", found)
}
same, differs, onlyHere, onlyThere := Tally(found)
if same+differs+onlyHere+onlyThere != 0 {
t.Fatalf("tally = %d %d %d %d", same, differs, onlyHere, onlyThere)
}
}
func TestTheTallyCountsEachVerdict(t *testing.T) {
objects := []api.KindDiff{
{Verdict: api.VerdictSame},
{Verdict: api.VerdictSame},
{Verdict: api.VerdictDiffers},
{Verdict: api.VerdictOnlyHere},
{Verdict: api.VerdictOnlyThere},
{Verdict: "something else"},
}
same, differs, onlyHere, onlyThere := Tally(objects)
if same != 2 || differs != 1 || onlyHere != 1 || onlyThere != 1 {
t.Fatalf("tally = %d %d %d %d", same, differs, onlyHere, onlyThere)
}
}
func TestClusterScopedObjectsCompareWithoutANamespace(t *testing.T) {
here := &unstructured.Unstructured{Object: map[string]any{
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "ClusterRole",
"metadata": map[string]any{"name": "cluster-admin"},
"rules": []any{map[string]any{"verbs": []any{"*"}}},
}}
there := here.DeepCopy()
found := Kinds([]*unstructured.Unstructured{here}, []*unstructured.Unstructured{there}, false, false)
if len(found) != 1 || found[0].Verdict != api.VerdictSame {
t.Fatalf("found = %+v, want one identical cluster-scoped object", found)
}
if found[0].Namespace != "" {
t.Fatalf("namespace = %q, want none", found[0].Namespace)
}
}