Ctrl K
ComunidadGuías…

internal/podcount/podcount_test.go

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

Archivo original ↗Preguntar a KiBot
package podcount

import (
	"context"
	"errors"
	"fmt"
	"testing"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	metadatafake "k8s.io/client-go/metadata/fake"
	k8stesting "k8s.io/client-go/testing"
)

func client() *metadatafake.FakeMetadataClient {
	scheme := runtime.NewScheme()
	err := metav1.AddMetaToScheme(scheme)
	if err != nil {
		panic(err)
	}
	return metadatafake.NewSimpleMetadataClient(scheme)
}

func pods(count int) []runtime.RawExtension {
	items := make([]runtime.RawExtension, 0, count)
	for i := range count {
		items = append(items, runtime.RawExtension{Object: &metav1.PartialObjectMetadata{
			Name:      fmt.Sprintf("pod-%d", i),
			Namespace: "default",
		}})
	}
	return items
}

func answerPages(
	client *metadatafake.FakeMetadataClient,
	pages [][]runtime.RawExtension,
	remaining *int64,
) *[]metav1ListCall {
	calls := &[]metav1ListCall{}
	index := 0
	client.PrependReactor("list", "pods", func(action k8stesting.Action) (bool, runtime.Object, error) {
		list, ok := action.(k8stesting.ListAction)
		if ok {
			*calls = append(*calls, metav1ListCall{fields: list.GetListRestrictions().Fields.String()})
		}
		page := pages[index]
		out := &metav1.List{Items: page}
		if index < len(pages)-1 {
			out.Continue = fmt.Sprintf("page-%d", index+1)
		}
		if index == 0 && remaining != nil {
			out.RemainingItemCount = remaining
		}
		index++
		return true, out, nil
	})
	return calls
}

type metav1ListCall struct {
	fields string
}

func TestARemainingEstimateWithoutAContinueTokenDoesNotInventPods(t *testing.T) {
	dyn := client()
	remaining := int64(41)
	answerPages(dyn, [][]runtime.RawExtension{pods(1)}, &remaining)

	got, err := Count(context.Background(), dyn, "")
	if err != nil {
		t.Fatalf("count: %v", err)
	}

	if got.Total != 1 {
		t.Fatalf("total = %d, want the item actually returned", got.Total)
	}
	if !got.Complete {
		t.Fatal("a list with no continuation was reported as partial")
	}
}

func TestANegativeRemainingCountIsIgnored(t *testing.T) {
	dyn := client()
	remaining := int64(-1)
	answerPages(dyn, [][]runtime.RawExtension{pods(1)}, &remaining)

	got, err := Count(context.Background(), dyn, "")
	if err != nil {
		t.Fatalf("count: %v", err)
	}

	if got.Total != 1 {
		t.Fatalf("total = %d, want 1", got.Total)
	}
}

func TestAFilteredCountPagesToTheEndRatherThanStoppingAtOne(t *testing.T) {
	dyn := client()
	calls := answerPages(dyn, [][]runtime.RawExtension{
		pods(500),
		pods(500),
		pods(7),
	}, nil)

	got, err := Count(context.Background(), dyn, "status.phase=Running")
	if err != nil {
		t.Fatalf("count: %v", err)
	}

	if got.Total != 1007 {
		t.Fatalf("total = %d, want every page counted rather than the first one stated as the answer", got.Total)
	}
	if !got.Complete {
		t.Fatal("a count that reached the last page said it was short")
	}
	if len(*calls) != 3 {
		t.Fatalf("list calls = %d, want one per page", len(*calls))
	}
	for at, call := range *calls {
		if call.fields != "status.phase=Running" {
			t.Fatalf("selector on call %d = %q, want it carried through the walk", at, call.fields)
		}
	}
}

func TestAnUnfilteredCountWalksWhenTheServerSizesNothing(t *testing.T) {
	dyn := client()
	calls := answerPages(dyn, [][]runtime.RawExtension{
		pods(1),
		pods(500),
		pods(7),
	}, nil)

	got, err := Count(context.Background(), dyn, "")
	if err != nil {
		t.Fatalf("count: %v", err)
	}

	if got.Total != 508 {
		t.Fatalf("total = %d, want every page counted, the probe's included", got.Total)
	}
	if !got.Complete {
		t.Fatal("a walk that reached the end was reported as partial")
	}
	if len(*calls) != 3 {
		t.Fatalf("list calls = %d, want the probe plus two pages", len(*calls))
	}
}

func TestASinglePageNeedsNoWalkAtAll(t *testing.T) {
	dyn := client()
	calls := answerPages(dyn, [][]runtime.RawExtension{pods(1)}, nil)

	got, err := Count(context.Background(), dyn, "status.phase=Failed")
	if err != nil {
		t.Fatalf("count: %v", err)
	}

	if got.Total != 1 {
		t.Fatalf("total = %d, want 1", got.Total)
	}
	if !got.Complete {
		t.Fatal("a single page was reported as partial")
	}
	if len(*calls) != 1 {
		t.Fatalf("list calls = %d, want just the probe", len(*calls))
	}
}

func TestARefusedListIsReported(t *testing.T) {
	dyn := client()
	dyn.PrependReactor("list", "pods", func(k8stesting.Action) (bool, runtime.Object, error) {
		return true, nil, errors.New("pods is forbidden")
	})

	_, err := Count(context.Background(), dyn, "")

	if err == nil {
		t.Fatal("a refused list reported success")
	}
}

func TestAPageThatFailsMidWalkIsReported(t *testing.T) {
	dyn := client()
	index := 0
	dyn.PrependReactor("list", "pods", func(k8stesting.Action) (bool, runtime.Object, error) {
		index++
		if index == 1 {
			out := &metav1.List{Items: pods(1)}
			out.SetContinue("page-1")
			return true, out, nil
		}
		return true, nil, errors.New("the continue token expired")
	})

	_, err := Count(context.Background(), dyn, "")

	if err == nil {
		t.Fatal("a failed page reported success")
	}
}

func TestARepeatedContinuationTokenIsReported(t *testing.T) {
	dyn := client()
	dyn.PrependReactor("list", "pods", func(k8stesting.Action) (bool, runtime.Object, error) {
		out := &metav1.List{Items: pods(1)}
		out.SetContinue("same")
		return true, out, nil
	})

	_, err := Count(context.Background(), dyn, "")

	if !errors.Is(err, errRepeatedContinue) {
		t.Fatalf("count error = %v, want the repeated token", err)
	}
}

func TestAnUnfilteredProbeWalksRatherThanTrustingTheServersEstimate(t *testing.T) {
	dyn := client()
	remaining := int64(4000)
	calls := answerPages(dyn, [][]runtime.RawExtension{
		pods(1),
		pods(500),
		pods(7),
	}, &remaining)

	got, err := Count(context.Background(), dyn, "")
	if err != nil {
		t.Fatalf("count: %v", err)
	}

	if got.Total != 508 {
		t.Fatalf("total = %d, want the items actually returned", got.Total)
	}
	if !got.Complete {
		t.Fatal("a walk that reached the final page was reported as partial")
	}
	if len(*calls) != 3 {
		t.Fatalf("list calls = %d, want the estimate verified through pagination", len(*calls))
	}
}

func TestAnUnfilteredWalkStopsAtTheCeilingItAdvertises(t *testing.T) {
	dyn := client()
	pages := make([][]runtime.RawExtension, 0, maxPages+5)
	pages = append(pages, pods(1))
	for range maxPages + 4 {
		pages = append(pages, pods(500))
	}
	answerPages(dyn, pages, nil)

	got, err := Count(context.Background(), dyn, "")
	if err != nil {
		t.Fatalf("count: %v", err)
	}

	if got.Complete {
		t.Fatal("a count that gave up early claimed to be complete")
	}
	if got.Total != Limit() {
		t.Fatalf("total = %d, want exactly the %d it advertises", got.Total, Limit())
	}
}