diff --git a/internal/doctor/httpprobe_test.go b/internal/doctor/httpprobe_test.go new file mode 100644 index 00000000..a417cf55 --- /dev/null +++ b/internal/doctor/httpprobe_test.go @@ -0,0 +1,37 @@ +package doctor + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" +) + +// TestHTTPProbe pins the real connectivity prober (doctor.go:648, was 0% — the +// checks inject Options.HTTPProbe in tests, so the prober the CLI actually +// ships was never exercised). Any HTTP response = reachable (nil); a dial +// failure = the "down" error; an unbuildable request = error. +func TestHTTPProbe(t *testing.T) { + t.Run("reachable host (any status) -> nil", func(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusTeapot) // non-2xx still means "connected" + })) + defer srv.Close() + if err := httpProbe(context.Background(), srv.URL); err != nil { + t.Errorf("a responding host must probe as reachable, got %v", err) + } + }) + t.Run("unreachable host -> error", func(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})) + url := srv.URL + srv.Close() // now refuses connections -> a fast Do error (not the 8s timeout) + if err := httpProbe(context.Background(), url); err == nil { + t.Error("a closed host must probe as unreachable") + } + }) + t.Run("unbuildable request -> error", func(t *testing.T) { + if err := httpProbe(context.Background(), "://not a url"); err == nil { + t.Error("an invalid URL must return the request-build error") + } + }) +} diff --git a/internal/resources/nodelarger_test.go b/internal/resources/nodelarger_test.go new file mode 100644 index 00000000..b6cdf751 --- /dev/null +++ b/internal/resources/nodelarger_test.go @@ -0,0 +1,32 @@ +package resources + +import ( + "testing" + + "k8s.io/apimachinery/pkg/api/resource" +) + +// TestNodeLarger pins set.go:99 — the equal-CPU memory tie-break that no test +// exercised (only CPU-differing nodes were compared), so LargestReadyNode's +// determinism on equal-CPU nodes was unverified. +func TestNodeLarger(t *testing.T) { + m := func(cpu, mem string) Machine { + return Machine{CPU: resource.MustParse(cpu), Mem: resource.MustParse(mem)} + } + cases := []struct { + name string + a, b Machine + want bool + }{ + {"more CPU wins", m("8", "16Gi"), m("4", "64Gi"), true}, + {"less CPU loses despite more memory", m("4", "64Gi"), m("8", "16Gi"), false}, + {"equal CPU -> more memory wins (tie-break)", m("8", "32Gi"), m("8", "16Gi"), true}, + {"equal CPU -> less memory loses", m("8", "16Gi"), m("8", "32Gi"), false}, + {"fully equal -> not larger", m("8", "16Gi"), m("8", "16Gi"), false}, + } + for _, c := range cases { + if got := nodeLarger(c.a, c.b); got != c.want { + t.Errorf("%s: nodeLarger = %v, want %v", c.name, got, c.want) + } + } +}