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