Skip to content

Commit

Permalink
FAB-13512 Add lifecycle integration test
Browse files Browse the repository at this point in the history
This integration test is supposed to perform basic sanity checking that
the assorted pieces of lifecycle all wire through correctly.

It begins with an empty db, then defines a chaincode for the org,
defines it for the channel, queries the defined namespaces, and finally
queries the defined chaincode (all done through the SCC interface with
mocked db which reads own writes to simulate commitment).

Change-Id: I9cabca1614be7cadc65425e9815ca6e6ed4cebec
Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
  • Loading branch information
Jason Yellick committed Jan 29, 2019
1 parent 81b05aa commit 6938e09
Show file tree
Hide file tree
Showing 3 changed files with 194 additions and 4 deletions.
181 changes: 181 additions & 0 deletions core/chaincode/lifecycle/integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package lifecycle_test

import (
"github.com/hyperledger/fabric/common/channelconfig"
"github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/core/chaincode/lifecycle"
"github.com/hyperledger/fabric/core/chaincode/lifecycle/mock"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/core/dispatcher"
"github.com/hyperledger/fabric/protos/ledger/queryresult"
lb "github.com/hyperledger/fabric/protos/peer/lifecycle"
"github.com/hyperledger/fabric/protos/utils"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

"github.com/golang/protobuf/proto"
)

var _ = Describe("Integration", func() {
var (
l *lifecycle.Lifecycle
scc *lifecycle.SCC

fakeChannelConfigSource *mock.ChannelConfigSource
fakeChannelConfig *mock.ChannelConfig
fakeApplicationConfig *mock.ApplicationConfig
fakeOrgConfig *mock.ApplicationOrgConfig
fakeStub *mock.ChaincodeStub

fakeOrgKVStore map[string][]byte
fakePublicKVStore map[string][]byte
)

BeforeEach(func() {
l = &lifecycle.Lifecycle{
Serializer: &lifecycle.Serializer{},
}

fakeChannelConfigSource = &mock.ChannelConfigSource{}
fakeChannelConfig = &mock.ChannelConfig{}
fakeChannelConfigSource.GetStableChannelConfigReturns(fakeChannelConfig)
fakeApplicationConfig = &mock.ApplicationConfig{}
fakeChannelConfig.ApplicationConfigReturns(fakeApplicationConfig, true)

fakeOrgConfig = &mock.ApplicationOrgConfig{}
fakeOrgConfig.MSPIDReturns("fake-mspid")

fakeApplicationConfig.OrganizationsReturns(map[string]channelconfig.ApplicationOrg{
"fakeOrg": fakeOrgConfig,
})

scc = &lifecycle.SCC{
Dispatcher: &dispatcher.Dispatcher{
Protobuf: &dispatcher.ProtobufImpl{},
},
Functions: l,
OrgMSPID: "fake-mspid",
ChannelConfigSource: fakeChannelConfigSource,
}

fakePublicKVStore = map[string][]byte{}
fakeOrgKVStore = map[string][]byte{}

fakeStub = &mock.ChaincodeStub{}
fakeStub.GetStateStub = func(key string) ([]byte, error) {
return fakePublicKVStore[key], nil
}
fakeStub.PutStateStub = func(key string, value []byte) error {
fakePublicKVStore[key] = value
return nil
}
fakeStub.GetStateByRangeStub = func(begin, end string) (shim.StateQueryIteratorInterface, error) {
fakeIterator := &mock.StateIterator{}
i := 0
for key, value := range fakePublicKVStore {
if key >= begin && key < end {
fakeIterator.HasNextReturnsOnCall(i, true)
fakeIterator.NextReturnsOnCall(i, &queryresult.KV{
Key: key,
Value: value,
}, nil)
i++
}
}
return fakeIterator, nil
}

fakeStub.PutPrivateDataStub = func(collection, key string, value []byte) error {
fakeOrgKVStore[key] = value
return nil
}

fakeStub.GetPrivateDataStub = func(collection, key string) ([]byte, error) {
return fakeOrgKVStore[key], nil
}

fakeStub.GetPrivateDataHashStub = func(collection, key string) ([]byte, error) {
return util.ComputeSHA256(fakeOrgKVStore[key]), nil
}
})

Describe("Instantiation", func() {
It("defines the chaincode for the org, defines it for the channel, queries all namespaces, and queries the chaincode", func() {
// Define for the org
fakeStub.GetArgsReturns([][]byte{
[]byte("DefineChaincodeForMyOrg"),
utils.MarshalOrPanic(&lb.DefineChaincodeForMyOrgArgs{
Name: "cc-name",
Version: "1.0",
Sequence: 1,
EndorsementPlugin: "builtin",
ValidationPlugin: "builtin",
ValidationParameter: []byte("validation-parameter"),
Hash: []byte("hash-value"),
}),
})
response := scc.Invoke(fakeStub)
Expect(response.Status).To(Equal(int32(200)))

// Define for the channel
fakeStub.GetArgsReturns([][]byte{
[]byte("DefineChaincode"),
utils.MarshalOrPanic(&lb.DefineChaincodeArgs{
Name: "cc-name",
Version: "1.0",
Sequence: 1,
EndorsementPlugin: "builtin",
ValidationPlugin: "builtin",
ValidationParameter: []byte("validation-parameter"),
Hash: []byte("hash-value"),
}),
})
response = scc.Invoke(fakeStub)
Expect(response.Status).To(Equal(int32(200)))

// Get channel definitions
fakeStub.GetArgsReturns([][]byte{
[]byte("QueryDefinedNamespaces"),
utils.MarshalOrPanic(&lb.QueryDefinedNamespacesArgs{}),
})
response = scc.Invoke(fakeStub)
Expect(response.Status).To(Equal(int32(200)))
namespaceResult := &lb.QueryDefinedNamespacesResult{}
err := proto.Unmarshal(response.Payload, namespaceResult)
Expect(err).NotTo(HaveOccurred())
Expect(len(namespaceResult.Namespaces)).To(Equal(1))
namespace, ok := namespaceResult.Namespaces["cc-name"]
Expect(ok).To(BeTrue())
Expect(namespace.Type).To(Equal("Chaincode"))

// Get chaincode definition details
fakeStub.GetArgsReturns([][]byte{
[]byte("QueryDefinedChaincode"),
utils.MarshalOrPanic(&lb.QueryDefinedChaincodeArgs{
Name: "cc-name",
}),
})
response = scc.Invoke(fakeStub)
Expect(response.Status).To(Equal(int32(200)))
chaincodeResult := &lb.QueryDefinedChaincodeResult{}
err = proto.Unmarshal(response.Payload, chaincodeResult)
Expect(err).NotTo(HaveOccurred())
Expect(proto.Equal(chaincodeResult, &lb.QueryDefinedChaincodeResult{
Sequence: 1,
Version: "1.0",
EndorsementPlugin: "builtin",
ValidationPlugin: "builtin",
ValidationParameter: []byte("validation-parameter"),
Hash: []byte("hash-value"),
})).To(BeTrue())
})
})

})
3 changes: 1 addition & 2 deletions core/chaincode/lifecycle/ledger_shim.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ func (cls *ChaincodePrivateLedgerShim) GetState(key string) ([]byte, error) {

// GetStateHash return the hash of the pre-image for the key in the configured collection.
func (cls *ChaincodePrivateLedgerShim) GetStateHash(key string) ([]byte, error) {
// XXX implement me
panic("unimplemented")
return cls.Stub.GetPrivateDataHash(cls.Collection, key)
}

// PutState sets the value for the key in the configured collection.
Expand Down
14 changes: 12 additions & 2 deletions core/chaincode/lifecycle/ledger_shim_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,18 @@ var _ = Describe("LedgerShims", func() {
})

Describe("GetStateHash", func() {
It("panics", func() {
Expect(func() { cls.GetStateHash("fake-key") }).To(Panic())
BeforeEach(func() {
fakeStub.GetPrivateDataHashReturns([]byte("fake-hash"), fmt.Errorf("fake-error"))
})

It("passes through to the chaincode stub", func() {
res, err := cls.GetStateHash("fake-key")
Expect(res).To(Equal([]byte("fake-hash")))
Expect(err).To(MatchError("fake-error"))
Expect(fakeStub.GetPrivateDataHashCallCount()).To(Equal(1))
collection, key := fakeStub.GetPrivateDataHashArgsForCall(0)
Expect(collection).To(Equal("fake-collection"))
Expect(key).To(Equal("fake-key"))
})
})

Expand Down

0 comments on commit 6938e09

Please sign in to comment.