mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-31 07:20:13 +00:00
Add CBOR variant of admission webhook integration test.
The existing admission webhook integration test provides good coverage of serving built-in resources and custom resources, including subresources. Serialization concerns, including roundtrippability, of built-in types have existing test coverage; the CBOR variant of the admission webhook integration test additionally exercises client and server codec wiring.
This commit is contained in:
parent
3e1b6aaf41
commit
77401d7073
@ -20,7 +20,6 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@ -49,6 +48,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
@ -446,16 +446,25 @@ func (w *warningHandler) HandleWarningHeader(code int, agent string, message str
|
||||
|
||||
// TestWebhookAdmissionWithWatchCache tests communication between API server and webhook process.
|
||||
func TestWebhookAdmissionWithWatchCache(t *testing.T) {
|
||||
testWebhookAdmission(t, true)
|
||||
testWebhookAdmission(t, true, func(testing.TB, *rest.Config) {})
|
||||
}
|
||||
|
||||
// TestWebhookAdmissionWithoutWatchCache tests communication between API server and webhook process.
|
||||
func TestWebhookAdmissionWithoutWatchCache(t *testing.T) {
|
||||
testWebhookAdmission(t, false)
|
||||
testWebhookAdmission(t, false, func(testing.TB, *rest.Config) {})
|
||||
}
|
||||
|
||||
func TestWebhookAdmissionWithCBOR(t *testing.T) {
|
||||
framework.EnableCBORServingAndStorageForTest(t)
|
||||
framework.SetTestOnlyCBORClientFeatureGatesForTest(t, true, true)
|
||||
testWebhookAdmission(t, false, func(t testing.TB, config *rest.Config) {
|
||||
config.Wrap(framework.AssertRequestResponseAsCBOR(t))
|
||||
})
|
||||
}
|
||||
|
||||
// testWebhookAdmission tests communication between API server and webhook process.
|
||||
func testWebhookAdmission(t *testing.T, watchCache bool) {
|
||||
func testWebhookAdmission(t *testing.T, watchCache bool, reconfigureClient func(testing.TB, *rest.Config)) {
|
||||
|
||||
// holder communicates expectations to webhooks, and results from webhooks
|
||||
holder := &holder{
|
||||
t: t,
|
||||
@ -528,10 +537,6 @@ func testWebhookAdmission(t *testing.T, watchCache bool) {
|
||||
}
|
||||
|
||||
// gather resources to test
|
||||
dynamicClient, err := dynamic.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, resources, err := client.Discovery().ServerGroupsAndResources()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get ServerGroupsAndResources with error: %+v", err)
|
||||
@ -640,6 +645,13 @@ func testWebhookAdmission(t *testing.T, watchCache bool) {
|
||||
for _, verb := range []string{"create", "update", "patch", "connect", "delete", "deletecollection"} {
|
||||
if shouldTestResourceVerb(gvr, resource, verb) {
|
||||
t.Run(verb, func(t *testing.T) {
|
||||
clientConfig := rest.CopyConfig(clientConfig)
|
||||
reconfigureClient(t, clientConfig)
|
||||
dynamicClient, err := dynamic.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
count++
|
||||
holder.reset(t)
|
||||
testFunc := getTestFunc(gvr, verb)
|
||||
|
@ -17,6 +17,9 @@ limitations under the License.
|
||||
package framework
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
apiextensionsapiserver "k8s.io/apiextensions-apiserver/pkg/apiserver"
|
||||
@ -24,9 +27,11 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/cbor"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
clientfeatures "k8s.io/client-go/features"
|
||||
"k8s.io/client-go/transport"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
aggregatorscheme "k8s.io/kube-aggregator/pkg/apiserver/scheme"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
@ -102,3 +107,67 @@ func EnableCBORServingAndStorageForTest(tb testing.TB) {
|
||||
*codecs[scheme] = serializer.NewCodecFactory(scheme, serializer.WithSerializer(newCBORSerializerInfo))
|
||||
}
|
||||
}
|
||||
|
||||
// AssertRequestResponseAsCBOR returns a transport.WrapperFunc that will report a test error if a
|
||||
// non-empty request or response body contains data that does not appear to be CBOR-encoded.
|
||||
func AssertRequestResponseAsCBOR(t testing.TB) transport.WrapperFunc {
|
||||
recognizer := cbor.NewSerializer(runtime.NewScheme(), runtime.NewScheme())
|
||||
|
||||
unsupportedPatchContentTypes := sets.New(
|
||||
"application/json-patch+json",
|
||||
"application/merge-patch+json",
|
||||
"application/strategic-merge-patch+json",
|
||||
)
|
||||
|
||||
return func(rt http.RoundTripper) http.RoundTripper {
|
||||
return roundTripperFunc(func(request *http.Request) (*http.Response, error) {
|
||||
if request.Body != nil && !unsupportedPatchContentTypes.Has(request.Header.Get("Content-Type")) {
|
||||
requestbody, err := io.ReadAll(request.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
recognized, _, err := recognizer.RecognizesData(requestbody)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if len(requestbody) > 0 && !recognized {
|
||||
t.Errorf("non-cbor request: 0x%x", requestbody)
|
||||
}
|
||||
request.Body = io.NopCloser(bytes.NewReader(requestbody))
|
||||
}
|
||||
|
||||
response, rterr := rt.RoundTrip(request)
|
||||
if rterr != nil {
|
||||
return response, rterr
|
||||
}
|
||||
|
||||
// We can't synchronously inspect streaming responses, so tee to a buffer
|
||||
// and inspect it at the end of the test.
|
||||
var buf bytes.Buffer
|
||||
response.Body = struct {
|
||||
io.Reader
|
||||
io.Closer
|
||||
}{
|
||||
Reader: io.TeeReader(response.Body, &buf),
|
||||
Closer: response.Body,
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
recognized, _, err := recognizer.RecognizesData(buf.Bytes())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if buf.Len() > 0 && !recognized {
|
||||
t.Errorf("non-cbor response: 0x%x", buf.Bytes())
|
||||
}
|
||||
})
|
||||
|
||||
return response, rterr
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type roundTripperFunc func(*http.Request) (*http.Response, error)
|
||||
|
||||
func (f roundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) {
|
||||
return f(r)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user