github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/chaincode/lifecycle/serializer_test.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package lifecycle_test
     8  
     9  import (
    10  	"fmt"
    11  
    12  	. "github.com/onsi/ginkgo"
    13  	. "github.com/onsi/gomega"
    14  
    15  	"github.com/golang/protobuf/proto"
    16  	"github.com/hechain20/hechain/common/util"
    17  	"github.com/hechain20/hechain/core/chaincode/lifecycle"
    18  	"github.com/hechain20/hechain/core/chaincode/lifecycle/mock"
    19  	"github.com/hechain20/hechain/protoutil"
    20  	lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle"
    21  )
    22  
    23  var _ = Describe("Serializer", func() {
    24  	type TestStruct struct {
    25  		Int    int64
    26  		Bytes  []byte
    27  		Proto  *lb.InstallChaincodeResult
    28  		String string
    29  	}
    30  
    31  	var (
    32  		s          *lifecycle.Serializer
    33  		fakeState  *mock.ReadWritableState
    34  		testStruct *TestStruct
    35  	)
    36  
    37  	BeforeEach(func() {
    38  		fakeState = &mock.ReadWritableState{}
    39  
    40  		s = &lifecycle.Serializer{}
    41  
    42  		testStruct = &TestStruct{
    43  			Int:   -3,
    44  			Bytes: []byte("bytes"),
    45  			Proto: &lb.InstallChaincodeResult{
    46  				PackageId: "hash",
    47  			},
    48  			String: "theory",
    49  		}
    50  	})
    51  
    52  	Describe("Serialize", func() {
    53  		It("serializes the structure", func() {
    54  			err := s.Serialize("namespaces", "fake", testStruct, fakeState)
    55  			Expect(err).NotTo(HaveOccurred())
    56  
    57  			Expect(fakeState.GetStateCallCount()).To(Equal(1))
    58  			Expect(fakeState.GetStateArgsForCall(0)).To(Equal("namespaces/metadata/fake"))
    59  
    60  			Expect(fakeState.PutStateCallCount()).To(Equal(5))
    61  
    62  			key, value := fakeState.PutStateArgsForCall(0)
    63  			Expect(key).To(Equal("namespaces/fields/fake/Int"))
    64  			Expect(value).To(Equal(protoutil.MarshalOrPanic(&lb.StateData{
    65  				Type: &lb.StateData_Int64{Int64: -3},
    66  			})))
    67  
    68  			key, value = fakeState.PutStateArgsForCall(1)
    69  			Expect(key).To(Equal("namespaces/fields/fake/Bytes"))
    70  			Expect(value).To(Equal(protoutil.MarshalOrPanic(&lb.StateData{
    71  				Type: &lb.StateData_Bytes{Bytes: []byte("bytes")},
    72  			})))
    73  
    74  			key, value = fakeState.PutStateArgsForCall(2)
    75  			Expect(key).To(Equal("namespaces/fields/fake/Proto"))
    76  			Expect(value).To(Equal(protoutil.MarshalOrPanic(&lb.StateData{
    77  				Type: &lb.StateData_Bytes{Bytes: protoutil.MarshalOrPanic(testStruct.Proto)},
    78  			})))
    79  
    80  			key, value = fakeState.PutStateArgsForCall(3)
    81  			Expect(key).To(Equal("namespaces/fields/fake/String"))
    82  			Expect(value).To(Equal(protoutil.MarshalOrPanic(&lb.StateData{
    83  				Type: &lb.StateData_String_{String_: "theory"},
    84  			})))
    85  
    86  			key, value = fakeState.PutStateArgsForCall(4)
    87  			Expect(key).To(Equal("namespaces/metadata/fake"))
    88  			Expect(value).To(Equal(protoutil.MarshalOrPanic(&lb.StateMetadata{
    89  				Datatype: "TestStruct",
    90  				Fields:   []string{"Int", "Bytes", "Proto", "String"},
    91  			})))
    92  
    93  			Expect(fakeState.DelStateCallCount()).To(Equal(0))
    94  		})
    95  
    96  		Context("when the namespace contains extraneous keys", func() {
    97  			BeforeEach(func() {
    98  				kvs := map[string][]byte{
    99  					"namespaces/fields/fake/ExtraneousKey1": protoutil.MarshalOrPanic(&lb.StateData{
   100  						Type: &lb.StateData_Bytes{Bytes: []byte("value1")},
   101  					}),
   102  					"namespaces/fields/fake/ExtraneousKey2": protoutil.MarshalOrPanic(&lb.StateData{
   103  						Type: &lb.StateData_Bytes{Bytes: []byte("value2")},
   104  					}),
   105  					"namespaces/metadata/fake": protoutil.MarshalOrPanic(&lb.StateMetadata{
   106  						Datatype: "Other",
   107  						Fields:   []string{"ExtraneousKey1", "ExtraneousKey2"},
   108  					}),
   109  				}
   110  				fakeState.GetStateStub = func(key string) ([]byte, error) {
   111  					return kvs[key], nil
   112  				}
   113  			})
   114  
   115  			It("deletes them before returning", func() {
   116  				err := s.Serialize("namespaces", "fake", testStruct, fakeState)
   117  				Expect(err).NotTo(HaveOccurred())
   118  
   119  				Expect(fakeState.DelStateCallCount()).To(Equal(2))
   120  				Expect(map[string]struct{}{
   121  					fakeState.DelStateArgsForCall(0): {},
   122  					fakeState.DelStateArgsForCall(1): {},
   123  				}).To(Equal(map[string]struct{}{
   124  					"namespaces/fields/fake/ExtraneousKey1": {},
   125  					"namespaces/fields/fake/ExtraneousKey2": {},
   126  				}))
   127  			})
   128  
   129  			Context("when deleting from  the state fails", func() {
   130  				BeforeEach(func() {
   131  					fakeState.DelStateReturns(fmt.Errorf("del-error"))
   132  				})
   133  
   134  				It("deletes them before returning", func() {
   135  					err := s.Serialize("namespaces", "fake", testStruct, fakeState)
   136  					Expect(err.Error()).To(MatchRegexp("could not delete unneeded key namespaces/fields/fake/ExtraneousKey.: del-error"))
   137  				})
   138  			})
   139  		})
   140  
   141  		Context("when the namespace already contains the keys and values", func() {
   142  			var kvs map[string][]byte
   143  
   144  			BeforeEach(func() {
   145  				kvs = map[string][]byte{
   146  					"namespaces/fields/fake/Int": protoutil.MarshalOrPanic(&lb.StateData{
   147  						Type: &lb.StateData_Int64{Int64: -3},
   148  					}),
   149  					"namespaces/fields/fake/Bytes": protoutil.MarshalOrPanic(&lb.StateData{
   150  						Type: &lb.StateData_Bytes{Bytes: []byte("bytes")},
   151  					}),
   152  					"namespaces/fields/fake/Proto": protoutil.MarshalOrPanic(&lb.StateData{
   153  						Type: &lb.StateData_Bytes{Bytes: protoutil.MarshalOrPanic(testStruct.Proto)},
   154  					}),
   155  					"namespaces/fields/fake/String": protoutil.MarshalOrPanic(&lb.StateData{
   156  						Type: &lb.StateData_String_{String_: "theory"},
   157  					}),
   158  					"namespaces/metadata/fake": protoutil.MarshalOrPanic(&lb.StateMetadata{
   159  						Datatype: "TestStruct",
   160  						Fields:   []string{"Int", "Bytes", "Proto", "String"},
   161  					}),
   162  				}
   163  				fakeState.GetStateStub = func(key string) ([]byte, error) {
   164  					return kvs[key], nil
   165  				}
   166  			})
   167  
   168  			It("does not perform writes", func() {
   169  				err := s.Serialize("namespaces", "fake", testStruct, fakeState)
   170  				Expect(err).NotTo(HaveOccurred())
   171  
   172  				Expect(fakeState.PutStateCallCount()).To(Equal(0))
   173  				Expect(fakeState.DelStateCallCount()).To(Equal(0))
   174  			})
   175  
   176  			Context("when some of the values are missing", func() {
   177  				BeforeEach(func() {
   178  					kvs["namespaces/metadata/fake"] = protoutil.MarshalOrPanic(&lb.StateMetadata{
   179  						Datatype: "TestStruct",
   180  						Fields:   []string{"Proto", "Bytes"},
   181  					})
   182  					delete(kvs, "namespaces/fields/fake/Int")
   183  				})
   184  
   185  				It("writes the missing field and new metadata ", func() {
   186  					err := s.Serialize("namespaces", "fake", testStruct, fakeState)
   187  					Expect(err).NotTo(HaveOccurred())
   188  
   189  					Expect(fakeState.PutStateCallCount()).To(Equal(3))
   190  					key, value := fakeState.PutStateArgsForCall(0)
   191  					Expect(value).To(Equal(protoutil.MarshalOrPanic(&lb.StateData{
   192  						Type: &lb.StateData_Int64{Int64: -3},
   193  					})))
   194  					Expect(key).To(Equal("namespaces/fields/fake/Int"))
   195  					key, value = fakeState.PutStateArgsForCall(1)
   196  					Expect(key).To(Equal("namespaces/fields/fake/String"))
   197  					Expect(value).To(Equal(protoutil.MarshalOrPanic(&lb.StateData{
   198  						Type: &lb.StateData_String_{String_: "theory"},
   199  					})))
   200  					key, value = fakeState.PutStateArgsForCall(2)
   201  					Expect(key).To(Equal("namespaces/metadata/fake"))
   202  					Expect(value).To(Equal(protoutil.MarshalOrPanic(&lb.StateMetadata{
   203  						Datatype: "TestStruct",
   204  						Fields:   []string{"Int", "Bytes", "Proto", "String"},
   205  					})))
   206  					Expect(fakeState.DelStateCallCount()).To(Equal(0))
   207  				})
   208  			})
   209  
   210  			Context("when the namespace metadata is invalid", func() {
   211  				BeforeEach(func() {
   212  					kvs["namespaces/metadata/fake"] = []byte("bad-data")
   213  				})
   214  
   215  				It("wraps and returns the error", func() {
   216  					err := s.Serialize("namespaces", "fake", testStruct, fakeState)
   217  					Expect(err).To(MatchError("could not deserialize metadata for namespace namespaces/fake: could not unmarshal metadata for namespace namespaces/fake: unexpected EOF"))
   218  				})
   219  			})
   220  		})
   221  
   222  		Context("when the argument is not a pointer", func() {
   223  			It("fails", func() {
   224  				err := s.Serialize("namespaces", "fake", 8, fakeState)
   225  				Expect(err).To(MatchError("structure for namespace namespaces/fake is not serializable: must be pointer to struct, but got non-pointer int"))
   226  			})
   227  		})
   228  
   229  		Context("when the argument is a pointer to not-a-struct", func() {
   230  			It("fails", func() {
   231  				value := 7
   232  				err := s.Serialize("namespaces", "fake", &value, fakeState)
   233  				Expect(err).To(MatchError("structure for namespace namespaces/fake is not serializable: must be pointers to struct, but got pointer to int"))
   234  			})
   235  		})
   236  
   237  		Context("when the argument contains an illegal field type", func() {
   238  			It("it fails", func() {
   239  				type BadStruct struct {
   240  					BadField int
   241  				}
   242  
   243  				err := s.Serialize("namespaces", "fake", &BadStruct{}, fakeState)
   244  				Expect(err).To(MatchError("structure for namespace namespaces/fake is not serializable: unsupported structure field kind int for serialization for field BadField"))
   245  			})
   246  		})
   247  
   248  		Context("when the argument contains a non-byte slice", func() {
   249  			It("it fails", func() {
   250  				type BadStruct struct {
   251  					BadField []uint64
   252  				}
   253  
   254  				err := s.Serialize("namespaces", "fake", &BadStruct{}, fakeState)
   255  				Expect(err).To(MatchError("structure for namespace namespaces/fake is not serializable: unsupported slice type uint64 for field BadField"))
   256  			})
   257  		})
   258  
   259  		Context("when the argument contains a non-proto pointer", func() {
   260  			It("it fails", func() {
   261  				type BadStruct struct {
   262  					BadField *int
   263  				}
   264  
   265  				err := s.Serialize("namespaces", "fake", &BadStruct{}, fakeState)
   266  				Expect(err).To(MatchError("structure for namespace namespaces/fake is not serializable: unsupported pointer type int for field BadField (must be proto)"))
   267  			})
   268  		})
   269  
   270  		Context("when the state metadata cannot be retrieved", func() {
   271  			BeforeEach(func() {
   272  				fakeState.GetStateReturns(nil, fmt.Errorf("state-error"))
   273  			})
   274  
   275  			It("wraps and returns the error", func() {
   276  				err := s.Serialize("namespaces", "fake", testStruct, fakeState)
   277  				Expect(err).To(MatchError("could not deserialize metadata for namespace namespaces/fake: could not query metadata for namespace namespaces/fake: state-error"))
   278  			})
   279  		})
   280  
   281  		Context("when the field data cannot be retrieved", func() {
   282  			BeforeEach(func() {
   283  				fakeState.GetStateReturnsOnCall(0, protoutil.MarshalOrPanic(&lb.StateMetadata{
   284  					Fields: []string{"field1"},
   285  				}), nil)
   286  				fakeState.GetStateReturnsOnCall(1, nil, fmt.Errorf("state-error"))
   287  			})
   288  
   289  			It("wraps and returns the error", func() {
   290  				err := s.Serialize("namespaces", "fake", testStruct, fakeState)
   291  				Expect(err).To(MatchError("could not get value for key namespaces/fields/fake/field1: state-error"))
   292  			})
   293  		})
   294  
   295  		Context("when writing to the state for a field fails", func() {
   296  			BeforeEach(func() {
   297  				fakeState.PutStateReturns(fmt.Errorf("put-error"))
   298  			})
   299  
   300  			It("wraps and returns the error", func() {
   301  				err := s.Serialize("namespaces", "fake", testStruct, fakeState)
   302  				Expect(err).To(MatchError("could not write key into state: put-error"))
   303  			})
   304  		})
   305  
   306  		Context("when writing to the state for metadata fails", func() {
   307  			BeforeEach(func() {
   308  				fakeState.PutStateReturns(fmt.Errorf("put-error"))
   309  			})
   310  
   311  			It("wraps and returns the error", func() {
   312  				type Other struct{}
   313  				err := s.Serialize("namespaces", "fake", &Other{}, fakeState)
   314  				Expect(err).To(MatchError("could not store metadata for namespace namespaces/fake: put-error"))
   315  			})
   316  		})
   317  
   318  		Context("when marshaling a field fails", func() {
   319  			BeforeEach(func() {
   320  				s.Marshaler = func(msg proto.Message) ([]byte, error) {
   321  					if _, ok := msg.(*lb.InstallChaincodeResult); !ok {
   322  						return proto.Marshal(msg)
   323  					}
   324  					return nil, fmt.Errorf("marshal-error")
   325  				}
   326  			})
   327  
   328  			It("wraps and returns the error", func() {
   329  				err := s.Serialize("namespaces", "fake", testStruct, fakeState)
   330  				Expect(err).To(MatchError("could not marshal field Proto: marshal-error"))
   331  			})
   332  		})
   333  
   334  		Context("when marshaling a field fails", func() {
   335  			BeforeEach(func() {
   336  				s.Marshaler = func(msg proto.Message) ([]byte, error) {
   337  					return nil, fmt.Errorf("marshal-error")
   338  				}
   339  			})
   340  
   341  			It("wraps and returns the error", func() {
   342  				err := s.Serialize("namespaces", "fake", testStruct, fakeState)
   343  				Expect(err).To(MatchError("could not marshal value for key namespaces/fields/fake/Int: marshal-error"))
   344  			})
   345  		})
   346  
   347  		Context("when marshaling a the metadata fails", func() {
   348  			BeforeEach(func() {
   349  				s.Marshaler = func(msg proto.Message) ([]byte, error) {
   350  					return nil, fmt.Errorf("marshal-error")
   351  				}
   352  			})
   353  
   354  			It("wraps and returns the error", func() {
   355  				type Other struct{}
   356  				err := s.Serialize("namespaces", "fake", &Other{}, fakeState)
   357  				Expect(err).To(MatchError("could not marshal metadata for namespace namespaces/fake: marshal-error"))
   358  			})
   359  		})
   360  	})
   361  
   362  	Describe("Deserialize", func() {
   363  		var (
   364  			kvs      map[string][]byte
   365  			metadata *lb.StateMetadata
   366  		)
   367  
   368  		BeforeEach(func() {
   369  			metadata = &lb.StateMetadata{
   370  				Datatype: "TestStruct",
   371  				Fields:   []string{"Int", "Bytes", "Proto"},
   372  			}
   373  
   374  			kvs = map[string][]byte{
   375  				"namespaces/fields/fake/Int": protoutil.MarshalOrPanic(&lb.StateData{
   376  					Type: &lb.StateData_Int64{Int64: -3},
   377  				}),
   378  				"namespaces/fields/fake/Bytes": protoutil.MarshalOrPanic(&lb.StateData{
   379  					Type: &lb.StateData_Bytes{Bytes: []byte("bytes")},
   380  				}),
   381  				"namespaces/fields/fake/Proto": protoutil.MarshalOrPanic(&lb.StateData{
   382  					Type: &lb.StateData_Bytes{Bytes: protoutil.MarshalOrPanic(testStruct.Proto)},
   383  				}),
   384  				"namespaces/fields/fake/String": protoutil.MarshalOrPanic(&lb.StateData{
   385  					Type: &lb.StateData_String_{String_: "theory"},
   386  				}),
   387  			}
   388  
   389  			fakeState.GetStateStub = func(key string) ([]byte, error) {
   390  				fmt.Println("returning", kvs[key], "for", key)
   391  				return kvs[key], nil
   392  			}
   393  		})
   394  
   395  		It("populates the given struct with values from the state", func() {
   396  			target := &TestStruct{}
   397  			err := s.Deserialize("namespaces", "fake", metadata, target, fakeState)
   398  			Expect(err).NotTo(HaveOccurred())
   399  
   400  			Expect(fakeState.GetStateCallCount()).To(Equal(4))
   401  
   402  			Expect(target.Int).To(Equal(int64(-3)))
   403  			Expect(target.Bytes).To(Equal([]byte("bytes")))
   404  			Expect(target.String).To(Equal("theory"))
   405  			Expect(proto.Equal(target.Proto, testStruct.Proto)).To(BeTrue())
   406  		})
   407  
   408  		Context("when the field encoding is bad", func() {
   409  			BeforeEach(func() {
   410  				kvs["namespaces/fields/fake/Int"] = []byte("bad-data")
   411  			})
   412  
   413  			It("fails", func() {
   414  				testStruct := &TestStruct{}
   415  				err := s.Deserialize("namespaces", "fake", metadata, testStruct, fakeState)
   416  				Expect(err).To(MatchError("could not unmarshal state for key namespaces/fields/fake/Int: unexpected EOF"))
   417  			})
   418  		})
   419  
   420  		Context("when the int is not the correct type", func() {
   421  			BeforeEach(func() {
   422  				kvs["namespaces/fields/fake/Int"] = kvs["namespaces/fields/fake/Proto"]
   423  			})
   424  
   425  			It("fails", func() {
   426  				testStruct := &TestStruct{}
   427  				err := s.Deserialize("namespaces", "fake", metadata, testStruct, fakeState)
   428  				Expect(err).To(MatchError("expected key namespaces/fields/fake/Int to encode a value of type Int64, but was *lifecycle.StateData_Bytes"))
   429  			})
   430  		})
   431  
   432  		Context("when the bytes are not the correct type", func() {
   433  			BeforeEach(func() {
   434  				kvs["namespaces/fields/fake/Bytes"] = kvs["namespaces/fields/fake/Int"]
   435  			})
   436  
   437  			It("fails", func() {
   438  				testStruct := &TestStruct{}
   439  				err := s.Deserialize("namespaces", "fake", metadata, testStruct, fakeState)
   440  				Expect(err).To(MatchError("expected key namespaces/fields/fake/Bytes to encode a value of type []byte, but was *lifecycle.StateData_Int64"))
   441  			})
   442  		})
   443  
   444  		Context("when the proto is not the correct type", func() {
   445  			BeforeEach(func() {
   446  				kvs["namespaces/fields/fake/Proto"] = kvs["namespaces/fields/fake/Int"]
   447  			})
   448  
   449  			It("fails", func() {
   450  				testStruct := &TestStruct{}
   451  				err := s.Deserialize("namespaces", "fake", metadata, testStruct, fakeState)
   452  				Expect(err).To(MatchError("expected key namespaces/fields/fake/Proto to encode a value of type []byte, but was *lifecycle.StateData_Int64"))
   453  			})
   454  		})
   455  
   456  		Context("when the bytes are not the correct type", func() {
   457  			BeforeEach(func() {
   458  				kvs["namespaces/fields/fake/String"] = kvs["namespaces/fields/fake/Int"]
   459  			})
   460  
   461  			It("fails", func() {
   462  				testStruct := &TestStruct{}
   463  				err := s.Deserialize("namespaces", "fake", metadata, testStruct, fakeState)
   464  				Expect(err).To(MatchError("expected key namespaces/fields/fake/String to encode a value of type String, but was *lifecycle.StateData_Int64"))
   465  			})
   466  		})
   467  
   468  		Context("when the state cannot be queried", func() {
   469  			BeforeEach(func() {
   470  				fakeState.GetStateReturns(nil, fmt.Errorf("state-error"))
   471  			})
   472  
   473  			It("fails", func() {
   474  				testStruct := &TestStruct{}
   475  				err := s.Deserialize("namespaces", "fake", metadata, testStruct, fakeState)
   476  				Expect(err).To(MatchError("could not get state for key namespaces/fields/fake/Int: state-error"))
   477  			})
   478  		})
   479  
   480  		Context("when the argument is not a pointer", func() {
   481  			It("fails", func() {
   482  				err := s.Deserialize("namespaces", "fake", metadata, 8, fakeState)
   483  				Expect(err).To(MatchError("could not deserialize namespace namespaces/fake to unserializable type int: must be pointer to struct, but got non-pointer int"))
   484  			})
   485  		})
   486  
   487  		Context("when the argument is a pointer to not-a-struct", func() {
   488  			It("fails", func() {
   489  				value := 7
   490  				err := s.Deserialize("namespaces", "fake", metadata, &value, fakeState)
   491  				Expect(err).To(MatchError("could not deserialize namespace namespaces/fake to unserializable type *int: must be pointers to struct, but got pointer to int"))
   492  			})
   493  		})
   494  
   495  		Context("when the argument does not match the stored type", func() {
   496  			It("it fails", func() {
   497  				type Other struct{}
   498  				err := s.Deserialize("namespaces", "fake", metadata, &Other{}, fakeState)
   499  				Expect(err).To(MatchError("type name mismatch 'Other' != 'TestStruct'"))
   500  			})
   501  		})
   502  
   503  		Context("when the argument contains an illegal field type", func() {
   504  			BeforeEach(func() {
   505  				kvs["namespaces/metadata/fake"] = protoutil.MarshalOrPanic(&lb.StateMetadata{
   506  					Datatype: "BadStruct",
   507  				})
   508  			})
   509  
   510  			It("it fails", func() {
   511  				type BadStruct struct {
   512  					BadField int
   513  				}
   514  
   515  				err := s.Deserialize("namespaces", "fake", metadata, &BadStruct{}, fakeState)
   516  				Expect(err).To(MatchError("could not deserialize namespace namespaces/fake to unserializable type *lifecycle_test.BadStruct: unsupported structure field kind int for serialization for field BadField"))
   517  			})
   518  		})
   519  	})
   520  
   521  	Describe("Integration Round Trip of Serialize/Deserialize", func() {
   522  		var KVStore map[string][]byte
   523  
   524  		BeforeEach(func() {
   525  			KVStore = map[string][]byte{}
   526  
   527  			fakeState.PutStateStub = func(key string, value []byte) error {
   528  				KVStore[key] = value
   529  				return nil
   530  			}
   531  
   532  			fakeState.GetStateStub = func(key string) ([]byte, error) {
   533  				return KVStore[key], nil
   534  			}
   535  
   536  			fakeState.GetStateHashStub = func(key string) ([]byte, error) {
   537  				return util.ComputeSHA256(KVStore[key]), nil
   538  			}
   539  		})
   540  
   541  		It("deserializes to the same value that was serialized in", func() {
   542  			err := s.Serialize("namespace", "fake", testStruct, fakeState)
   543  			Expect(err).NotTo(HaveOccurred())
   544  
   545  			metadata, ok, err := s.DeserializeMetadata("namespace", "fake", fakeState)
   546  			Expect(err).NotTo(HaveOccurred())
   547  			Expect(ok).To(BeTrue())
   548  			deserialized := &TestStruct{}
   549  			err = s.Deserialize("namespace", "fake", metadata, deserialized, fakeState)
   550  			Expect(err).NotTo(HaveOccurred())
   551  
   552  			Expect(testStruct.Int).To(Equal(deserialized.Int))
   553  			Expect(proto.Equal(testStruct.Proto, deserialized.Proto))
   554  
   555  			matched, err := s.IsSerialized("namespace", "fake", testStruct, fakeState)
   556  			Expect(err).NotTo(HaveOccurred())
   557  			Expect(matched).To(BeTrue())
   558  		})
   559  	})
   560  
   561  	Describe("IsMetadataSerialized", func() {
   562  		var kvs map[string][]byte
   563  
   564  		BeforeEach(func() {
   565  			kvs = map[string][]byte{
   566  				"namespaces/metadata/fake": protoutil.MarshalOrPanic(&lb.StateMetadata{
   567  					Datatype: "TestStruct",
   568  					Fields:   []string{"Int", "Bytes", "Proto", "String"},
   569  				}),
   570  			}
   571  
   572  			fakeState.GetStateHashStub = func(key string) ([]byte, error) {
   573  				return util.ComputeSHA256(kvs[key]), nil
   574  			}
   575  		})
   576  
   577  		It("checks to see if the metadata type is stored in the opaque state", func() {
   578  			matched, err := s.IsMetadataSerialized("namespaces", "fake", testStruct, fakeState)
   579  			Expect(err).NotTo(HaveOccurred())
   580  			Expect(matched).To(BeTrue())
   581  
   582  			Expect(fakeState.GetStateHashCallCount()).To(Equal(1))
   583  			Expect(fakeState.GetStateHashArgsForCall(0)).To(Equal("namespaces/metadata/fake"))
   584  		})
   585  
   586  		Context("when the struct is not serializable", func() {
   587  			It("wraps and returns the error", func() {
   588  				_, err := s.IsMetadataSerialized("namespaces", "fake", nil, fakeState)
   589  				Expect(err).To(MatchError("structure for namespace namespaces/fake is not serializable: must be pointer to struct, but got non-pointer invalid"))
   590  			})
   591  		})
   592  
   593  		Context("when marshaling the metadata fails", func() {
   594  			BeforeEach(func() {
   595  				s.Marshaler = func(msg proto.Message) ([]byte, error) {
   596  					return nil, fmt.Errorf("marshal-error")
   597  				}
   598  			})
   599  
   600  			It("wraps and returns the error", func() {
   601  				type Other struct{}
   602  				_, err := s.IsMetadataSerialized("namespaces", "fake", &Other{}, fakeState)
   603  				Expect(err).To(MatchError("could not marshal metadata for namespace namespaces/fake: marshal-error"))
   604  			})
   605  		})
   606  	})
   607  
   608  	Describe("IsSerialized", func() {
   609  		var kvs map[string][]byte
   610  
   611  		BeforeEach(func() {
   612  			kvs = map[string][]byte{
   613  				"namespaces/fields/fake/Int": protoutil.MarshalOrPanic(&lb.StateData{
   614  					Type: &lb.StateData_Int64{Int64: -3},
   615  				}),
   616  				"namespaces/fields/fake/Bytes": protoutil.MarshalOrPanic(&lb.StateData{
   617  					Type: &lb.StateData_Bytes{Bytes: []byte("bytes")},
   618  				}),
   619  				"namespaces/fields/fake/Proto": protoutil.MarshalOrPanic(&lb.StateData{
   620  					Type: &lb.StateData_Bytes{Bytes: protoutil.MarshalOrPanic(testStruct.Proto)},
   621  				}),
   622  				"namespaces/fields/fake/String": protoutil.MarshalOrPanic(&lb.StateData{
   623  					Type: &lb.StateData_String_{String_: "theory"},
   624  				}),
   625  				"namespaces/metadata/fake": protoutil.MarshalOrPanic(&lb.StateMetadata{
   626  					Datatype: "TestStruct",
   627  					Fields:   []string{"Int", "Bytes", "Proto", "String"},
   628  				}),
   629  			}
   630  
   631  			fakeState.GetStateHashStub = func(key string) ([]byte, error) {
   632  				return util.ComputeSHA256(kvs[key]), nil
   633  			}
   634  		})
   635  
   636  		It("checks to see if the structure is stored in the opaque state", func() {
   637  			matched, err := s.IsSerialized("namespaces", "fake", testStruct, fakeState)
   638  			Expect(err).NotTo(HaveOccurred())
   639  			Expect(matched).To(BeTrue())
   640  
   641  			Expect(fakeState.GetStateHashCallCount()).To(Equal(5))
   642  			Expect(fakeState.GetStateHashArgsForCall(0)).To(Equal("namespaces/metadata/fake"))
   643  			Expect(fakeState.GetStateHashArgsForCall(1)).To(Equal("namespaces/fields/fake/Int"))
   644  			Expect(fakeState.GetStateHashArgsForCall(2)).To(Equal("namespaces/fields/fake/Bytes"))
   645  			Expect(fakeState.GetStateHashArgsForCall(3)).To(Equal("namespaces/fields/fake/Proto"))
   646  			Expect(fakeState.GetStateHashArgsForCall(4)).To(Equal("namespaces/fields/fake/String"))
   647  		})
   648  
   649  		Context("when the namespace contains extraneous keys", func() {
   650  			BeforeEach(func() {
   651  				kvs["namespaces/metadata/fake"] = protoutil.MarshalOrPanic(&lb.StateMetadata{
   652  					Datatype: "TestStruct",
   653  					Fields:   []string{"Int", "Uint", "String", "Bytes", "Other"},
   654  				})
   655  				kvs["namespaces/fields/fake/Other"] = protoutil.MarshalOrPanic(&lb.StateData{
   656  					Type: &lb.StateData_Bytes{Bytes: []byte("value1")},
   657  				})
   658  			})
   659  
   660  			It("returns a mismatch", func() {
   661  				matched, err := s.IsSerialized("namespaces", "fake", testStruct, fakeState)
   662  				Expect(err).NotTo(HaveOccurred())
   663  				Expect(matched).To(BeFalse())
   664  			})
   665  		})
   666  
   667  		Context("when the namespace contains different keys", func() {
   668  			BeforeEach(func() {
   669  				kvs["namespaces/fields/fake/Int"] = protoutil.MarshalOrPanic(&lb.StateData{
   670  					Type: &lb.StateData_Bytes{Bytes: []byte("value1")},
   671  				})
   672  			})
   673  
   674  			It("returns a mismatch", func() {
   675  				matched, err := s.IsSerialized("namespaces", "fake", testStruct, fakeState)
   676  				Expect(err).NotTo(HaveOccurred())
   677  				Expect(matched).To(BeFalse())
   678  			})
   679  		})
   680  
   681  		Context("when the argument is not a pointer", func() {
   682  			It("fails", func() {
   683  				_, err := s.IsSerialized("namespaces", "fake", 8, fakeState)
   684  				Expect(err).To(MatchError("structure for namespace namespaces/fake is not serializable: must be pointer to struct, but got non-pointer int"))
   685  			})
   686  		})
   687  
   688  		Context("when the namespace does not contains the keys and values", func() {
   689  			BeforeEach(func() {
   690  				kvs = map[string][]byte{}
   691  			})
   692  
   693  			It("returns a mismatch", func() {
   694  				matched, err := s.IsSerialized("namespaces", "fake", testStruct, fakeState)
   695  				Expect(err).NotTo(HaveOccurred())
   696  				Expect(matched).To(BeFalse())
   697  			})
   698  		})
   699  
   700  		Context("when the state metadata cannot be retrieved", func() {
   701  			BeforeEach(func() {
   702  				fakeState.GetStateHashReturns(nil, fmt.Errorf("state-error"))
   703  			})
   704  
   705  			It("wraps and returns the error", func() {
   706  				_, err := s.IsSerialized("namespaces", "fake", testStruct, fakeState)
   707  				Expect(err).To(MatchError("could not get value for key namespaces/metadata/fake: state-error"))
   708  			})
   709  		})
   710  
   711  		Context("when inner marshaling of a proto field fails", func() {
   712  			BeforeEach(func() {
   713  				s.Marshaler = func(msg proto.Message) ([]byte, error) {
   714  					if _, ok := msg.(*lb.StateMetadata); ok {
   715  						return proto.Marshal(msg)
   716  					}
   717  					if _, ok := msg.(*lb.StateData); ok {
   718  						return proto.Marshal(msg)
   719  					}
   720  					return nil, fmt.Errorf("marshal-error")
   721  				}
   722  			})
   723  
   724  			It("wraps and returns the error", func() {
   725  				_, err := s.IsSerialized("namespaces", "fake", testStruct, fakeState)
   726  				Expect(err).To(MatchError("could not marshal field Proto: marshal-error"))
   727  			})
   728  		})
   729  
   730  		Context("when marshaling a field fails", func() {
   731  			BeforeEach(func() {
   732  				s.Marshaler = func(msg proto.Message) ([]byte, error) {
   733  					if _, ok := msg.(*lb.StateData); ok {
   734  						return nil, fmt.Errorf("marshal-error")
   735  					}
   736  					return proto.Marshal(msg)
   737  				}
   738  			})
   739  
   740  			It("wraps and returns the error", func() {
   741  				_, err := s.IsSerialized("namespaces", "fake", testStruct, fakeState)
   742  				Expect(err).To(MatchError("could not marshal value for key namespaces/fields/fake/Int: marshal-error"))
   743  			})
   744  		})
   745  
   746  		Context("when marshaling a the metadata fails", func() {
   747  			BeforeEach(func() {
   748  				s.Marshaler = func(msg proto.Message) ([]byte, error) {
   749  					return nil, fmt.Errorf("marshal-error")
   750  				}
   751  			})
   752  
   753  			It("wraps and returns the error", func() {
   754  				type Other struct{}
   755  				_, err := s.IsSerialized("namespaces", "fake", &Other{}, fakeState)
   756  				Expect(err).To(MatchError("could not marshal metadata for namespace namespaces/fake: marshal-error"))
   757  			})
   758  		})
   759  	})
   760  
   761  	Describe("DeserializeAllMetadata", func() {
   762  		BeforeEach(func() {
   763  			fakeState.GetStateRangeReturns(map[string][]byte{
   764  				"namespaces/metadata/thing0": protoutil.MarshalOrPanic(&lb.StateMetadata{
   765  					Datatype: "TestDatatype0",
   766  				}),
   767  				"namespaces/metadata/thing1": protoutil.MarshalOrPanic(&lb.StateMetadata{
   768  					Datatype: "TestDatatype1",
   769  				}),
   770  				"namespaces/metadata/thing2": protoutil.MarshalOrPanic(&lb.StateMetadata{
   771  					Datatype: "TestDatatype2",
   772  				}),
   773  			}, nil)
   774  		})
   775  
   776  		It("deserializes all the metadata", func() {
   777  			result, err := s.DeserializeAllMetadata("namespaces", fakeState)
   778  			Expect(err).NotTo(HaveOccurred())
   779  			Expect(len(result)).To(Equal(3))
   780  			Expect(proto.Equal(result["thing0"], &lb.StateMetadata{Datatype: "TestDatatype0"})).To(BeTrue())
   781  			Expect(proto.Equal(result["thing1"], &lb.StateMetadata{Datatype: "TestDatatype1"})).To(BeTrue())
   782  			Expect(proto.Equal(result["thing2"], &lb.StateMetadata{Datatype: "TestDatatype2"})).To(BeTrue())
   783  
   784  			Expect(fakeState.GetStateRangeCallCount()).To(Equal(1))
   785  			Expect(fakeState.GetStateRangeArgsForCall(0)).To(Equal("namespaces/metadata/"))
   786  		})
   787  
   788  		Context("when GetStateRange returns an error", func() {
   789  			BeforeEach(func() {
   790  				fakeState.GetStateRangeReturns(nil, fmt.Errorf("get-state-range-error"))
   791  			})
   792  
   793  			It("wraps and returns the error", func() {
   794  				_, err := s.DeserializeAllMetadata("namespaces", fakeState)
   795  				Expect(err).To(MatchError("could not get state range for namespace namespaces: get-state-range-error"))
   796  			})
   797  		})
   798  
   799  		Context("when GetState returns nil", func() {
   800  			BeforeEach(func() {
   801  				fakeState.GetStateRangeReturns(nil, nil)
   802  			})
   803  
   804  			It("returns an empty map", func() {
   805  				result, err := s.DeserializeAllMetadata("namespaces", fakeState)
   806  				Expect(err).NotTo(HaveOccurred())
   807  				Expect(result).To(BeEmpty())
   808  			})
   809  		})
   810  
   811  		Context("when the metadata is invalid", func() {
   812  			BeforeEach(func() {
   813  				fakeState.GetStateRangeReturns(map[string][]byte{"namespaces/metadata/bad": []byte("bad-data")}, nil)
   814  			})
   815  
   816  			It("returns an error", func() {
   817  				_, err := s.DeserializeAllMetadata("namespaces", fakeState)
   818  				Expect(err).To(MatchError("error unmarshalling metadata for key namespaces/metadata/bad: unexpected EOF"))
   819  			})
   820  		})
   821  	})
   822  
   823  	Describe("DeserializeMetadata", func() {
   824  		BeforeEach(func() {
   825  			fakeState.GetStateReturns(protoutil.MarshalOrPanic(&lb.StateMetadata{
   826  				Datatype: "TestDatatype",
   827  			}), nil)
   828  		})
   829  
   830  		It("deserializes the metadata", func() {
   831  			result, ok, err := s.DeserializeMetadata("namespaces", "fake", fakeState)
   832  			Expect(err).NotTo(HaveOccurred())
   833  			Expect(ok).To(BeTrue())
   834  			Expect(proto.Equal(result, &lb.StateMetadata{Datatype: "TestDatatype"})).To(BeTrue())
   835  
   836  			Expect(fakeState.GetStateCallCount()).To(Equal(1))
   837  			Expect(fakeState.GetStateArgsForCall(0)).To(Equal("namespaces/metadata/fake"))
   838  		})
   839  
   840  		Context("when GetState returns an error", func() {
   841  			BeforeEach(func() {
   842  				fakeState.GetStateReturns(nil, fmt.Errorf("get-state-error"))
   843  			})
   844  
   845  			It("wraps and returns the error", func() {
   846  				_, _, err := s.DeserializeMetadata("namespaces", "fake", fakeState)
   847  				Expect(err).To(MatchError("could not query metadata for namespace namespaces/fake: get-state-error"))
   848  			})
   849  		})
   850  
   851  		Context("when GetState returns nil", func() {
   852  			BeforeEach(func() {
   853  				fakeState.GetStateReturns(nil, nil)
   854  			})
   855  
   856  			It("returns an error", func() {
   857  				_, ok, err := s.DeserializeMetadata("namespaces", "fake", fakeState)
   858  				Expect(err).NotTo(HaveOccurred())
   859  				Expect(ok).To(BeFalse())
   860  			})
   861  		})
   862  
   863  		Context("when the metadata is invalid", func() {
   864  			BeforeEach(func() {
   865  				fakeState.GetStateReturns([]byte("bad-data"), nil)
   866  			})
   867  
   868  			It("returns an error", func() {
   869  				_, _, err := s.DeserializeMetadata("namespaces", "fake", fakeState)
   870  				Expect(err).To(MatchError("could not unmarshal metadata for namespace namespaces/fake: unexpected EOF"))
   871  			})
   872  		})
   873  	})
   874  
   875  	Describe("DeserializeFieldAsBytes", func() {
   876  		BeforeEach(func() {
   877  			fakeState.GetStateReturns(protoutil.MarshalOrPanic(&lb.StateData{
   878  				Type: &lb.StateData_Bytes{Bytes: []byte("bytes")},
   879  			}), nil)
   880  		})
   881  
   882  		It("deserializes the field to a string", func() {
   883  			result, err := s.DeserializeFieldAsBytes("namespaces", "fake", "field", fakeState)
   884  			Expect(err).NotTo(HaveOccurred())
   885  			Expect(result).To(Equal([]byte("bytes")))
   886  
   887  			Expect(fakeState.GetStateCallCount()).To(Equal(1))
   888  			Expect(fakeState.GetStateArgsForCall(0)).To(Equal("namespaces/fields/fake/field"))
   889  		})
   890  
   891  		Context("when GetState returns an error", func() {
   892  			BeforeEach(func() {
   893  				fakeState.GetStateReturns(nil, fmt.Errorf("get-state-error"))
   894  			})
   895  
   896  			It("wraps and returns the error", func() {
   897  				_, err := s.DeserializeFieldAsBytes("namespaces", "fake", "field", fakeState)
   898  				Expect(err).To(MatchError("could not get state for key namespaces/fields/fake/field: get-state-error"))
   899  			})
   900  		})
   901  
   902  		Context("when GetState returns nil", func() {
   903  			BeforeEach(func() {
   904  				fakeState.GetStateReturns(nil, nil)
   905  			})
   906  
   907  			It("returns nil", func() {
   908  				result, err := s.DeserializeFieldAsBytes("namespaces", "fake", "field", fakeState)
   909  				Expect(err).NotTo(HaveOccurred())
   910  				Expect(result).To(BeNil())
   911  			})
   912  		})
   913  	})
   914  
   915  	Describe("DeserializeFieldAsProto", func() {
   916  		BeforeEach(func() {
   917  			fakeState.GetStateReturns(protoutil.MarshalOrPanic(&lb.StateData{
   918  				Type: &lb.StateData_Bytes{Bytes: protoutil.MarshalOrPanic(&lb.InstallChaincodeResult{PackageId: "hash"})},
   919  			}), nil)
   920  		})
   921  
   922  		It("deserializes the field to a string", func() {
   923  			result := &lb.InstallChaincodeResult{}
   924  			err := s.DeserializeFieldAsProto("namespaces", "fake", "field", fakeState, result)
   925  			Expect(err).NotTo(HaveOccurred())
   926  			Expect(proto.Equal(result, &lb.InstallChaincodeResult{PackageId: "hash"})).To(BeTrue())
   927  
   928  			Expect(fakeState.GetStateCallCount()).To(Equal(1))
   929  			Expect(fakeState.GetStateArgsForCall(0)).To(Equal("namespaces/fields/fake/field"))
   930  		})
   931  
   932  		Context("when GetState returns an error", func() {
   933  			BeforeEach(func() {
   934  				fakeState.GetStateReturns(nil, fmt.Errorf("get-state-error"))
   935  			})
   936  
   937  			It("wraps and returns the error", func() {
   938  				err := s.DeserializeFieldAsProto("namespaces", "fake", "field", fakeState, &lb.InstallChaincodeResult{})
   939  				Expect(err).To(MatchError("could not get state for key namespaces/fields/fake/field: get-state-error"))
   940  			})
   941  		})
   942  
   943  		Context("when GetState returns nil", func() {
   944  			BeforeEach(func() {
   945  				fakeState.GetStateReturns(nil, nil)
   946  			})
   947  
   948  			It("does nothing", func() {
   949  				result := &lb.InstallChaincodeResult{}
   950  				err := s.DeserializeFieldAsProto("namespaces", "fake", "field", fakeState, result)
   951  				Expect(err).NotTo(HaveOccurred())
   952  				Expect(proto.Equal(result, &lb.InstallChaincodeResult{})).To(BeTrue())
   953  			})
   954  		})
   955  
   956  		Context("when the db does not encode a proto", func() {
   957  			BeforeEach(func() {
   958  				fakeState.GetStateReturns(protoutil.MarshalOrPanic(&lb.StateData{
   959  					Type: &lb.StateData_Bytes{Bytes: []byte("garbage")},
   960  				}), nil)
   961  			})
   962  
   963  			It("wraps and returns the error", func() {
   964  				err := s.DeserializeFieldAsProto("namespaces", "fake", "field", fakeState, &lb.InstallChaincodeResult{})
   965  				Expect(err).To(MatchError("could not unmarshal key namespaces/fields/fake/field to *lifecycle.InstallChaincodeResult: proto: can't skip unknown wire type 7"))
   966  			})
   967  		})
   968  	})
   969  
   970  	Describe("DeserializeFieldAsInt64", func() {
   971  		BeforeEach(func() {
   972  			fakeState.GetStateReturns(protoutil.MarshalOrPanic(&lb.StateData{
   973  				Type: &lb.StateData_Int64{Int64: -3},
   974  			}), nil)
   975  		})
   976  
   977  		It("deserializes the field to a string", func() {
   978  			result, err := s.DeserializeFieldAsInt64("namespaces", "fake", "field", fakeState)
   979  			Expect(err).NotTo(HaveOccurred())
   980  			Expect(result).To(Equal(int64(-3)))
   981  
   982  			Expect(fakeState.GetStateCallCount()).To(Equal(1))
   983  			Expect(fakeState.GetStateArgsForCall(0)).To(Equal("namespaces/fields/fake/field"))
   984  		})
   985  
   986  		Context("when GetState returns an error", func() {
   987  			BeforeEach(func() {
   988  				fakeState.GetStateReturns(nil, fmt.Errorf("get-state-error"))
   989  			})
   990  
   991  			It("wraps and returns the error", func() {
   992  				_, err := s.DeserializeFieldAsInt64("namespaces", "fake", "field", fakeState)
   993  				Expect(err).To(MatchError("could not get state for key namespaces/fields/fake/field: get-state-error"))
   994  			})
   995  		})
   996  
   997  		Context("when GetState returns nil", func() {
   998  			BeforeEach(func() {
   999  				fakeState.GetStateReturns(nil, nil)
  1000  			})
  1001  
  1002  			It("returns nil", func() {
  1003  				result, err := s.DeserializeFieldAsInt64("namespaces", "fake", "field", fakeState)
  1004  				Expect(err).NotTo(HaveOccurred())
  1005  				Expect(result).To(Equal(int64(0)))
  1006  			})
  1007  		})
  1008  
  1009  		Context("when the field has trailing data", func() {
  1010  			BeforeEach(func() {
  1011  				fakeState.GetStateReturns([]byte("bad-data"), nil)
  1012  			})
  1013  
  1014  			It("returns an error", func() {
  1015  				_, err := s.DeserializeFieldAsInt64("namespaces", "fake", "field", fakeState)
  1016  				Expect(err).To(MatchError("could not unmarshal state for key namespaces/fields/fake/field: unexpected EOF"))
  1017  			})
  1018  		})
  1019  	})
  1020  
  1021  	Describe("DeserializeFieldAsString", func() {
  1022  		BeforeEach(func() {
  1023  			fakeState.GetStateReturns(protoutil.MarshalOrPanic(&lb.StateData{
  1024  				Type: &lb.StateData_String_{String_: "theory"},
  1025  			}), nil)
  1026  		})
  1027  
  1028  		It("deserializes the field to a string", func() {
  1029  			result, err := s.DeserializeFieldAsString("namespaces", "fake", "field", fakeState)
  1030  			Expect(err).NotTo(HaveOccurred())
  1031  			Expect(result).To(Equal("theory"))
  1032  
  1033  			Expect(fakeState.GetStateCallCount()).To(Equal(1))
  1034  			Expect(fakeState.GetStateArgsForCall(0)).To(Equal("namespaces/fields/fake/field"))
  1035  		})
  1036  
  1037  		Context("when GetState returns an error", func() {
  1038  			BeforeEach(func() {
  1039  				fakeState.GetStateReturns(nil, fmt.Errorf("get-state-error"))
  1040  			})
  1041  
  1042  			It("wraps and returns the error", func() {
  1043  				_, err := s.DeserializeFieldAsString("namespaces", "fake", "field", fakeState)
  1044  				Expect(err).To(MatchError("could not get state for key namespaces/fields/fake/field: get-state-error"))
  1045  			})
  1046  		})
  1047  
  1048  		Context("when GetState returns nil", func() {
  1049  			BeforeEach(func() {
  1050  				fakeState.GetStateReturns(nil, nil)
  1051  			})
  1052  
  1053  			It("returns nil", func() {
  1054  				result, err := s.DeserializeFieldAsString("namespaces", "fake", "field", fakeState)
  1055  				Expect(err).NotTo(HaveOccurred())
  1056  				Expect(result).To(Equal(""))
  1057  			})
  1058  		})
  1059  
  1060  		Context("when the field has trailing data", func() {
  1061  			BeforeEach(func() {
  1062  				fakeState.GetStateReturns([]byte("bad-data"), nil)
  1063  			})
  1064  
  1065  			It("returns an error", func() {
  1066  				_, err := s.DeserializeFieldAsString("namespaces", "fake", "field", fakeState)
  1067  				Expect(err).To(MatchError("could not unmarshal state for key namespaces/fields/fake/field: unexpected EOF"))
  1068  			})
  1069  		})
  1070  	})
  1071  })