diff --git a/pkg/controlplane/apiserver/options/options_test.go b/pkg/controlplane/apiserver/options/options_test.go index 4f202860842..71d74314545 100644 --- a/pkg/controlplane/apiserver/options/options_test.go +++ b/pkg/controlplane/apiserver/options/options_test.go @@ -32,6 +32,7 @@ import ( "github.com/google/go-cmp/cmp/cmpopts" "github.com/spf13/pflag" noopoteltrace "go.opentelemetry.io/otel/trace/noop" + utilnettesting "k8s.io/apimachinery/pkg/util/net/testing" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apiserver/pkg/admission" apiserveroptions "k8s.io/apiserver/pkg/server/options" @@ -483,7 +484,7 @@ func TestCompleteForServiceAccount(t *testing.T) { options := NewOptions() if tc.externalSigner { // create and start mock signer. - socketPath := fmt.Sprintf("@mock-external-jwt-signer-%d.sock", time.Now().Nanosecond()) + socketPath := utilnettesting.MakeSocketNameForTest(t, fmt.Sprintf("mock-external-jwt-signer-%d.sock", time.Now().Nanosecond())) mockSigner := v1alpha1testing.NewMockSigner(t, socketPath) defer mockSigner.CleanUp() diff --git a/pkg/serviceaccount/externaljwt/plugin/keycache_test.go b/pkg/serviceaccount/externaljwt/plugin/keycache_test.go index 710e0741159..06da6067a1c 100644 --- a/pkg/serviceaccount/externaljwt/plugin/keycache_test.go +++ b/pkg/serviceaccount/externaljwt/plugin/keycache_test.go @@ -20,7 +20,6 @@ import ( "context" "fmt" "net" - "os" "strings" "sync/atomic" "testing" @@ -35,6 +34,8 @@ import ( "k8s.io/apimachinery/pkg/util/wait" externaljwtv1alpha1 "k8s.io/externaljwt/apis/v1alpha1" "k8s.io/kubernetes/pkg/serviceaccount" + + utilnettesting "k8s.io/apimachinery/pkg/util/net/testing" ) func TestExternalPublicKeyGetter(t *testing.T) { @@ -169,8 +170,7 @@ func TestExternalPublicKeyGetter(t *testing.T) { t.Run(tc.desc, func(t *testing.T) { ctx := context.Background() - sockname := fmt.Sprintf("@test-external-public-key-getter-%d-%d.sock", time.Now().Nanosecond(), i) - t.Cleanup(func() { _ = os.Remove(sockname) }) + sockname := utilnettesting.MakeSocketNameForTest(t, fmt.Sprintf("test-external-public-key-getter-%d-%d.sock", time.Now().Nanosecond(), i)) addr := &net.UnixAddr{Name: sockname, Net: "unix"} listener, err := net.ListenUnix(addr.Network(), addr) @@ -240,8 +240,7 @@ func TestExternalPublicKeyGetter(t *testing.T) { func TestInitialFill(t *testing.T) { ctx := context.Background() - sockname := fmt.Sprintf("@test-initial-fill-%d.sock", time.Now().Nanosecond()) - t.Cleanup(func() { _ = os.Remove(sockname) }) + sockname := utilnettesting.MakeSocketNameForTest(t, fmt.Sprintf("test-initial-fill-%d.sock", time.Now().Nanosecond())) addr := &net.UnixAddr{Name: sockname, Net: "unix"} listener, err := net.ListenUnix(addr.Network(), addr) @@ -306,8 +305,7 @@ func TestInitialFill(t *testing.T) { func TestReflectChanges(t *testing.T) { ctx := context.Background() - sockname := fmt.Sprintf("@test-reflect-changes-%d.sock", time.Now().Nanosecond()) - t.Cleanup(func() { _ = os.Remove(sockname) }) + sockname := utilnettesting.MakeSocketNameForTest(t, fmt.Sprintf("test-reflect-changes-%d.sock", time.Now().Nanosecond())) addr := &net.UnixAddr{Name: sockname, Net: "unix"} listener, err := net.ListenUnix(addr.Network(), addr) diff --git a/pkg/serviceaccount/externaljwt/plugin/plugin_test.go b/pkg/serviceaccount/externaljwt/plugin/plugin_test.go index bbb62f29348..04f3700b859 100644 --- a/pkg/serviceaccount/externaljwt/plugin/plugin_test.go +++ b/pkg/serviceaccount/externaljwt/plugin/plugin_test.go @@ -25,7 +25,6 @@ import ( "encoding/json" "fmt" "net" - "os" "strings" "sync" "testing" @@ -39,6 +38,7 @@ import ( "k8s.io/kubernetes/pkg/serviceaccount" + utilnettesting "k8s.io/apimachinery/pkg/util/net/testing" externaljwtv1alpha1 "k8s.io/externaljwt/apis/v1alpha1" ) @@ -258,8 +258,7 @@ func TestExternalTokenGenerator(t *testing.T) { t.Run(tc.desc, func(t *testing.T) { ctx := context.Background() - sockname := fmt.Sprintf("@test-external-token-generator-%d-%d.sock", time.Now().Nanosecond(), i) - t.Cleanup(func() { _ = os.Remove(sockname) }) + sockname := utilnettesting.MakeSocketNameForTest(t, fmt.Sprintf("test-external-token-generator-%d-%d.sock", time.Now().Nanosecond(), i)) addr := &net.UnixAddr{Name: sockname, Net: "unix"} listener, err := net.ListenUnix(addr.Network(), addr) diff --git a/staging/src/k8s.io/apimachinery/pkg/util/net/testing/socket.go b/staging/src/k8s.io/apimachinery/pkg/util/net/testing/socket.go new file mode 100644 index 00000000000..4bf868aac8b --- /dev/null +++ b/staging/src/k8s.io/apimachinery/pkg/util/net/testing/socket.go @@ -0,0 +1,41 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package nettesting contains utilities for testing networking functionality. +// Don't use these utilities in production code. They have not been security +// reviewed. +package nettesting + +import ( + "os" + goruntime "runtime" + "testing" +) + +// MakeSocketNameForTest returns a socket name to use for the duration of a test. +// On Operating systems that support abstract sockets, it the name is prefixed with `@` to make it an abstract socket. +// On Operating systems that do not support abstract sockets, the name is treated as a filename and a cleanup hook is +// registered to delete the socket at the end of the test. +func MakeSocketNameForTest(t testing.TB, name string) string { + var sockname = name + switch goruntime.GOOS { + case "darwin", "windows": + t.Cleanup(func() { _ = os.Remove(sockname) }) + default: + sockname = "@" + name + } + return sockname +} diff --git a/test/integration/serviceaccount/external_jwt_signer_test.go b/test/integration/serviceaccount/external_jwt_signer_test.go index ce3efa74215..fdccdd988b8 100644 --- a/test/integration/serviceaccount/external_jwt_signer_test.go +++ b/test/integration/serviceaccount/external_jwt_signer_test.go @@ -30,6 +30,7 @@ import ( authv1 "k8s.io/api/authentication/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + utilnettesting "k8s.io/apimachinery/pkg/util/net/testing" "k8s.io/apimachinery/pkg/util/wait" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/client-go/kubernetes" @@ -61,7 +62,7 @@ func TestExternalJWTSigningAndAuth(t *testing.T) { defer cancel() // create and start mock signer. - socketPath := fmt.Sprintf("@mock-external-jwt-signer-%d.sock", time.Now().Nanosecond()) + socketPath := utilnettesting.MakeSocketNameForTest(t, fmt.Sprintf("mock-external-jwt-signer-%d.sock", time.Now().Nanosecond())) t.Cleanup(func() { _ = os.Remove(socketPath) }) mockSigner := v1alpha1testing.NewMockSigner(t, socketPath) defer mockSigner.CleanUp() @@ -277,7 +278,7 @@ func TestDelayedStartForSigner(t *testing.T) { defer cancel() // Schedule signer to start on socket after 20 sec - socketPath := "@mock-external-jwt-signer.sock" + socketPath := utilnettesting.MakeSocketNameForTest(t, "mock-external-jwt-signer.sock") t.Cleanup(func() { _ = os.Remove(socketPath) }) go func() { time.Sleep(20 * time.Second)