From 8bd602f446172010029930b0f2493735a8d01b98 Mon Sep 17 00:00:00 2001 From: tim Date: Tue, 20 Jun 2017 17:46:25 +0200 Subject: [PATCH] Fix and test outputs endpoint --- src/connection/index.js | 20 ++-- test/connection/test_connection.js | 47 +++++++++ test/integration/test_integration.js | 137 +++++++++++++++++++++++++++ 3 files changed, 196 insertions(+), 8 deletions(-) diff --git a/src/connection/index.js b/src/connection/index.js index 80702de..59be9a4 100644 --- a/src/connection/index.js +++ b/src/connection/index.js @@ -78,17 +78,21 @@ export default class Connection { /** * @public - * @param public_key - * @param unspent + * @param publicKey + * @param spent * @param onlyJsonResponse */ - // TODO: Use camel case for parameters - listOutputs({ public_key, unspent }, onlyJsonResponse = true) { + listOutputs(publicKey, spent, onlyJsonResponse = true) { + const query = { + public_key: publicKey + } + // NOTE: If `spent` is not defined, it must not be included in the + // query parameters. + if (spent !== undefined) { + query.spent = spent + } return this._req(this.getApiUrls('outputs'), { - query: { - public_key, - unspent - } + query }, onlyJsonResponse) } diff --git a/test/connection/test_connection.js b/test/connection/test_connection.js index 4ccbb41..8a8979e 100644 --- a/test/connection/test_connection.js +++ b/test/connection/test_connection.js @@ -110,6 +110,53 @@ test('Get list of blocks for a transaction id', t => { }) +test('Get outputs for a public key and no spent flag', t => { + const expectedPath = 'path' + const publicKey = 'publicKey' + + conn._req = sinon.spy() + conn.getApiUrls = sinon.stub().returns(expectedPath) + + conn.listOutputs(publicKey) + t.truthy(conn._req.calledWith( + expectedPath, + { query: { public_key: publicKey } } + )) +}) + + +test('Get outputs for a public key and spent=false', t => { + const expectedPath = 'path' + const publicKey = 'publicKey' + const spent = false + + conn._req = sinon.spy() + conn.getApiUrls = sinon.stub().returns(expectedPath) + + conn.listOutputs(publicKey, spent) + t.truthy(conn._req.calledWith( + expectedPath, + { query: { public_key: publicKey, spent } } + )) +}) + + +test('Get outputs for a public key and spent=true', t => { + const expectedPath = 'path' + const publicKey = 'publicKey' + const spent = true + + conn._req = sinon.spy() + conn.getApiUrls = sinon.stub().returns(expectedPath) + + conn.listOutputs(publicKey, spent) + t.truthy(conn._req.calledWith( + expectedPath, + { query: { public_key: publicKey, spent } } + )) +}) + + test('Get votes for a block id', t => { const expectedPath = 'path' const blockId = 'abc' diff --git a/test/integration/test_integration.js b/test/integration/test_integration.js index 1f38853..8d38b70 100644 --- a/test/integration/test_integration.js +++ b/test/integration/test_integration.js @@ -110,6 +110,143 @@ test('Valid TRANSFER transaction with multiple Ed25519 inputs', t => { }) +test('Search for spent and unspent outputs of a given public key', t => { + const conn = new Connection(API_PATH) + + const createTx = Transaction.makeCreateTransaction( + asset(), + metaData, + [aliceOutput, aliceOutput], + alice.publicKey + ) + const createTxSigned = Transaction.signTransaction( + createTx, + alice.privateKey, + alice.privateKey + ) + + // We spent output 1 (of 0, 1) + const transferTx = Transaction.makeTransferTransaction( + createTxSigned, + metaData, + [bobOutput], + 1 + ) + const transferTxSigned = Transaction.signTransaction( + transferTx, + alice.privateKey, + ) + + function byTransactionId(transactionId, ...outputIndices) { + return value => transactionId === value.transaction_id && + outputIndices.includes(value.output) + } + + return conn.postTransaction(createTxSigned) + .then(({ id }) => conn.pollStatusAndFetchTransaction(id)) + .then(() => conn.postTransaction(transferTxSigned)) + .then(({ id }) => conn.pollStatusAndFetchTransaction(id)) + .then(() => conn.listOutputs(alice.publicKey)) + // now listOutputs should return us outputs 0 and 1 (unfiltered) + .then(outputs => outputs.filter(byTransactionId( + createTxSigned.id, + 0, + 1 + ))) + .then(outputs => t.truthy(outputs.length === 2)) +}) + + +test('Search for unspent outputs for a given public key', t => { + const conn = new Connection(API_PATH) + + const createTx = Transaction.makeCreateTransaction( + asset(), + metaData, + [aliceOutput, aliceOutput, aliceOutput], + alice.publicKey + ) + const createTxSigned = Transaction.signTransaction( + createTx, + alice.privateKey, + alice.privateKey + ) + + // We spent output 1 (of 0, 1, 2) + const transferTx = Transaction.makeTransferTransaction( + createTxSigned, + metaData, + [bobOutput], + 1 + ) + const transferTxSigned = Transaction.signTransaction( + transferTx, + alice.privateKey, + ) + + function byTransactionId(transactionId, ...outputIndices) { + return value => transactionId === value.transaction_id && + outputIndices.includes(value.output) + } + + return conn.postTransaction(createTxSigned) + .then(({ id }) => conn.pollStatusAndFetchTransaction(id)) + .then(() => conn.postTransaction(transferTxSigned)) + .then(({ id }) => conn.pollStatusAndFetchTransaction(id)) + // now listOutputs should return us outputs 0 and 2 (1 is spent) + .then(() => conn.listOutputs(alice.publicKey, false)) + .then(outputs => outputs.filter(byTransactionId( + createTxSigned.id, + 0, + 2 + ))) + .then(outputs => t.truthy(outputs.length === 2)) +}) + + +test('Search for spent outputs for a given public key', t => { + const conn = new Connection(API_PATH) + + const createTx = Transaction.makeCreateTransaction( + asset(), + metaData, + [aliceOutput, aliceOutput, aliceOutput], + alice.publicKey + ) + const createTxSigned = Transaction.signTransaction( + createTx, + alice.privateKey, + alice.privateKey + ) + + // We spent output 1 (of 0, 1, 2) + const transferTx = Transaction.makeTransferTransaction( + createTxSigned, + metaData, + [bobOutput], + 1 + ) + const transferTxSigned = Transaction.signTransaction( + transferTx, + alice.privateKey, + ) + + function byTransactionId(transactionId, ...outputIndices) { + return value => transactionId === value.transaction_id && + outputIndices.includes(value.output) + } + + return conn.postTransaction(createTxSigned) + .then(({ id }) => conn.pollStatusAndFetchTransaction(id)) + .then(() => conn.postTransaction(transferTxSigned)) + .then(({ id }) => conn.pollStatusAndFetchTransaction(id)) + // now listOutputs should only return us output 1 (0 and 2 are unspent) + .then(() => conn.listOutputs(alice.publicKey, true)) + .then(outputs => outputs.filter(byTransactionId(createTxSigned.id, 1))) + .then(outputs => t.truthy(outputs.length === 1)) +}) + + test('Search for an asset', t => { const conn = new Connection(API_PATH)