diff --git a/cmd/cluster-kube-apiserver-operator-tests-ext/main.go b/cmd/cluster-kube-apiserver-operator-tests-ext/main.go index 023ee383db..8b0d19e6b8 100644 --- a/cmd/cluster-kube-apiserver-operator-tests-ext/main.go +++ b/cmd/cluster-kube-apiserver-operator-tests-ext/main.go @@ -19,6 +19,8 @@ import ( "k8s.io/klog/v2" "github.com/openshift/cluster-kube-apiserver-operator/pkg/version" + // Import test packages to register Ginkgo tests + _ "github.com/openshift/cluster-kube-apiserver-operator/test/e2e" ) func main() { diff --git a/go.mod b/go.mod index ef0bf3002d..1dc2130545 100644 --- a/go.mod +++ b/go.mod @@ -36,6 +36,8 @@ require ( sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96 ) +require github.com/onsi/ginkgo/v2 v2.21.0 + require ( cel.dev/expr v0.24.0 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect @@ -78,7 +80,6 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/onsi/ginkgo/v2 v2.21.0 // indirect github.com/onsi/gomega v1.35.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect diff --git a/test/e2e/bound_sa_token.go b/test/e2e/bound_sa_token.go new file mode 100644 index 0000000000..3fb18e462c --- /dev/null +++ b/test/e2e/bound_sa_token.go @@ -0,0 +1,83 @@ +package e2e + +import ( + "context" + + g "github.com/onsi/ginkgo/v2" + "github.com/stretchr/testify/require" + + authenticationv1 "k8s.io/api/authentication/v1" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + + testlibrary "github.com/openshift/cluster-kube-apiserver-operator/test/library" +) + +// TestingT is the minimal common interface that both testing.TB and +// ginkgo.GinkgoTInterface implement. This allows test functions to be +// called from both standard Go tests and Ginkgo tests. +type TestingT interface { + Errorf(format string, args ...interface{}) + FailNow() + Helper() +} + +var _ = g.Describe("[sig-api-machinery] kube-apiserver operator", func() { + g.It("[Operator][Serial] TestTokenRequestAndReview", func() { + testTokenRequestAndReview(g.GinkgoT()) + }) +}) + +// testTokenRequestAndReview checks that bound sa tokens are correctly +// configured. A token is requested via the TokenRequest API and +// validated via the TokenReview API. +func testTokenRequestAndReview(t TestingT) { + kubeConfig, err := testlibrary.NewClientConfigForTest() + require.NoError(t, err) + kubeClient, err := kubernetes.NewForConfig(kubeConfig) + require.NoError(t, err) + corev1client := kubeClient.CoreV1() + + // Create all test resources in a temp namespace that will be + // removed at the end of the test to avoid requiring explicit + // cleanup. + ns, err := corev1client.Namespaces().Create(context.TODO(), &v1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "e2e-token-request-", + }, + }, metav1.CreateOptions{}) + require.NoError(t, err) + defer func() { + err := corev1client.Namespaces().Delete(context.TODO(), ns.Name, metav1.DeleteOptions{}) + require.NoError(t, err) + }() + namespace := ns.Name + + sa, err := corev1client.ServiceAccounts(namespace).Create(context.TODO(), &v1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-service-account", + }, + }, metav1.CreateOptions{}) + require.NoError(t, err) + + treq, err := corev1client.ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), + sa.Name, + &authenticationv1.TokenRequest{ + Spec: authenticationv1.TokenRequestSpec{ + // Avoid specifying any audiences so that the token will be + // issued for the default audience of the issuer. + }, + }, + metav1.CreateOptions{}) + require.NoError(t, err) + + trev, err := kubeClient.AuthenticationV1().TokenReviews().Create(context.TODO(), &authenticationv1.TokenReview{ + Spec: authenticationv1.TokenReviewSpec{ + Token: treq.Status.Token, + }, + }, metav1.CreateOptions{}) + require.NoError(t, err) + require.Empty(t, trev.Status.Error) + require.True(t, trev.Status.Authenticated) +} diff --git a/test/e2e/bound_sa_token_test.go b/test/e2e/bound_sa_token_test.go index 74d004c980..53440e6922 100644 --- a/test/e2e/bound_sa_token_test.go +++ b/test/e2e/bound_sa_token_test.go @@ -8,13 +8,11 @@ import ( "github.com/stretchr/testify/require" - authenticationv1 "k8s.io/api/authentication/v1" corev1 "k8s.io/api/core/v1" - v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/kubernetes" + clientcorev1 "k8s.io/client-go/kubernetes/typed/core/v1" tokenctl "github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/boundsatokensignercontroller" @@ -171,52 +169,9 @@ func checkCertConfigMap(t *testing.T, kubeClient *clientcorev1.CoreV1Client, exp // TestTokenRequestAndReview checks that bound sa tokens are correctly // configured. A token is requested via the TokenRequest API and // validated via the TokenReview API. +// +// This test calls the shared testTokenRequestAndReview function which +// can be called from both standard Go tests and Ginkgo tests. func TestTokenRequestAndReview(t *testing.T) { - kubeConfig, err := testlibrary.NewClientConfigForTest() - require.NoError(t, err) - kubeClient, err := kubernetes.NewForConfig(kubeConfig) - require.NoError(t, err) - corev1client := kubeClient.CoreV1() - - // Create all test resources in a temp namespace that will be - // removed at the end of the test to avoid requiring explicit - // cleanup. - ns, err := corev1client.Namespaces().Create(context.TODO(), &v1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "e2e-token-request-", - }, - }, metav1.CreateOptions{}) - require.NoError(t, err) - defer func() { - err := corev1client.Namespaces().Delete(context.TODO(), ns.Name, metav1.DeleteOptions{}) - require.NoError(t, err) - }() - namespace := ns.Name - - sa, err := corev1client.ServiceAccounts(namespace).Create(context.TODO(), &v1.ServiceAccount{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-service-account", - }, - }, metav1.CreateOptions{}) - require.NoError(t, err) - - treq, err := corev1client.ServiceAccounts(sa.Namespace).CreateToken(context.TODO(), - sa.Name, - &authenticationv1.TokenRequest{ - Spec: authenticationv1.TokenRequestSpec{ - // Avoid specifying any audiences so that the token will be - // issued for the default audience of the issuer. - }, - }, - metav1.CreateOptions{}) - require.NoError(t, err) - - trev, err := kubeClient.AuthenticationV1().TokenReviews().Create(context.TODO(), &authenticationv1.TokenReview{ - Spec: authenticationv1.TokenReviewSpec{ - Token: treq.Status.Token, - }, - }, metav1.CreateOptions{}) - require.NoError(t, err) - require.Empty(t, trev.Status.Error) - require.True(t, trev.Status.Authenticated) + testTokenRequestAndReview(t) }