Chris Sargent
Chris Sargent

Reputation: 321

How to perform unit tests on Hyperledger Fabric Go chaincode which uses ACL controls?

I am currently writing some unit tests for some Hyperledger Fabric chaincode functions, written in Go.

Some of the functions require a user with certain attributes or indeed just need to know the user's ID.

For example, some of the functions use the following methods from the github.com/hyperledger/fabric-chaincode-go/pkg/cid package:

I don't see how to create and / or pass an identity / certificate when using the mock shim package, github.com/hyperledger/fabric-chaincode-go/shimtest and calls fail with: failed to get transaction invoker's identity from the chaincode stub

Is it maybe possible to create and use fake, but acceptable certificates? Or is there some better way to mock these ACL parts?

Considering Hyperledger bills itself as being permissioned and having strict ACL opportunities, it seems surprising that this can't be tested (hence, I think I'm missing something!).

Upvotes: 1

Views: 1208

Answers (1)

Chris Sargent
Chris Sargent

Reputation: 321

After some more investigation, I found an example in the Hyperledger Fabric Samples repo, in the ABAC test files: https://github.com/hyperledger/fabric-samples/blob/master/chaincode/abac/go/abac_test.go.

In summary, it is not necessary to mock the calls to cid, it can be achieved by setting a creator on the mock stub, *shimtest.MockStub using stub.Creator. This means the calls actually interrogate the 'Creator' identity and methods like GetID() and AssertAttributeValue() work as expected.

Of course, you also need to generate some test certificates, first you need to (or similar). I generated various user certificates using my actual api / chaincode and then copied them off the api container in to a fixtures folder, but maybe there's an easier way (e.g. using the fabric ca client cli).

From the fabric samples link above, they have this helper function which I have used:

func setCreator(t *testing.T, stub *shimtest.MockStub, mspID string, idbytes []byte) {
    sid := &msp.SerializedIdentity{Mspid: mspID, IdBytes: idbytes}
    b, err := proto.Marshal(sid)
    if err != nil {
        t.FailNow()
    }
    stub.Creator = b
}

and then this can be used like this:

func TestInit(t *testing.T) (stub *shimtest.MockStub) {
    cc := new(Chaincode)
    stub = shimtest.NewMockStub("__TEST__", cc)
    setCreator(t, stub, "org1MSP", []byte(fixtures.Cert))
    return stub
}

where fixtures.Cert is your certificate as a string. After this is done, you can also call the GetCreator function to verify the identity has been set, using something like

    cert, _ := stub.GetCreator()
    fmt.Println(string(cert))

Hope that helps someone out!

Upvotes: 4

Related Questions