Ctrl K
ComunidadGuías…

internal/portforward/resolver_test.go

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

Archivo original ↗Preguntar a KiBot
package portforward

import (
	"context"
	"errors"
	"testing"

	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/intstr"
	k8sfake "k8s.io/client-go/kubernetes/fake"
	k8stesting "k8s.io/client-go/testing"
)

func service(port int32, target intstr.IntOrString, selector map[string]string) *corev1.Service {
	return &corev1.Service{
		Name: "prometheus", Namespace: "monitoring",
		Spec: corev1.ServiceSpec{
			Selector: selector,
			Ports:    []corev1.ServicePort{{Name: "http", Port: port, TargetPort: target}},
		},
	}
}

func readyPod(name string, labels map[string]string, ports []corev1.ContainerPort) *corev1.Pod {
	return &corev1.Pod{
		Name: name, Namespace: "monitoring", Labels: labels,
		Spec: corev1.PodSpec{
			Containers: []corev1.Container{{Name: "app", Ports: ports}},
		},
		Status: corev1.PodStatus{
			Phase:      corev1.PodRunning,
			Conditions: []corev1.PodCondition{{Type: corev1.PodReady, Status: corev1.ConditionTrue}},
		},
	}
}

func serviceTarget() Target {
	return Target{Kind: KindService, Namespace: "monitoring", Name: "prometheus"}
}

func TestResolvePodPassesThrough(t *testing.T) {
	resolver := NewResolver(k8sfake.NewClientset())

	pod, port, err := resolver.Resolve(context.Background(), podTarget(), 8080)
	if err != nil {
		t.Fatalf("resolve: %v", err)
	}
	if pod != "web" || port != 8080 {
		t.Fatalf("resolved %s:%d, want web:8080", pod, port)
	}
}

func TestResolveServiceWithANumericTargetPort(t *testing.T) {
	selector := map[string]string{"app": "prom"}
	cs := k8sfake.NewClientset(
		service(9090, intstr.FromInt32(9091), selector),
		readyPod("prom-0", selector, nil),
	)

	pod, port, err := NewResolver(cs).Resolve(context.Background(), serviceTarget(), 9090)
	if err != nil {
		t.Fatalf("resolve: %v", err)
	}
	if pod != "prom-0" {
		t.Fatalf("pod = %q", pod)
	}
	if port != 9091 {
		t.Fatalf("port = %d, want the numeric targetPort 9091", port)
	}
}

func TestResolveServiceWithANamedTargetPort(t *testing.T) {
	selector := map[string]string{"app": "prom"}
	cs := k8sfake.NewClientset(
		service(9090, intstr.FromString("web"), selector),
		readyPod("prom-0", selector, []corev1.ContainerPort{{Name: "web", ContainerPort: 9099}}),
	)

	_, port, err := NewResolver(cs).Resolve(context.Background(), serviceTarget(), 9090)
	if err != nil {
		t.Fatalf("resolve: %v", err)
	}
	if port != 9099 {
		t.Fatalf("port = %d, want the named port resolved to 9099", port)
	}
}

func TestResolveServiceFallsBackToTheServicePort(t *testing.T) {
	selector := map[string]string{"app": "prom"}
	cs := k8sfake.NewClientset(
		service(9090, intstr.IntOrString{}, selector),
		readyPod("prom-0", selector, nil),
	)

	_, port, err := NewResolver(cs).Resolve(context.Background(), serviceTarget(), 9090)
	if err != nil {
		t.Fatalf("resolve: %v", err)
	}
	if port != 9090 {
		t.Fatalf("port = %d, want the service port when no targetPort is set", port)
	}
}

func TestResolveServiceRejectsAnUnknownPort(t *testing.T) {
	selector := map[string]string{"app": "prom"}
	cs := k8sfake.NewClientset(
		service(9090, intstr.FromInt32(9090), selector),
		readyPod("prom-0", selector, nil),
	)

	_, _, err := NewResolver(cs).Resolve(context.Background(), serviceTarget(), 1234)

	if err == nil {
		t.Fatalf("expected an error for a port the service does not expose")
	}
}

func TestResolveServiceWithoutASelector(t *testing.T) {
	cs := k8sfake.NewClientset(service(9090, intstr.FromInt32(9090), nil))

	_, _, err := NewResolver(cs).Resolve(context.Background(), serviceTarget(), 9090)

	if err == nil {
		t.Fatalf("expected an error for a selectorless service")
	}
}

func TestResolveServiceWithNoReadyPod(t *testing.T) {
	selector := map[string]string{"app": "prom"}
	pending := readyPod("prom-0", selector, nil)
	pending.Status.Phase = corev1.PodPending
	cs := k8sfake.NewClientset(service(9090, intstr.FromInt32(9090), selector), pending)

	_, _, err := NewResolver(cs).Resolve(context.Background(), serviceTarget(), 9090)

	if err == nil {
		t.Fatalf("expected an error when no pod is running")
	}
}

func TestResolveServiceSkipsAnUnreadyPod(t *testing.T) {
	selector := map[string]string{"app": "prom"}
	unready := readyPod("prom-0", selector, nil)
	unready.Status.Conditions = []corev1.PodCondition{{Type: corev1.PodReady, Status: corev1.ConditionFalse}}
	ready := readyPod("prom-1", selector, nil)
	cs := k8sfake.NewClientset(service(9090, intstr.FromInt32(9090), selector), unready, ready)

	pod, _, err := NewResolver(cs).Resolve(context.Background(), serviceTarget(), 9090)
	if err != nil {
		t.Fatalf("resolve: %v", err)
	}
	if pod != "prom-1" {
		t.Fatalf("pod = %q, want the ready one", pod)
	}
}

func TestResolveServiceIgnoresUnrelatedConditions(t *testing.T) {
	selector := map[string]string{"app": "prom"}
	pod := readyPod("prom-0", selector, nil)
	pod.Status.Conditions = append(
		[]corev1.PodCondition{{Type: corev1.PodScheduled, Status: corev1.ConditionTrue}},
		pod.Status.Conditions...,
	)
	cs := k8sfake.NewClientset(service(9090, intstr.FromInt32(9090), selector), pod)

	got, _, err := NewResolver(cs).Resolve(context.Background(), serviceTarget(), 9090)
	if err != nil {
		t.Fatalf("resolve: %v", err)
	}
	if got != "prom-0" {
		t.Fatalf("pod = %q", got)
	}
}

func TestResolveServiceSkipsAPodWithoutAReadyCondition(t *testing.T) {
	selector := map[string]string{"app": "prom"}
	bare := readyPod("prom-0", selector, nil)
	bare.Status.Conditions = nil
	cs := k8sfake.NewClientset(service(9090, intstr.FromInt32(9090), selector), bare)

	_, _, err := NewResolver(cs).Resolve(context.Background(), serviceTarget(), 9090)

	if err == nil {
		t.Fatalf("expected an error when no pod reports readiness")
	}
}

func TestResolveServiceRejectsAMissingNamedPort(t *testing.T) {
	selector := map[string]string{"app": "prom"}
	cs := k8sfake.NewClientset(
		service(9090, intstr.FromString("missing"), selector),
		readyPod("prom-0", selector, []corev1.ContainerPort{{Name: "web", ContainerPort: 9099}}),
	)

	_, _, err := NewResolver(cs).Resolve(context.Background(), serviceTarget(), 9090)

	if err == nil {
		t.Fatalf("expected an error for a named port the pod does not declare")
	}
}

func TestResolveServiceSurfacesAGetFailure(t *testing.T) {
	cs := k8sfake.NewClientset()
	cs.PrependReactor("get", "services", func(k8stesting.Action) (bool, runtime.Object, error) {
		return true, nil, errors.New("boom")
	})

	_, _, err := NewResolver(cs).Resolve(context.Background(), serviceTarget(), 9090)

	if err == nil {
		t.Fatalf("expected the get failure to surface")
	}
}

func TestResolveServiceSurfacesAListFailure(t *testing.T) {
	selector := map[string]string{"app": "prom"}
	cs := k8sfake.NewClientset(service(9090, intstr.FromInt32(9090), selector))
	cs.PrependReactor("list", "pods", func(k8stesting.Action) (bool, runtime.Object, error) {
		return true, nil, errors.New("boom")
	})

	_, _, err := NewResolver(cs).Resolve(context.Background(), serviceTarget(), 9090)

	if err == nil {
		t.Fatalf("expected the list failure to surface")
	}
}

func TestResolveRejectsAnUnsupportedKind(t *testing.T) {
	target := Target{Kind: "Deployment", Namespace: "apps", Name: "web"}

	_, _, err := NewResolver(k8sfake.NewClientset()).Resolve(context.Background(), target, 8080)

	if err == nil {
		t.Fatalf("expected an error for an unsupported kind")
	}
}

func TestResolveServiceRejectsAnOutOfRangeTargetPort(t *testing.T) {
	selector := map[string]string{"app": "prom"}
	cs := k8sfake.NewClientset(
		service(9090, intstr.FromInt(70000), selector),
		readyPod("prom-0", selector, nil),
	)

	_, _, err := NewResolver(cs).Resolve(context.Background(), serviceTarget(), 9090)

	if err == nil {
		t.Fatalf("expected an error for a target port above 65535")
	}
}

func TestResolveServiceRejectsANegativeTargetPort(t *testing.T) {
	selector := map[string]string{"app": "prom"}
	cs := k8sfake.NewClientset(
		service(9090, intstr.FromInt(-1), selector),
		readyPod("prom-0", selector, nil),
	)

	_, _, err := NewResolver(cs).Resolve(context.Background(), serviceTarget(), 9090)

	if err == nil {
		t.Fatalf("expected an error for a negative target port")
	}
}