github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/kbfscodec/unknown_fields_test_util.go (about) 1 // Copyright 2016 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 5 package kbfscodec 6 7 import ( 8 "crypto/hmac" 9 "crypto/sha256" 10 "reflect" 11 12 "github.com/stretchr/testify/require" 13 ) 14 15 type fakeEncryptedData struct { 16 Version int 17 EncryptedData []byte 18 Nonce []byte 19 } 20 21 // Extra contains some fake extra fields that can be embedded into a 22 // struct to test handling of unknown fields. 23 type Extra struct { 24 Extra1 fakeEncryptedData 25 Extra2 []byte 26 Extra3 string 27 } 28 29 // MakeExtraOrBust returns a filled-in Extra structure based on the 30 // given prefix. 31 func MakeExtraOrBust(prefix string, t require.TestingT) Extra { 32 mac := hmac.New(sha256.New, []byte("fake extra key")) 33 _, _ = mac.Write([]byte("fake extra buf")) 34 h := mac.Sum(nil) 35 return Extra{ 36 Extra1: fakeEncryptedData{ 37 Version: 2, 38 EncryptedData: []byte(prefix + " fake extra encrypted data"), 39 Nonce: []byte(prefix + " fake extra nonce"), 40 }, 41 Extra2: h, 42 Extra3: prefix + " extra string", 43 } 44 } 45 46 // Template for implementing the interfaces below for use with 47 // TestStructUnknownFields, with MyType being the type to test, and 48 // MySubType being the type of one of its sub-fields St, which may 49 // also have unknown fields: 50 // 51 // type myTypeFuture struct { 52 // MyType 53 // // Override MyType.St. 54 // St mySubTypeFuture 55 // kbfscrypto.Extra 56 // } 57 // 58 // func (mf myTypeFuture) toCurrent() MyType { 59 // m := mf.MyType 60 // m.St = m.St.toCurrent() 61 // return m 62 // } 63 // 64 // func (mf myTypeFuture) ToCurrentStruct() kbfscrypto.CurrentStruct { 65 // return mf.toCurrent() 66 // } 67 // 68 // func makeFakeMyTypeFuture(t *testing.T) myTypeFuture { 69 // mf := myTypeFuture{ 70 // myType{ 71 // // List elements (with nil for St) without keys, so that any change 72 // // to the struct will necessitate making the corresponding test 73 // // change. 74 // codec.UnknownFieldSet{}, 75 // }, 76 // makeFakeMySubTypeFuture(t), 77 // kbfscrypto.MakeExtraOrBust("MyType", t), 78 // } 79 // return mf 80 // } 81 // 82 // func TestMyTypeUnknownFields(t *testing.T) { 83 // cFuture := kbfscodec.NewMsgpack() 84 // registerOpsFuture(cFuture) 85 // 86 // cCurrent := kbfscodec.NewMsgpack() 87 // RegisterOps(cCurrent) 88 // 89 // cCurrentKnownOnly := kbfscodec.NewMsgpackNoUnknownFields() 90 // RegisterOps(cCurrentKnownOnly) 91 // 92 // kbfscodec.TestStructUnknownFields(t, makeMyTypeFuture(t)) 93 // } 94 95 // CurrentStruct is an interface for the current version of a struct 96 // type. 97 type CurrentStruct interface{} 98 99 // FutureStruct is an interface for a hypothetical future version of a 100 // struct type. 101 type FutureStruct interface { 102 // toCurrentStruct returns the fields of the current object 103 // copied to the current struct, with all unknown fields 104 // discarded. 105 ToCurrentStruct() CurrentStruct 106 } 107 108 // TestStructUnknownFields tests that hypothetical future versions of 109 // a struct can be deserialized by current clients and preserve 110 // unknown fields. 111 func TestStructUnknownFields(t require.TestingT, 112 cFuture, cCurrent, cCurrentKnownOnly Codec, 113 sFuture FutureStruct) { 114 s := sFuture.ToCurrentStruct() 115 116 buf, err := cFuture.Encode(sFuture) 117 require.NoError(t, err) 118 119 // Make sure sFuture round-trips correctly. 120 sFuture2 := reflect.Zero(reflect.TypeOf(sFuture)).Interface() 121 err = cFuture.Decode(buf, &sFuture2) 122 require.NoError(t, err) 123 require.Equal(t, sFuture, sFuture2) 124 125 s2 := reflect.Zero(reflect.TypeOf(s)).Interface() 126 err = cCurrent.Decode(buf, &s2) 127 require.NoError(t, err) 128 129 knownS2 := reflect.Zero(reflect.TypeOf(s)).Interface() 130 err = cCurrentKnownOnly.Decode(buf, &knownS2) 131 require.NoError(t, err) 132 133 // Make sure known fields are the same. 134 require.Equal(t, s, knownS2) 135 136 buf2, err := cCurrent.Encode(s2) 137 require.NoError(t, err) 138 139 // Make sure serializing s preserves the extra fields. 140 require.Equal(t, buf, buf2) 141 142 // As a sanity test, make sure sFuture decodes back from buf2. 143 sFuture3 := reflect.Zero(reflect.TypeOf(sFuture)).Interface() 144 err = cFuture.Decode(buf2, &sFuture3) 145 require.NoError(t, err) 146 require.Equal(t, sFuture, sFuture3) 147 } 148 149 // TestStructUnknownFieldsMsgpack calls TestStructUnknownFields with 150 // codecs with the msgpack codec. 151 func TestStructUnknownFieldsMsgpack(t require.TestingT, sFuture FutureStruct) { 152 cFuture := NewMsgpack() 153 cCurrent := NewMsgpack() 154 cCurrentKnownOnly := NewMsgpackNoUnknownFields() 155 156 TestStructUnknownFields(t, cFuture, cCurrent, cCurrentKnownOnly, sFuture) 157 }