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 })