-
Notifications
You must be signed in to change notification settings - Fork 145
Implement and test getMultipleStates
method for Stub API.
#454
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -277,6 +277,8 @@ class ChaincodeMessageHandler { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
constructor(stream, chaincode) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
this._stream = stream; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
this.chaincode = chaincode; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
this.usePeerGetMultipleKeys = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
this.maxSizeGetMultipleKeys = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// this is a long-running method that does not return until | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -388,6 +390,65 @@ class ChaincodeMessageHandler { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return await this._askPeerAndListen(msg, 'GetState'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
async handleGetMultipleStates(collection, keys, channel_id, txId) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (keys.length === 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const responses = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!this.usePeerGetMultipleKeys) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for (const key of keys) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const resp = await this.handleGetState(collection, key, channel_id, txId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
responses.push(resp); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return responses; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let remainingKeys = [...keys]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess you are doing this to take a copy and avoid modifying the keys array passed in by the caller? I don't think this will be necessary since slice will return a new array rather than modifying the original array. If it is a concern, it might be worth adding a unit test to confirm that the caller's array is not modified. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
while (remainingKeys.length > this.maxSizeGetMultipleKeys) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const batch = remainingKeys.slice(0, this.maxSizeGetMultipleKeys); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const resp = await this.handleOneSendGetMultipleStates(collection, batch, channel_id, txId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
responses.push(...resp); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
remainingKeys = remainingKeys.slice(this.maxSizeGetMultipleKeys); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (remainingKeys.length > 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const resp = await this.handleOneSendGetMultipleStates(collection, remainingKeys, channel_id, txId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
responses.push(...resp); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return responses.map(r => (r.length === 0 ? null : r)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+409
to
+421
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. slice handles out of bounds indexes cleanly so this should not need the multiple loops that the Go implementation uses. You might be able to simplify the implementation similar to the following:
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
async handleOneSendGetMultipleStates(collection, keys, channel_id, txId) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const msgPb = new peer.GetStateMultiple(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
msgPb.setCollection(collection); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
msgPb.setKeysList(keys); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const msg = mapToChaincodeMessage({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type: peer.ChaincodeMessage.Type.GET_STATE_MULTIPLE, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
payload: msgPb.serializeBinary(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
txid: txId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
channel_id: channel_id | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
logger.debug('handleOneSendGetMultipleStates - keys:', keys); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const responseMsg = await this._askPeerAndListen(msg, 'GetMultipleStates'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (responseMsg.getType() === peer.ChaincodeMessage.Type.RESPONSE) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const result = peer.GetStateMultipleResult.deserializeBinary(responseMsg.getPayload()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return result.getValuesList(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (responseMsg.getType() === peer.ChaincodeMessage.Type.ERROR) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
throw new Error(Buffer.from(responseMsg.getPayload()).toString()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
throw new Error(`Unexpected message type ${responseMsg.getType()} received`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
async handlePutState(collection, key, value, channel_id, txId) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const msgPb = new peer.PutState(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
msgPb.setKey(key); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -612,6 +612,56 @@ describe('Stub', () => { | |||||
}); | ||||||
}); | ||||||
|
||||||
describe.only('getMultipleStates', () => { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
it('should return handler.handleGetMultipleStates results', async () => { | ||||||
const handleGetMultipleStatesStub = sinon.stub().resolves(['value1', 'value2', 'value3']); | ||||||
|
||||||
const stub = new Stub({ | ||||||
handleGetMultipleStates: handleGetMultipleStatesStub | ||||||
}, 'dummyChannelId', 'dummyTxid', chaincodeInput); | ||||||
|
||||||
const result = await stub.getMultipleStates('key1', 'key2', 'key3'); | ||||||
expect(result).to.deep.equal(['value1', 'value2', 'value3']); | ||||||
|
||||||
expect(handleGetMultipleStatesStub.calledOnce).to.be.true; | ||||||
expect(handleGetMultipleStatesStub.firstCall.args).to.deep.equal([ | ||||||
'', | ||||||
['key1', 'key2', 'key3'], | ||||||
'dummyChannelId', | ||||||
'dummyTxid' | ||||||
]); | ||||||
}); | ||||||
|
||||||
it('should return empty array if no keys passed', async () => { | ||||||
const handleGetMultipleStatesStub = sinon.stub().resolves([]); | ||||||
|
||||||
const stub = new Stub({ | ||||||
handleGetMultipleStates: handleGetMultipleStatesStub | ||||||
}, 'dummyChannelId', 'dummyTxid', chaincodeInput); | ||||||
|
||||||
const result = await stub.getMultipleStates(); | ||||||
expect(result).to.deep.equal([]); | ||||||
|
||||||
expect(handleGetMultipleStatesStub.calledOnce).to.be.true; | ||||||
expect(handleGetMultipleStatesStub.firstCall.args).to.deep.equal([ | ||||||
'', | ||||||
[], | ||||||
'dummyChannelId', | ||||||
'dummyTxid' | ||||||
]); | ||||||
}); | ||||||
|
||||||
it('should throw error if handler rejects', async () => { | ||||||
const handleGetMultipleStatesStub = sinon.stub().rejects(new Error('Something gone wrong')); | ||||||
|
||||||
const stub = new Stub({ | ||||||
handleGetMultipleStates: handleGetMultipleStatesStub | ||||||
}, 'dummyChannelId', 'dummyTxid', chaincodeInput); | ||||||
|
||||||
await expect(stub.getMultipleStates('key1')).to.be.rejectedWith('Something gone wrong'); | ||||||
}); | ||||||
}); | ||||||
|
||||||
describe('putState', () => { | ||||||
it ('should return handler.handlePutState', async () => { | ||||||
const handlePutStateStub = sinon.stub().resolves('some state'); | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be possible to simplify this, similar to the following: