/* Copyright 2022 The Karmada 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 util import ( "bytes" "context" "encoding/pem" "io" "net/http" "net/http/httptest" "testing" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/client-go/rest" controllerruntime "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake" clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" "github.com/karmada-io/karmada/pkg/util/gclient" ) // Generated by // // openssl genrsa 2048 > ca.key // openssl req -new -x509 -nodes -days 365000 -key ca.key -out ca.crt var testCA = []byte(`-----BEGIN CERTIFICATE----- MIIDlTCCAn2gAwIBAgIULtNqpv91jFAqaYIcKC3+2B3PalwwDQYJKoZIhvcNAQEL BQAwWTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJMTI3LjAuMC4xMCAX DTI1MDEyNzA5NTAzMFoYDzMwMjQwNTMwMDk1MDMwWjBZMQswCQYDVQQGEwJBVTET MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ dHkgTHRkMRIwEAYDVQQDDAkxMjcuMC4wLjEwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDBMshenKkdcJPzAiIcbSjbtoNppdMvOQoEY+EAwz2xZf1cYuJN 86roVXb+YI7NEN1IZcP2T1BJR4/l1QS9AC2bhssss6ANEsQRKFbL+F71GWvrD8SU nqsEgtceZkMWahFALgFZ5msBdHlibtmiqZEt7vXiHGK5hVVpdWLHBR6vYcxpzH0g wSnGTz0Y1vkN/vZ/sS/NPQnfrDMwmF7M5z/Y5HtWQYeKklYnjUS5bcmXWU1Cal2Q DSZwhgdr/BfmtsBG8PXu/0T2DchQi6UwO6S2yLeVN6QOdgC6GRO80L4M4t7h3BoB WI5BrUIHiqnIPkKCk46WgdjXGhi0r5a1MqE7AgMBAAGjUzBRMB0GA1UdDgQWBBQa I7a0H4qe70U2kEW/XpiqXG+diDAfBgNVHSMEGDAWgBQaI7a0H4qe70U2kEW/Xpiq XG+diDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAlGvFxY8zI yT+YUHQ0Kbg6EKeXf/t36dMKA+cmWSkBK26q4rBu1M8SoICbLpkjtvDsxGgylOll HfCM08wFDELnJdAIKKcqXqP9tMG9RoUBxKIh1dmTHBAOpAN+RXCYHwiFNLTFLbQI GsZ3Cl3vF5RBzkFHGE/fV1m6y1+DUOGAn2meQVZR5epW5aU+fd7eodhF9ck9hfHW qpUIgHpXjWb1Lb6w2Y19eK/4kkMTlcj/XWmQfgXFgVUANUsCDIu/ftoYY9eO6ymu qS+QTm6FNs0/71qf9muggh4jLnCjlXd9/aCQNPZ7p/m3Te9tpVQaEkTtu8Qe4g1j nQi8/QKAuCtv -----END CERTIFICATE-----`) func TestNewClusterScaleClientSet(t *testing.T) { type args struct { clusterName string client client.Client } tests := []struct { name string args args wantErr bool errMsg string }{ { name: "cluster not found", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).Build(), }, wantErr: true, errMsg: "clusters.cluster.karmada.io \"test\" not found", }, { name: "APIEndpoint is empty", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()). WithObjects(newCluster("test")).Build(), }, wantErr: true, errMsg: "the api endpoint of cluster test is empty", }, { name: "SecretRef is empty", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()). WithObjects(withAPIEndPoint(newCluster("test"), "https://127.0.0.1")).Build(), }, wantErr: true, errMsg: "cluster test does not have a secret", }, { name: "Secret not found", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: clusterv1alpha1.ClusterSpec{ APIEndpoint: "https://127.0.0.1", SecretRef: &clusterv1alpha1.LocalSecretReference{Namespace: "default", Name: "secret1"}, }, }).Build(), }, wantErr: true, errMsg: "secrets \"secret1\" not found", }, { name: "token not found", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: clusterv1alpha1.ClusterSpec{ APIEndpoint: "https://127.0.0.1", SecretRef: &clusterv1alpha1.LocalSecretReference{Namespace: "ns1", Name: "secret1"}, }, }, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{Namespace: "ns1", Name: "secret1"}, }).Build(), }, wantErr: true, errMsg: "the secret for cluster test is missing a non-empty value for \"token\"", }, { name: "valid configuration", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: clusterv1alpha1.ClusterSpec{ APIEndpoint: "https://127.0.0.1", SecretRef: &clusterv1alpha1.LocalSecretReference{Namespace: "ns1", Name: "secret1"}, }, }, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{Namespace: "ns1", Name: "secret1"}, Data: map[string][]byte{clusterv1alpha1.SecretTokenKey: []byte("token"), clusterv1alpha1.SecretCADataKey: testCA}, }).Build(), }, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := NewClusterScaleClientSet(tt.args.clusterName, tt.args.client) if tt.wantErr { assert.Error(t, err) assert.Nil(t, got) assert.Contains(t, err.Error(), tt.errMsg) } else { assert.NoError(t, err) assert.NotNil(t, got) assert.Equal(t, tt.args.clusterName, got.ClusterName) assert.NotNil(t, got.KubeClient) assert.NotNil(t, got.ScaleClient) } }) } } func TestNewClusterClientSetForAgent(t *testing.T) { type args struct { clusterName string client client.Client clientOption *ClientOption } tests := []struct { name string args args wantErr bool }{ { name: "valid configuration", args: args{ clusterName: "test-agent", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).Build(), clientOption: &ClientOption{QPS: 100, Burst: 200}, }, wantErr: false, }, } // Store the original GetConfig function originalGetConfig := controllerruntime.GetConfig // Defer its restoration defer func() { controllerruntime.GetConfig = originalGetConfig }() // Mock the GetConfig function controllerruntime.GetConfig = func() (*rest.Config, error) { return &rest.Config{ Host: "https://fake.example.com", }, nil } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := NewClusterClientSetForAgent(tt.args.clusterName, tt.args.client, tt.args.clientOption) if tt.wantErr { assert.Error(t, err) assert.Nil(t, got) } else { assert.NoError(t, err) assert.NotNil(t, got) assert.Equal(t, tt.args.clusterName, got.ClusterName) assert.NotNil(t, got.KubeClient) } }) } } func TestNewClusterDynamicClientSetForAgent(t *testing.T) { type args struct { clusterName string client client.Client } tests := []struct { name string args args wantErr bool }{ { name: "valid configuration", args: args{ clusterName: "test-agent-dynamic", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).Build(), }, wantErr: false, }, } // Store the original GetConfig function originalGetConfig := controllerruntime.GetConfig // Defer its restoration defer func() { controllerruntime.GetConfig = originalGetConfig }() // Mock the GetConfig function controllerruntime.GetConfig = func() (*rest.Config, error) { return &rest.Config{ Host: "https://fake.example.com", }, nil } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := NewClusterDynamicClientSetForAgent(tt.args.clusterName, tt.args.client) if tt.wantErr { assert.Error(t, err) assert.Nil(t, got) } else { assert.NoError(t, err) assert.NotNil(t, got) assert.Equal(t, tt.args.clusterName, got.ClusterName) assert.NotNil(t, got.DynamicClientSet) } }) } } func TestNewClusterClientSet(t *testing.T) { type args struct { clusterName string client client.Client clientOption *ClientOption } tests := []struct { name string args args wantErr bool }{ { name: "cluster not found", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).Build(), clientOption: nil, }, wantErr: true, }, { name: "APIEndpoint is empty", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()). WithObjects(newCluster("test")).Build(), clientOption: nil, }, wantErr: true, }, { name: "SecretRef is empty", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()). WithObjects(withAPIEndPoint(newCluster("test"), "https://127.0.0.1")).Build(), clientOption: nil, }, wantErr: true, }, { name: "Secret not found", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: clusterv1alpha1.ClusterSpec{ APIEndpoint: "https://127.0.0.1", SecretRef: &clusterv1alpha1.LocalSecretReference{Namespace: "default", Name: "secret1"}, }, }).Build(), clientOption: nil, }, wantErr: true, }, { name: "token not found", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: clusterv1alpha1.ClusterSpec{ APIEndpoint: "https://127.0.0.1", SecretRef: &clusterv1alpha1.LocalSecretReference{Namespace: "ns1", Name: "secret1"}, }, }, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{Namespace: "ns1", Name: "secret1"}, }).Build(), clientOption: nil, }, wantErr: true, }, { name: "CA data is set", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: clusterv1alpha1.ClusterSpec{ APIEndpoint: "https://127.0.0.1", SecretRef: &clusterv1alpha1.LocalSecretReference{Namespace: "ns1", Name: "secret1"}, }, }, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{Namespace: "ns1", Name: "secret1"}, Data: map[string][]byte{clusterv1alpha1.SecretTokenKey: []byte("token"), clusterv1alpha1.SecretCADataKey: testCA}, }).Build(), clientOption: &ClientOption{QPS: 100, Burst: 200}, }, wantErr: false, }, { name: "skip TLS verification", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: clusterv1alpha1.ClusterSpec{ APIEndpoint: "https://127.0.0.1", SecretRef: &clusterv1alpha1.LocalSecretReference{Namespace: "ns1", Name: "secret1"}, InsecureSkipTLSVerification: true, }, }, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{Namespace: "ns1", Name: "secret1"}, Data: map[string][]byte{clusterv1alpha1.SecretTokenKey: []byte("token")}, }).Build(), clientOption: &ClientOption{QPS: 100, Burst: 200}, }, wantErr: false, }, { name: "ProxyURL is error", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: clusterv1alpha1.ClusterSpec{ APIEndpoint: "https://127.0.0.1", SecretRef: &clusterv1alpha1.LocalSecretReference{Namespace: "ns1", Name: "secret1"}, ProxyURL: "://", }, }, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{Namespace: "ns1", Name: "secret1"}, Data: map[string][]byte{clusterv1alpha1.SecretTokenKey: []byte("token"), clusterv1alpha1.SecretCADataKey: testCA}}).Build(), clientOption: &ClientOption{QPS: 100, Burst: 200}, }, wantErr: true, }, { name: "ProxyURL is set", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: clusterv1alpha1.ClusterSpec{ APIEndpoint: "https://127.0.0.1", SecretRef: &clusterv1alpha1.LocalSecretReference{Namespace: "ns1", Name: "secret1"}, ProxyURL: "http://1.1.1.1", }, }, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{Namespace: "ns1", Name: "secret1"}, Data: map[string][]byte{clusterv1alpha1.SecretTokenKey: []byte("token"), clusterv1alpha1.SecretCADataKey: testCA}, }).Build(), clientOption: &ClientOption{QPS: 100, Burst: 200}, }, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := NewClusterClientSet(tt.args.clusterName, tt.args.client, tt.args.clientOption) if tt.wantErr { assert.Error(t, err) assert.Nil(t, got) } else { assert.NoError(t, err) assert.NotNil(t, got) assert.Equal(t, tt.args.clusterName, got.ClusterName) assert.NotNil(t, got.KubeClient) } }) } } func TestNewClusterClientSet_ClientWorks(t *testing.T) { s := httptest.NewTLSServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { rw.Header().Add("Content-Type", "application/json") _, _ = io.WriteString(rw, ` { "apiVersion": "v1", "kind": "Node", "metadata": { "name": "foo" } }`) })) defer s.Close() testCA := getCACertFromGTestServer(t, s) const clusterName = "test" hostClient := fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: clusterName}, Spec: clusterv1alpha1.ClusterSpec{ APIEndpoint: s.URL, SecretRef: &clusterv1alpha1.LocalSecretReference{Namespace: "ns1", Name: "secret1"}, }, }, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{Namespace: "ns1", Name: "secret1"}, Data: map[string][]byte{clusterv1alpha1.SecretTokenKey: []byte("token"), clusterv1alpha1.SecretCADataKey: testCA}, }).Build() clusterClient, err := NewClusterClientSet(clusterName, hostClient, nil) assert.NoError(t, err) assert.NotNil(t, clusterClient) got, err := clusterClient.KubeClient.CoreV1().Nodes().Get(context.TODO(), "foo", metav1.GetOptions{}) assert.NoError(t, err) assert.NotNil(t, got) want := &corev1.Node{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", }, } assert.Equal(t, want, got) } func TestNewClusterDynamicClientSet(t *testing.T) { type args struct { clusterName string client client.Client } tests := []struct { name string args args wantErr bool }{ { name: "cluster not found", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).Build(), }, wantErr: true, }, { name: "APIEndpoint is empty", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()). WithObjects(newCluster("test")).Build(), }, wantErr: true, }, { name: "SecretRef is empty", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()). WithObjects(withAPIEndPoint(newCluster("test"), "https://127.0.0.1")).Build(), }, wantErr: true, }, { name: "Secret not found", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: clusterv1alpha1.ClusterSpec{ APIEndpoint: "https://127.0.0.1", SecretRef: &clusterv1alpha1.LocalSecretReference{Namespace: "default", Name: "secret1"}, }, }).Build(), }, wantErr: true, }, { name: "token not found", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: clusterv1alpha1.ClusterSpec{ APIEndpoint: "https://127.0.0.1", SecretRef: &clusterv1alpha1.LocalSecretReference{Namespace: "ns1", Name: "secret1"}, }, }, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{Namespace: "ns1", Name: "secret1"}, }).Build(), }, wantErr: true, }, { name: "CA data is set", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: clusterv1alpha1.ClusterSpec{ APIEndpoint: "https://127.0.0.1", SecretRef: &clusterv1alpha1.LocalSecretReference{Namespace: "ns1", Name: "secret1"}, }, }, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{Namespace: "ns1", Name: "secret1"}, Data: map[string][]byte{clusterv1alpha1.SecretTokenKey: []byte("token"), clusterv1alpha1.SecretCADataKey: testCA}, }).Build(), }, wantErr: false, }, { name: "skip TLS verification", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: clusterv1alpha1.ClusterSpec{ APIEndpoint: "https://127.0.0.1", SecretRef: &clusterv1alpha1.LocalSecretReference{Namespace: "ns1", Name: "secret1"}, }, }, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{Namespace: "ns1", Name: "secret1"}, Data: map[string][]byte{clusterv1alpha1.SecretTokenKey: []byte("token"), clusterv1alpha1.SecretCADataKey: testCA}, }).Build(), }, wantErr: false, }, { name: "ProxyURL is error", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: clusterv1alpha1.ClusterSpec{ APIEndpoint: "https://127.0.0.1", SecretRef: &clusterv1alpha1.LocalSecretReference{Namespace: "ns1", Name: "secret1"}, ProxyURL: "://", }, }, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{Namespace: "ns1", Name: "secret1"}, Data: map[string][]byte{clusterv1alpha1.SecretTokenKey: []byte("token"), clusterv1alpha1.SecretCADataKey: testCA}, }).Build(), }, wantErr: true, }, { name: "ProxyURL is set", args: args{ clusterName: "test", client: fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: clusterv1alpha1.ClusterSpec{ APIEndpoint: "https://127.0.0.1", SecretRef: &clusterv1alpha1.LocalSecretReference{Namespace: "ns1", Name: "secret1"}, ProxyURL: "http://1.1.1.1", }, }, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{Namespace: "ns1", Name: "secret1"}, Data: map[string][]byte{clusterv1alpha1.SecretTokenKey: []byte("token"), clusterv1alpha1.SecretCADataKey: testCA}, }).Build(), }, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := NewClusterDynamicClientSet(tt.args.clusterName, tt.args.client) if tt.wantErr { assert.Error(t, err) assert.Nil(t, got) } else { assert.NoError(t, err) assert.NotNil(t, got) assert.Equal(t, tt.args.clusterName, got.ClusterName) assert.NotNil(t, got.DynamicClientSet) } }) } } func TestNewClusterDynamicClientSet_ClientWorks(t *testing.T) { s := httptest.NewTLSServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { rw.Header().Add("Content-Type", "application/json") _, _ = io.WriteString(rw, ` { "apiVersion": "v1", "kind": "Node", "metadata": { "name": "foo" } }`) })) defer s.Close() testCA := getCACertFromGTestServer(t, s) const clusterName = "test" hostClient := fakeclient.NewClientBuilder().WithScheme(gclient.NewSchema()).WithObjects( &clusterv1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{Name: clusterName}, Spec: clusterv1alpha1.ClusterSpec{ APIEndpoint: s.URL, SecretRef: &clusterv1alpha1.LocalSecretReference{Namespace: "ns1", Name: "secret1"}, }, }, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{Namespace: "ns1", Name: "secret1"}, Data: map[string][]byte{clusterv1alpha1.SecretTokenKey: []byte("token"), clusterv1alpha1.SecretCADataKey: testCA}, }).Build() clusterClient, err := NewClusterDynamicClientSet(clusterName, hostClient) assert.NoError(t, err) assert.NotNil(t, clusterClient) nodeGVR := corev1.SchemeGroupVersion.WithResource("nodes") got, err := clusterClient.DynamicClientSet.Resource(nodeGVR).Get(context.TODO(), "foo", metav1.GetOptions{}) assert.NoError(t, err) assert.NotNil(t, got) want := &unstructured.Unstructured{} want.SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("Node")) want.SetName("foo") assert.Equal(t, want, got) } func getCACertFromGTestServer(t *testing.T, s *httptest.Server) []byte { t.Helper() testCA := new(bytes.Buffer) err := pem.Encode(testCA, &pem.Block{ Type: "CERTIFICATE", Bytes: s.Certificate().Raw, }) assert.NoError(t, err) return testCA.Bytes() }