github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/test/runtime_serializer_protobuf_protobuf_test.go (about)

     1  /*
     2  Copyright 2015 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package test
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/hex"
    22  	"fmt"
    23  	"reflect"
    24  	"strings"
    25  	"testing"
    26  
    27  	"github.com/stretchr/testify/require"
    28  
    29  	apiequality "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/api/equality"
    30  	metav1 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/apis/meta/v1"
    31  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/apis/testapigroup/v1"
    32  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime"
    33  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/schema"
    34  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/serializer/protobuf"
    35  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/util/diff"
    36  )
    37  
    38  type testObject struct {
    39  	gvk schema.GroupVersionKind
    40  }
    41  
    42  func (d *testObject) GetObjectKind() schema.ObjectKind                { return d }
    43  func (d *testObject) SetGroupVersionKind(gvk schema.GroupVersionKind) { d.gvk = gvk }
    44  func (d *testObject) GroupVersionKind() schema.GroupVersionKind       { return d.gvk }
    45  func (d *testObject) DeepCopyObject() runtime.Object {
    46  	panic("testObject does not support DeepCopy")
    47  }
    48  
    49  type testMarshalable struct {
    50  	testObject
    51  	data []byte
    52  	err  error
    53  }
    54  
    55  func (d *testMarshalable) Marshal() ([]byte, error) {
    56  	return d.data, d.err
    57  }
    58  
    59  func (d *testMarshalable) DeepCopyObject() runtime.Object {
    60  	panic("testMarshalable does not support DeepCopy")
    61  }
    62  
    63  type testBufferedMarshalable struct {
    64  	testObject
    65  	data []byte
    66  	err  error
    67  }
    68  
    69  func (d *testBufferedMarshalable) Marshal() ([]byte, error) {
    70  	return nil, fmt.Errorf("not invokable")
    71  }
    72  
    73  func (d *testBufferedMarshalable) MarshalTo(data []byte) (int, error) {
    74  	copy(data, d.data)
    75  	return len(d.data), d.err
    76  }
    77  
    78  func (d *testBufferedMarshalable) Size() int {
    79  	return len(d.data)
    80  }
    81  
    82  func (d *testBufferedMarshalable) DeepCopyObject() runtime.Object {
    83  	panic("testBufferedMarshalable does not support DeepCopy")
    84  }
    85  
    86  func TestRecognize(t *testing.T) {
    87  	s := protobuf.NewSerializer(nil, nil)
    88  	ignores := [][]byte{
    89  		nil,
    90  		{},
    91  		[]byte("k8s"),
    92  		{0x6b, 0x38, 0x73, 0x01},
    93  	}
    94  	for i, data := range ignores {
    95  		if ok, _, err := s.RecognizesData(data); err != nil || ok {
    96  			t.Errorf("%d: should not recognize data: %v", i, err)
    97  		}
    98  	}
    99  	recognizes := [][]byte{
   100  		{0x6b, 0x38, 0x73, 0x00},
   101  		{0x6b, 0x38, 0x73, 0x00, 0x01},
   102  	}
   103  	for i, data := range recognizes {
   104  		if ok, _, err := s.RecognizesData(data); err != nil || !ok {
   105  			t.Errorf("%d: should recognize data: %v", i, err)
   106  		}
   107  	}
   108  }
   109  
   110  func TestEncode(t *testing.T) {
   111  	obj1 := &testMarshalable{testObject: testObject{}, data: []byte{}}
   112  	wire1 := []byte{
   113  		0x6b, 0x38, 0x73, 0x00, // prefix
   114  		0x0a, 0x04,
   115  		0x0a, 0x00, // apiversion
   116  		0x12, 0x00, // kind
   117  		0x12, 0x00, // data
   118  		0x1a, 0x00, // content-type
   119  		0x22, 0x00, // content-encoding
   120  	}
   121  	obj2 := &testMarshalable{
   122  		testObject: testObject{gvk: schema.GroupVersionKind{Kind: "test", Group: "other", Version: "version"}},
   123  		data:       []byte{0x01, 0x02, 0x03},
   124  	}
   125  	wire2 := []byte{
   126  		0x6b, 0x38, 0x73, 0x00, // prefix
   127  		0x0a, 0x15,
   128  		0x0a, 0x0d, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, // apiversion
   129  		0x12, 0x04, 0x74, 0x65, 0x73, 0x74, // kind
   130  		0x12, 0x03, 0x01, 0x02, 0x03, // data
   131  		0x1a, 0x00, // content-type
   132  		0x22, 0x00, // content-encoding
   133  	}
   134  
   135  	err1 := fmt.Errorf("a test error")
   136  
   137  	testCases := []struct {
   138  		obj   runtime.Object
   139  		data  []byte
   140  		errFn func(error) bool
   141  	}{
   142  		{
   143  			obj:   &testObject{},
   144  			errFn: protobuf.IsNotMarshalable,
   145  		},
   146  		{
   147  			obj:  obj1,
   148  			data: wire1,
   149  		},
   150  		{
   151  			obj:   &testMarshalable{testObject: obj1.testObject, err: err1},
   152  			errFn: func(err error) bool { return err == err1 },
   153  		},
   154  		{
   155  			// if this test fails, writing the "fast path" marshal is not the same as the "slow path"
   156  			obj:  &testBufferedMarshalable{testObject: obj1.testObject, data: obj1.data},
   157  			data: wire1,
   158  		},
   159  		{
   160  			obj:  obj2,
   161  			data: wire2,
   162  		},
   163  		{
   164  			// if this test fails, writing the "fast path" marshal is not the same as the "slow path"
   165  			obj:  &testBufferedMarshalable{testObject: obj2.testObject, data: obj2.data},
   166  			data: wire2,
   167  		},
   168  		{
   169  			obj:   &testBufferedMarshalable{testObject: obj1.testObject, err: err1},
   170  			errFn: func(err error) bool { return err == err1 },
   171  		},
   172  	}
   173  
   174  	for i, test := range testCases {
   175  		s := protobuf.NewSerializer(nil, nil)
   176  		data, err := runtime.Encode(s, test.obj)
   177  
   178  		switch {
   179  		case err == nil && test.errFn != nil:
   180  			t.Errorf("%d: failed: %v", i, err)
   181  			continue
   182  		case err != nil && test.errFn == nil:
   183  			t.Errorf("%d: failed: %v", i, err)
   184  			continue
   185  		case err != nil:
   186  			if !test.errFn(err) {
   187  				t.Errorf("%d: failed: %v", i, err)
   188  			}
   189  			if data != nil {
   190  				t.Errorf("%d: should not have returned nil data", i)
   191  			}
   192  			continue
   193  		}
   194  
   195  		if test.data != nil && !bytes.Equal(test.data, data) {
   196  			t.Errorf("%d: unexpected data:\n%s", i, hex.Dump(data))
   197  			continue
   198  		}
   199  
   200  		if ok, _, err := s.RecognizesData(data); !ok || err != nil {
   201  			t.Errorf("%d: did not recognize data generated by call: %v", i, err)
   202  		}
   203  	}
   204  }
   205  
   206  func TestProtobufDecode(t *testing.T) {
   207  	wire1 := []byte{
   208  		0x6b, 0x38, 0x73, 0x00, // prefix
   209  		0x0a, 0x04,
   210  		0x0a, 0x00, // apiversion
   211  		0x12, 0x00, // kind
   212  		0x12, 0x00, // data
   213  		0x1a, 0x00, // content-type
   214  		0x22, 0x00, // content-encoding
   215  	}
   216  	wire2 := []byte{
   217  		0x6b, 0x38, 0x73, 0x00, // prefix
   218  		0x0a, 0x15,
   219  		0x0a, 0x0d, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, // apiversion
   220  		0x12, 0x04, 0x74, 0x65, 0x73, 0x74, // kind
   221  		0x12, 0x07, 0x6b, 0x38, 0x73, 0x00, 0x01, 0x02, 0x03, // data
   222  		0x1a, 0x00, // content-type
   223  		0x22, 0x00, // content-encoding
   224  	}
   225  
   226  	testCases := []struct {
   227  		obj   runtime.Object
   228  		data  []byte
   229  		errFn func(error) bool
   230  	}{
   231  		{
   232  			obj:   &runtime.Unknown{},
   233  			errFn: func(err error) bool { return err.Error() == "empty data" },
   234  		},
   235  		{
   236  			data:  []byte{0x6b},
   237  			errFn: func(err error) bool { return strings.Contains(err.Error(), "does not appear to be a protobuf message") },
   238  		},
   239  		{
   240  			obj: &runtime.Unknown{
   241  				Raw: []byte{},
   242  			},
   243  			data: wire1,
   244  		},
   245  		{
   246  			obj: &runtime.Unknown{
   247  				TypeMeta: runtime.TypeMeta{
   248  					APIVersion: "other/version",
   249  					Kind:       "test",
   250  				},
   251  				// content type is set because the prefix matches the content
   252  				ContentType: runtime.ContentTypeProtobuf,
   253  				Raw:         []byte{0x6b, 0x38, 0x73, 0x00, 0x01, 0x02, 0x03},
   254  			},
   255  			data: wire2,
   256  		},
   257  	}
   258  
   259  	for i, test := range testCases {
   260  		s := protobuf.NewSerializer(nil, nil)
   261  		unk := &runtime.Unknown{}
   262  		err := runtime.DecodeInto(s, test.data, unk)
   263  
   264  		switch {
   265  		case err == nil && test.errFn != nil:
   266  			t.Errorf("%d: failed: %v", i, err)
   267  			continue
   268  		case err != nil && test.errFn == nil:
   269  			t.Errorf("%d: failed: %v", i, err)
   270  			continue
   271  		case err != nil:
   272  			if !test.errFn(err) {
   273  				t.Errorf("%d: failed: %v", i, err)
   274  			}
   275  			continue
   276  		}
   277  
   278  		if !reflect.DeepEqual(unk, test.obj) {
   279  			t.Errorf("%d: unexpected object:\n%#v", i, unk)
   280  			continue
   281  		}
   282  	}
   283  }
   284  
   285  func TestDecodeObjects(t *testing.T) {
   286  	obj1 := &v1.Carp{
   287  		ObjectMeta: metav1.ObjectMeta{
   288  			Name: "cool",
   289  		},
   290  		Spec: v1.CarpSpec{
   291  			Hostname: "coolhost",
   292  		},
   293  	}
   294  	obj1wire, err := obj1.Marshal()
   295  	if err != nil {
   296  		t.Fatal(err)
   297  	}
   298  
   299  	wire1, err := (&runtime.Unknown{
   300  		TypeMeta: runtime.TypeMeta{Kind: "Carp", APIVersion: "v1"},
   301  		Raw:      obj1wire,
   302  	}).Marshal()
   303  	if err != nil {
   304  		t.Fatal(err)
   305  	}
   306  
   307  	unk2 := &runtime.Unknown{
   308  		TypeMeta: runtime.TypeMeta{Kind: "Carp", APIVersion: "v1"},
   309  	}
   310  	wire2 := make([]byte, len(wire1)*2)
   311  	n, err := unk2.NestedMarshalTo(wire2, obj1, uint64(obj1.Size()))
   312  	if err != nil {
   313  		t.Fatal(err)
   314  	}
   315  	if n != len(wire1) || !bytes.Equal(wire1, wire2[:n]) {
   316  		t.Fatalf("unexpected wire:\n%s", hex.Dump(wire2[:n]))
   317  	}
   318  
   319  	wire1 = append([]byte{0x6b, 0x38, 0x73, 0x00}, wire1...)
   320  
   321  	obj1WithKind := obj1.DeepCopyObject()
   322  	obj1WithKind.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Carp"})
   323  	testCases := []struct {
   324  		obj   runtime.Object
   325  		data  []byte
   326  		errFn func(error) bool
   327  	}{
   328  		{
   329  			obj:  obj1WithKind,
   330  			data: wire1,
   331  		},
   332  	}
   333  	scheme := runtime.NewScheme()
   334  	for i, test := range testCases {
   335  		scheme.AddKnownTypes(schema.GroupVersion{Version: "v1"}, &v1.Carp{})
   336  		require.NoError(t, v1.AddToScheme(scheme))
   337  		s := protobuf.NewSerializer(scheme, scheme)
   338  		obj, err := runtime.Decode(s, test.data)
   339  
   340  		switch {
   341  		case err == nil && test.errFn != nil:
   342  			t.Errorf("%d: failed: %v", i, err)
   343  			continue
   344  		case err != nil && test.errFn == nil:
   345  			t.Errorf("%d: failed: %v", i, err)
   346  			continue
   347  		case err != nil:
   348  			if !test.errFn(err) {
   349  				t.Errorf("%d: failed: %v", i, err)
   350  			}
   351  			if obj != nil {
   352  				t.Errorf("%d: should not have returned an object", i)
   353  			}
   354  			continue
   355  		}
   356  
   357  		if !apiequality.Semantic.DeepEqual(obj, test.obj) {
   358  			t.Errorf("%d: unexpected object:\n%s", i, diff.ObjectGoPrintDiff(test.obj, obj))
   359  			continue
   360  		}
   361  	}
   362  }