Skip to content

Commit 0338d1b

Browse files
feat(mbe): complete integration test
1 parent caec81e commit 0338d1b

File tree

1 file changed

+52
-149
lines changed

1 file changed

+52
-149
lines changed

src/__tests__/api/master/consolidate.test.ts

Lines changed: 52 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@ import nock from 'nock';
55
import { app as expressApp } from '../../../masterExpressApp';
66
import { AppMode, MasterExpressConfig, TlsMode } from '../../../shared/types';
77
import { Environments, Wallet } from '@bitgo/sdk-core';
8-
import { Hteth } from '@bitgo/sdk-coin-eth';
98

10-
describe('POST /api/:coin/wallet/:walletId/consolidate', () => {
9+
describe('POST /api/:coin/wallet/:walletId/consolidateunspents', () => {
1110
let agent: request.SuperAgentTest;
12-
const coin = 'hteth';
11+
const coin = 'btc';
1312
const walletId = 'test-wallet-id';
1413
const accessToken = 'test-access-token';
1514
const bitgoApiUrl = Environments.test.uri;
@@ -21,7 +20,7 @@ describe('POST /api/:coin/wallet/:walletId/consolidate', () => {
2120

2221
const config: MasterExpressConfig = {
2322
appMode: AppMode.MASTER_EXPRESS,
24-
port: 0, // Let OS assign a free port
23+
port: 0,
2524
bind: 'localhost',
2625
timeout: 30000,
2726
logFile: '',
@@ -44,8 +43,7 @@ describe('POST /api/:coin/wallet/:walletId/consolidate', () => {
4443
sinon.restore();
4544
});
4645

47-
it('should consolidate account addresses by calling the enclaved express service', async () => {
48-
// Mock wallet get request
46+
it('should return transfer, txid, tx, and status on success', async () => {
4947
const walletGetNock = nock(bitgoApiUrl)
5048
.get(`/api/v2/${coin}/wallet/${walletId}`)
5149
.matchHeader('any', () => true)
@@ -56,7 +54,6 @@ describe('POST /api/:coin/wallet/:walletId/consolidate', () => {
5654
keys: ['user-key-id', 'backup-key-id', 'bitgo-key-id'],
5755
});
5856

59-
// Mock keychain get request
6057
const keychainGetNock = nock(bitgoApiUrl)
6158
.get(`/api/v2/${coin}/key/user-key-id`)
6259
.matchHeader('any', () => true)
@@ -65,99 +62,52 @@ describe('POST /api/:coin/wallet/:walletId/consolidate', () => {
6562
pub: 'xpub_user',
6663
});
6764

68-
// Mock sendAccountConsolidations
69-
const sendConsolidationsStub = sinon
70-
.stub(Wallet.prototype, 'sendAccountConsolidations')
71-
.resolves({
72-
success: [
73-
{
74-
txid: 'consolidation-tx-1',
75-
status: 'signed',
76-
},
65+
const mockResult = {
66+
transfer: {
67+
entries: [
68+
{ address: 'tb1qu...', value: -4000 },
69+
{ address: 'tb1qle...', value: -4000 },
70+
{ address: 'tb1qtw...', value: 2714, isChange: true },
7771
],
78-
failure: [],
79-
});
80-
81-
const response = await agent
82-
.post(`/api/${coin}/wallet/${walletId}/consolidate`)
83-
.set('Authorization', `Bearer ${accessToken}`)
84-
.send({
85-
source: 'user',
86-
pubkey: 'xpub_user',
87-
consolidateAddresses: ['0x1234567890abcdef', '0xfedcba0987654321'],
88-
});
89-
90-
response.status.should.equal(200);
91-
response.body.should.have.property('success');
92-
response.body.success.should.have.length(1);
93-
response.body.success[0].should.have.property('txid', 'consolidation-tx-1');
94-
95-
walletGetNock.done();
96-
keychainGetNock.done();
97-
sinon.assert.calledOnce(sendConsolidationsStub);
98-
});
99-
100-
it('should handle partial consolidation failures', async () => {
101-
// Mock wallet get request
102-
const walletGetNock = nock(bitgoApiUrl)
103-
.get(`/api/v2/${coin}/wallet/${walletId}`)
104-
.matchHeader('any', () => true)
105-
.reply(200, {
106-
id: walletId,
107-
type: 'cold',
108-
subType: 'onPrem',
109-
keys: ['user-key-id', 'backup-key-id', 'bitgo-key-id'],
110-
});
111-
112-
// Mock keychain get request
113-
const keychainGetNock = nock(bitgoApiUrl)
114-
.get(`/api/v2/${coin}/key/user-key-id`)
115-
.matchHeader('any', () => true)
116-
.reply(200, {
117-
id: 'user-key-id',
118-
pub: 'xpub_user',
119-
});
72+
id: '685ac2f3c2f8a2a5d9cc18d3593f1751',
73+
coin: 'tbtc',
74+
wallet: '685abbf19ca95b79f88e0b41d9337109',
75+
txid: '239d143cdfc6d6c83a935da4f3d610b2364a956c7b6dcdc165eb706f62c4432a',
76+
status: 'signed',
77+
},
78+
txid: '239d143cdfc6d6c83a935da4f3d610b2364a956c7b6dcdc165eb706f62c4432a',
79+
tx: '01000000000102580b...',
80+
status: 'signed',
81+
};
12082

121-
// Mock sendAccountConsolidations with partial failures
122-
const sendConsolidationsStub = sinon
123-
.stub(Wallet.prototype, 'sendAccountConsolidations')
124-
.resolves({
125-
success: [
126-
{
127-
txid: 'consolidation-tx-1',
128-
status: 'signed',
129-
},
130-
],
131-
failure: [
132-
{
133-
error: 'Insufficient funds',
134-
address: '0xfedcba0987654321',
135-
},
136-
],
137-
});
83+
const consolidateUnspentsStub = sinon
84+
.stub(Wallet.prototype, 'consolidateUnspents')
85+
.resolves(mockResult);
13886

13987
const response = await agent
140-
.post(`/api/${coin}/wallet/${walletId}/consolidate`)
88+
.post(`/api/${coin}/wallet/${walletId}/consolidateunspents`)
14189
.set('Authorization', `Bearer ${accessToken}`)
14290
.send({
14391
source: 'user',
14492
pubkey: 'xpub_user',
145-
consolidateAddresses: ['0x1234567890abcdef', '0xfedcba0987654321'],
93+
feeRate: 1000,
14694
});
14795

148-
response.status.should.equal(500);
149-
response.body.should.have.property('error', 'Internal Server Error');
150-
response.body.should.have
151-
.property('details')
152-
.which.match(/Consolidations failed: 1 and succeeded: 1/);
96+
response.status.should.equal(200);
97+
response.body.should.have.property('transfer');
98+
response.body.should.have.property('txid', mockResult.txid);
99+
response.body.should.have.property('tx', mockResult.tx);
100+
response.body.should.have.property('status', mockResult.status);
101+
response.body.transfer.should.have.property('txid', mockResult.transfer.txid);
102+
response.body.transfer.should.have.property('status', mockResult.transfer.status);
103+
response.body.transfer.should.have.property('entries').which.is.Array();
153104

154105
walletGetNock.done();
155106
keychainGetNock.done();
156-
sinon.assert.calledOnce(sendConsolidationsStub);
107+
sinon.assert.calledOnce(consolidateUnspentsStub);
157108
});
158109

159-
it('should throw error when all consolidations fail', async () => {
160-
// Mock wallet get request
110+
it('should return error, name, and details on failure', async () => {
161111
const walletGetNock = nock(bitgoApiUrl)
162112
.get(`/api/v2/${coin}/wallet/${walletId}`)
163113
.matchHeader('any', () => true)
@@ -168,7 +118,6 @@ describe('POST /api/:coin/wallet/:walletId/consolidate', () => {
168118
keys: ['user-key-id', 'backup-key-id', 'bitgo-key-id'],
169119
});
170120

171-
// Mock keychain get request
172121
const keychainGetNock = nock(bitgoApiUrl)
173122
.get(`/api/v2/${coin}/key/user-key-id`)
174123
.matchHeader('any', () => true)
@@ -177,83 +126,37 @@ describe('POST /api/:coin/wallet/:walletId/consolidate', () => {
177126
pub: 'xpub_user',
178127
});
179128

180-
// Mock sendAccountConsolidations with all failures
181-
const sendConsolidationsStub = sinon
182-
.stub(Wallet.prototype, 'sendAccountConsolidations')
183-
.resolves({
184-
success: [],
185-
failure: [
186-
{
187-
error: 'All consolidations failed',
188-
address: '0x1234567890abcdef',
189-
},
190-
{
191-
error: 'All consolidations failed',
192-
address: '0xfedcba0987654321',
193-
},
194-
],
195-
});
196-
197-
const response = await agent
198-
.post(`/api/${coin}/wallet/${walletId}/consolidate`)
199-
.set('Authorization', `Bearer ${accessToken}`)
200-
.send({
201-
source: 'user',
202-
pubkey: 'xpub_user',
203-
consolidateAddresses: ['0x1234567890abcdef', '0xfedcba0987654321'],
204-
});
205-
206-
response.status.should.equal(500);
207-
response.body.should.have.property('error');
208-
response.body.should.have.property('details').which.match(/All consolidations failed/);
209-
210-
walletGetNock.done();
211-
keychainGetNock.done();
212-
sinon.assert.calledOnce(sendConsolidationsStub);
213-
});
214-
215-
it('should throw error when coin does not support account consolidations', async () => {
216-
// Mock wallet get request
217-
const walletGetNock = nock(bitgoApiUrl)
218-
.get(`/api/v2/${coin}/wallet/${walletId}`)
219-
.matchHeader('any', () => true)
220-
.reply(200, {
221-
id: walletId,
222-
type: 'cold',
223-
subType: 'onPrem',
224-
keys: ['user-key-id', 'backup-key-id', 'bitgo-key-id'],
225-
});
226-
// Mock keychain get request
227-
const keychainGetNock = nock(bitgoApiUrl)
228-
.get(`/api/v2/${coin}/key/user-key-id`)
229-
.matchHeader('any', () => true)
230-
.reply(200, {
231-
id: 'user-key-id',
232-
pub: 'xpub_user',
233-
});
129+
const mockError = {
130+
error: 'Internal Server Error',
131+
name: 'ApiResponseError',
132+
details:
133+
'There are too few unspents that meet the given parameters to consolidate (1 available).',
134+
};
234135

235-
// Mock allowsAccountConsolidations to return false
236-
const allowsConsolidationsStub = sinon
237-
.stub(Hteth.prototype, 'allowsAccountConsolidations')
238-
.returns(false);
136+
const consolidateUnspentsStub = sinon
137+
.stub(Wallet.prototype, 'consolidateUnspents')
138+
.throws(Object.assign(new Error(mockError.details), mockError));
239139

240140
const response = await agent
241-
.post(`/api/${coin}/wallet/${walletId}/consolidate`)
141+
.post(`/api/${coin}/wallet/${walletId}/consolidateunspents`)
242142
.set('Authorization', `Bearer ${accessToken}`)
243143
.send({
244144
source: 'user',
245145
pubkey: 'xpub_user',
146+
feeRate: 1000,
246147
});
247148

248149
response.status.should.equal(500);
150+
response.body.should.have.property('error', mockError.error);
151+
response.body.should.have.property('name', mockError.name);
152+
response.body.should.have.property('details', mockError.details);
249153

250154
walletGetNock.done();
251155
keychainGetNock.done();
252-
sinon.assert.calledOnce(allowsConsolidationsStub);
156+
sinon.assert.calledOnce(consolidateUnspentsStub);
253157
});
254158

255159
it('should throw error when provided pubkey does not match wallet keychain', async () => {
256-
// Mock wallet get request
257160
const walletGetNock = nock(bitgoApiUrl)
258161
.get(`/api/v2/${coin}/wallet/${walletId}`)
259162
.matchHeader('any', () => true)
@@ -264,7 +167,6 @@ describe('POST /api/:coin/wallet/:walletId/consolidate', () => {
264167
keys: ['user-key-id', 'backup-key-id', 'bitgo-key-id'],
265168
});
266169

267-
// Mock keychain get request
268170
const keychainGetNock = nock(bitgoApiUrl)
269171
.get(`/api/v2/${coin}/key/user-key-id`)
270172
.matchHeader('any', () => true)
@@ -274,11 +176,12 @@ describe('POST /api/:coin/wallet/:walletId/consolidate', () => {
274176
});
275177

276178
const response = await agent
277-
.post(`/api/${coin}/wallet/${walletId}/consolidate`)
179+
.post(`/api/${coin}/wallet/${walletId}/consolidateunspents`)
278180
.set('Authorization', `Bearer ${accessToken}`)
279181
.send({
280182
source: 'user',
281183
pubkey: 'wrong_pubkey',
184+
feeRate: 1000,
282185
});
283186

284187
response.status.should.equal(500);

0 commit comments

Comments
 (0)