123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- /*
- Copyright 2015 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 protobuf_test
- import (
- "bytes"
- "encoding/hex"
- "fmt"
- "reflect"
- "strings"
- "testing"
- "k8s.io/kubernetes/pkg/api"
- _ "k8s.io/kubernetes/pkg/api/install"
- "k8s.io/kubernetes/pkg/api/unversioned"
- "k8s.io/kubernetes/pkg/api/v1"
- "k8s.io/kubernetes/pkg/runtime"
- "k8s.io/kubernetes/pkg/runtime/serializer/protobuf"
- "k8s.io/kubernetes/pkg/util/diff"
- )
- type testObject struct {
- gvk unversioned.GroupVersionKind
- }
- func (d *testObject) GetObjectKind() unversioned.ObjectKind { return d }
- func (d *testObject) SetGroupVersionKind(gvk unversioned.GroupVersionKind) { d.gvk = gvk }
- func (d *testObject) GroupVersionKind() unversioned.GroupVersionKind { return d.gvk }
- type testMarshalable struct {
- testObject
- data []byte
- err error
- }
- func (d *testMarshalable) Marshal() ([]byte, error) {
- return d.data, d.err
- }
- type testBufferedMarshalable struct {
- testObject
- data []byte
- err error
- }
- func (d *testBufferedMarshalable) Marshal() ([]byte, error) {
- return nil, fmt.Errorf("not invokable")
- }
- func (d *testBufferedMarshalable) MarshalTo(data []byte) (int, error) {
- copy(data, d.data)
- return len(d.data), d.err
- }
- func (d *testBufferedMarshalable) Size() int {
- return len(d.data)
- }
- func TestRecognize(t *testing.T) {
- s := protobuf.NewSerializer(nil, nil, "application/protobuf")
- ignores := [][]byte{
- nil,
- {},
- []byte("k8s"),
- {0x6b, 0x38, 0x73, 0x01},
- }
- for i, data := range ignores {
- if ok, _, err := s.RecognizesData(bytes.NewBuffer(data)); err != nil || ok {
- t.Errorf("%d: should not recognize data: %v", i, err)
- }
- }
- recognizes := [][]byte{
- {0x6b, 0x38, 0x73, 0x00},
- {0x6b, 0x38, 0x73, 0x00, 0x01},
- }
- for i, data := range recognizes {
- if ok, _, err := s.RecognizesData(bytes.NewBuffer(data)); err != nil || !ok {
- t.Errorf("%d: should recognize data: %v", i, err)
- }
- }
- }
- func TestEncode(t *testing.T) {
- obj1 := &testMarshalable{testObject: testObject{}, data: []byte{}}
- wire1 := []byte{
- 0x6b, 0x38, 0x73, 0x00, // prefix
- 0x0a, 0x04,
- 0x0a, 0x00, // apiversion
- 0x12, 0x00, // kind
- 0x12, 0x00, // data
- 0x1a, 0x00, // content-type
- 0x22, 0x00, // content-encoding
- }
- obj2 := &testMarshalable{
- testObject: testObject{gvk: unversioned.GroupVersionKind{Kind: "test", Group: "other", Version: "version"}},
- data: []byte{0x01, 0x02, 0x03},
- }
- wire2 := []byte{
- 0x6b, 0x38, 0x73, 0x00, // prefix
- 0x0a, 0x15,
- 0x0a, 0x0d, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, // apiversion
- 0x12, 0x04, 0x74, 0x65, 0x73, 0x74, // kind
- 0x12, 0x03, 0x01, 0x02, 0x03, // data
- 0x1a, 0x00, // content-type
- 0x22, 0x00, // content-encoding
- }
- err1 := fmt.Errorf("a test error")
- testCases := []struct {
- obj runtime.Object
- data []byte
- errFn func(error) bool
- }{
- {
- obj: &testObject{},
- errFn: protobuf.IsNotMarshalable,
- },
- {
- obj: obj1,
- data: wire1,
- },
- {
- obj: &testMarshalable{testObject: obj1.testObject, err: err1},
- errFn: func(err error) bool { return err == err1 },
- },
- {
- // if this test fails, writing the "fast path" marshal is not the same as the "slow path"
- obj: &testBufferedMarshalable{testObject: obj1.testObject, data: obj1.data},
- data: wire1,
- },
- {
- obj: obj2,
- data: wire2,
- },
- {
- // if this test fails, writing the "fast path" marshal is not the same as the "slow path"
- obj: &testBufferedMarshalable{testObject: obj2.testObject, data: obj2.data},
- data: wire2,
- },
- {
- obj: &testBufferedMarshalable{testObject: obj1.testObject, err: err1},
- errFn: func(err error) bool { return err == err1 },
- },
- }
- for i, test := range testCases {
- s := protobuf.NewSerializer(nil, nil, "application/protobuf")
- data, err := runtime.Encode(s, test.obj)
- switch {
- case err == nil && test.errFn != nil:
- t.Errorf("%d: failed: %v", i, err)
- continue
- case err != nil && test.errFn == nil:
- t.Errorf("%d: failed: %v", i, err)
- continue
- case err != nil:
- if !test.errFn(err) {
- t.Errorf("%d: failed: %v", i, err)
- }
- if data != nil {
- t.Errorf("%d: should not have returned nil data", i)
- }
- continue
- }
- if test.data != nil && !bytes.Equal(test.data, data) {
- t.Errorf("%d: unexpected data:\n%s", i, hex.Dump(data))
- continue
- }
- if ok, _, err := s.RecognizesData(bytes.NewBuffer(data)); !ok || err != nil {
- t.Errorf("%d: did not recognize data generated by call: %v", i, err)
- }
- }
- }
- func TestDecode(t *testing.T) {
- wire1 := []byte{
- 0x6b, 0x38, 0x73, 0x00, // prefix
- 0x0a, 0x04,
- 0x0a, 0x00, // apiversion
- 0x12, 0x00, // kind
- 0x12, 0x00, // data
- 0x1a, 0x00, // content-type
- 0x22, 0x00, // content-encoding
- }
- wire2 := []byte{
- 0x6b, 0x38, 0x73, 0x00, // prefix
- 0x0a, 0x15,
- 0x0a, 0x0d, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, // apiversion
- 0x12, 0x04, 0x74, 0x65, 0x73, 0x74, // kind
- 0x12, 0x07, 0x6b, 0x38, 0x73, 0x00, 0x01, 0x02, 0x03, // data
- 0x1a, 0x00, // content-type
- 0x22, 0x00, // content-encoding
- }
- //err1 := fmt.Errorf("a test error")
- testCases := []struct {
- obj runtime.Object
- data []byte
- errFn func(error) bool
- }{
- {
- obj: &runtime.Unknown{},
- errFn: func(err error) bool { return err.Error() == "empty data" },
- },
- {
- data: []byte{0x6b},
- errFn: func(err error) bool { return strings.Contains(err.Error(), "does not appear to be a protobuf message") },
- },
- {
- obj: &runtime.Unknown{
- Raw: []byte{},
- },
- data: wire1,
- },
- {
- obj: &runtime.Unknown{
- TypeMeta: runtime.TypeMeta{
- APIVersion: "other/version",
- Kind: "test",
- },
- // content type is set because the prefix matches the content
- ContentType: "application/protobuf",
- Raw: []byte{0x6b, 0x38, 0x73, 0x00, 0x01, 0x02, 0x03},
- },
- data: wire2,
- },
- }
- for i, test := range testCases {
- s := protobuf.NewSerializer(nil, nil, "application/protobuf")
- unk := &runtime.Unknown{}
- err := runtime.DecodeInto(s, test.data, unk)
- switch {
- case err == nil && test.errFn != nil:
- t.Errorf("%d: failed: %v", i, err)
- continue
- case err != nil && test.errFn == nil:
- t.Errorf("%d: failed: %v", i, err)
- continue
- case err != nil:
- if !test.errFn(err) {
- t.Errorf("%d: failed: %v", i, err)
- }
- continue
- }
- if !reflect.DeepEqual(unk, test.obj) {
- t.Errorf("%d: unexpected object:\n%#v", i, unk)
- continue
- }
- }
- }
- func TestDecodeObjects(t *testing.T) {
- obj1 := &v1.Pod{
- ObjectMeta: v1.ObjectMeta{
- Name: "cool",
- },
- Spec: v1.PodSpec{
- Containers: []v1.Container{
- {
- Name: "test",
- },
- },
- },
- }
- obj1wire, err := obj1.Marshal()
- if err != nil {
- t.Fatal(err)
- }
- wire1, err := (&runtime.Unknown{
- TypeMeta: runtime.TypeMeta{Kind: "Pod", APIVersion: "v1"},
- Raw: obj1wire,
- }).Marshal()
- if err != nil {
- t.Fatal(err)
- }
- unk2 := &runtime.Unknown{
- TypeMeta: runtime.TypeMeta{Kind: "Pod", APIVersion: "v1"},
- }
- wire2 := make([]byte, len(wire1)*2)
- n, err := unk2.NestedMarshalTo(wire2, obj1, uint64(obj1.Size()))
- if err != nil {
- t.Fatal(err)
- }
- if n != len(wire1) || !bytes.Equal(wire1, wire2[:n]) {
- t.Fatalf("unexpected wire:\n%s", hex.Dump(wire2[:n]))
- }
- wire1 = append([]byte{0x6b, 0x38, 0x73, 0x00}, wire1...)
- testCases := []struct {
- obj runtime.Object
- data []byte
- errFn func(error) bool
- }{
- {
- obj: obj1,
- data: wire1,
- },
- }
- for i, test := range testCases {
- s := protobuf.NewSerializer(api.Scheme, api.Scheme, "application/protobuf")
- obj, err := runtime.Decode(s, test.data)
- switch {
- case err == nil && test.errFn != nil:
- t.Errorf("%d: failed: %v", i, err)
- continue
- case err != nil && test.errFn == nil:
- t.Errorf("%d: failed: %v", i, err)
- continue
- case err != nil:
- if !test.errFn(err) {
- t.Errorf("%d: failed: %v", i, err)
- }
- if obj != nil {
- t.Errorf("%d: should not have returned an object", i)
- }
- continue
- }
- if !api.Semantic.DeepEqual(obj, test.obj) {
- t.Errorf("%d: unexpected object:\n%s", i, diff.ObjectGoPrintDiff(test.obj, obj))
- continue
- }
- }
- }
|