Skip to content

Commit 67845e4

Browse files
test: divide api-tests into 8 files (#1221)
Co-authored-by: Rafael Cárdenas <[email protected]>
1 parent 1e998db commit 67845e4

File tree

10 files changed

+11189
-10936
lines changed

10 files changed

+11189
-10936
lines changed

src/tests/address-tests.ts

Lines changed: 2815 additions & 0 deletions
Large diffs are not rendered by default.

src/tests/api-tests.ts

Lines changed: 0 additions & 10934 deletions
This file was deleted.

src/tests/block-tests.ts

Lines changed: 501 additions & 0 deletions
Large diffs are not rendered by default.

src/tests/burnchain-tests.ts

Lines changed: 475 additions & 0 deletions
Large diffs are not rendered by default.

src/tests/mempool-tests.ts

Lines changed: 1139 additions & 2 deletions
Large diffs are not rendered by default.
File renamed without changes.

src/tests/other-tests.ts

Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
import * as supertest from 'supertest';
2+
import { ChainID } from '@stacks/transactions';
3+
import {
4+
DbBlock,
5+
DbTx,
6+
DbTxTypeId,
7+
DbStxEvent,
8+
DbEventTypeId,
9+
DbAssetEventTypeId,
10+
DbMinerReward,
11+
} from '../datastore/common';
12+
import { startApiServer, ApiServer } from '../api/init';
13+
import { bufferToHexPrefixString, I32_MAX, microStxToStx, STACKS_DECIMAL_PLACES } from '../helpers';
14+
import { FEE_RATE } from '../api/routes/fee-rate';
15+
import { FeeRateRequest } from 'docs/generated';
16+
import { PgWriteStore } from '../datastore/pg-write-store';
17+
import { cycleMigrations, runMigrations } from '../datastore/migrations';
18+
import { PgSqlClient } from '../datastore/connection';
19+
20+
describe('other tests', () => {
21+
let db: PgWriteStore;
22+
let client: PgSqlClient;
23+
let api: ApiServer;
24+
25+
beforeEach(async () => {
26+
process.env.PG_DATABASE = 'postgres';
27+
await cycleMigrations();
28+
db = await PgWriteStore.connect({
29+
usageName: 'tests',
30+
withNotifier: false,
31+
skipMigrations: true,
32+
});
33+
client = db.sql;
34+
api = await startApiServer({ datastore: db, chainId: ChainID.Testnet, httpLogLevel: 'silly' });
35+
});
36+
37+
test('stx-supply', async () => {
38+
const testAddr1 = 'testAddr1';
39+
const dbBlock1: DbBlock = {
40+
block_hash: '0x0123',
41+
index_block_hash: '0x1234',
42+
parent_index_block_hash: '0x00',
43+
parent_block_hash: '0x5678',
44+
parent_microblock_hash: '',
45+
parent_microblock_sequence: 0,
46+
block_height: 1,
47+
burn_block_time: 39486,
48+
burn_block_hash: '0x1234',
49+
burn_block_height: 123,
50+
miner_txid: '0x4321',
51+
canonical: true,
52+
execution_cost_read_count: 0,
53+
execution_cost_read_length: 0,
54+
execution_cost_runtime: 0,
55+
execution_cost_write_count: 0,
56+
execution_cost_write_length: 0,
57+
};
58+
const tx: DbTx = {
59+
tx_id: '0x1234',
60+
tx_index: 4,
61+
anchor_mode: 3,
62+
nonce: 0,
63+
raw_tx: '',
64+
index_block_hash: dbBlock1.index_block_hash,
65+
block_hash: dbBlock1.block_hash,
66+
block_height: dbBlock1.block_height,
67+
burn_block_time: dbBlock1.burn_block_time,
68+
parent_burn_block_time: 0,
69+
type_id: DbTxTypeId.Coinbase,
70+
coinbase_payload: bufferToHexPrefixString(Buffer.from('coinbase hi')),
71+
status: 1,
72+
raw_result: '0x0100000000000000000000000000000001', // u1
73+
canonical: true,
74+
microblock_canonical: true,
75+
microblock_sequence: I32_MAX,
76+
microblock_hash: '',
77+
parent_index_block_hash: '',
78+
parent_block_hash: '',
79+
post_conditions: '0x01f5',
80+
fee_rate: 1234n,
81+
sponsored: false,
82+
sponsor_address: undefined,
83+
sender_address: testAddr1,
84+
origin_hash_mode: 1,
85+
event_count: 5,
86+
execution_cost_read_count: 0,
87+
execution_cost_read_length: 0,
88+
execution_cost_runtime: 0,
89+
execution_cost_write_count: 0,
90+
execution_cost_write_length: 0,
91+
};
92+
const stxMintEvent1: DbStxEvent = {
93+
event_index: 0,
94+
tx_id: tx.tx_id,
95+
tx_index: tx.tx_index,
96+
block_height: tx.block_height,
97+
canonical: true,
98+
asset_event_type_id: DbAssetEventTypeId.Mint,
99+
recipient: tx.sender_address,
100+
event_type: DbEventTypeId.StxAsset,
101+
amount: 230_000_000_000_000n,
102+
};
103+
const stxMintEvent2: DbStxEvent = {
104+
...stxMintEvent1,
105+
amount: 5_000_000_000_000n,
106+
};
107+
await db.update({
108+
block: dbBlock1,
109+
microblocks: [],
110+
minerRewards: [],
111+
txs: [
112+
{
113+
tx: tx,
114+
stxEvents: [stxMintEvent1, stxMintEvent2],
115+
stxLockEvents: [],
116+
ftEvents: [],
117+
nftEvents: [],
118+
contractLogEvents: [],
119+
names: [],
120+
namespaces: [],
121+
smartContracts: [],
122+
},
123+
],
124+
});
125+
126+
const expectedTotalStx1 = stxMintEvent1.amount + stxMintEvent2.amount;
127+
const result1 = await supertest(api.server).get(`/extended/v1/stx_supply`);
128+
expect(result1.status).toBe(200);
129+
expect(result1.type).toBe('application/json');
130+
const expectedResp1 = {
131+
unlocked_percent: '17.38',
132+
total_stx: '1352464600.000000',
133+
unlocked_stx: microStxToStx(expectedTotalStx1),
134+
block_height: dbBlock1.block_height,
135+
};
136+
expect(JSON.parse(result1.text)).toEqual(expectedResp1);
137+
138+
// ensure burned STX reduce the unlocked stx supply
139+
const stxBurnEvent1: DbStxEvent = {
140+
event_index: 0,
141+
tx_id: tx.tx_id,
142+
tx_index: tx.tx_index,
143+
block_height: tx.block_height,
144+
canonical: true,
145+
asset_event_type_id: DbAssetEventTypeId.Burn,
146+
sender: tx.sender_address,
147+
event_type: DbEventTypeId.StxAsset,
148+
amount: 10_000_000_000_000n,
149+
};
150+
await db.updateStxEvent(client, tx, stxBurnEvent1);
151+
const expectedTotalStx2 = stxMintEvent1.amount + stxMintEvent2.amount - stxBurnEvent1.amount;
152+
const result2 = await supertest(api.server).get(`/extended/v1/stx_supply`);
153+
expect(result2.status).toBe(200);
154+
expect(result2.type).toBe('application/json');
155+
const expectedResp2 = {
156+
unlocked_percent: '16.64',
157+
total_stx: '1352464600.000000',
158+
unlocked_stx: microStxToStx(expectedTotalStx2),
159+
block_height: dbBlock1.block_height,
160+
};
161+
expect(JSON.parse(result2.text)).toEqual(expectedResp2);
162+
163+
// ensure miner coinbase rewards are included
164+
const minerReward1: DbMinerReward = {
165+
block_hash: dbBlock1.block_hash,
166+
index_block_hash: dbBlock1.index_block_hash,
167+
from_index_block_hash: dbBlock1.index_block_hash,
168+
mature_block_height: dbBlock1.block_height,
169+
canonical: true,
170+
recipient: testAddr1,
171+
coinbase_amount: 15_000_000_000_000n,
172+
tx_fees_anchored: 1_000_000_000_000n,
173+
tx_fees_streamed_confirmed: 2_000_000_000_000n,
174+
tx_fees_streamed_produced: 3_000_000_000_000n,
175+
};
176+
await db.updateMinerReward(client, minerReward1);
177+
const expectedTotalStx3 =
178+
stxMintEvent1.amount +
179+
stxMintEvent2.amount -
180+
stxBurnEvent1.amount +
181+
minerReward1.coinbase_amount;
182+
const result3 = await supertest(api.server).get(`/extended/v1/stx_supply`);
183+
expect(result3.status).toBe(200);
184+
expect(result3.type).toBe('application/json');
185+
const expectedResp3 = {
186+
unlocked_percent: '17.75',
187+
total_stx: '1352464600.000000',
188+
unlocked_stx: microStxToStx(expectedTotalStx3),
189+
block_height: dbBlock1.block_height,
190+
};
191+
expect(JSON.parse(result3.text)).toEqual(expectedResp3);
192+
193+
const result4 = await supertest(api.server).get(`/extended/v1/stx_supply/total/plain`);
194+
expect(result4.status).toBe(200);
195+
expect(result4.type).toBe('text/plain');
196+
expect(result4.text).toEqual('1352464600.000000');
197+
198+
const result5 = await supertest(api.server).get(`/extended/v1/stx_supply/circulating/plain`);
199+
expect(result5.status).toBe(200);
200+
expect(result5.type).toBe('text/plain');
201+
expect(result5.text).toEqual(microStxToStx(expectedTotalStx3));
202+
203+
// test legacy endpoint response formatting
204+
const result6 = await supertest(api.server).get(`/extended/v1/stx_supply/legacy_format`);
205+
expect(result6.status).toBe(200);
206+
expect(result6.type).toBe('application/json');
207+
const expectedResp6 = {
208+
unlockedPercent: '17.75',
209+
totalStacks: '1352464600.000000',
210+
totalStacksFormatted: '1,352,464,600.000000',
211+
unlockedSupply: microStxToStx(expectedTotalStx3),
212+
unlockedSupplyFormatted: new Intl.NumberFormat('en', {
213+
minimumFractionDigits: STACKS_DECIMAL_PLACES,
214+
}).format(parseInt(microStxToStx(expectedTotalStx3))),
215+
blockHeight: dbBlock1.block_height.toString(),
216+
};
217+
expect(JSON.parse(result6.text)).toEqual(expectedResp6);
218+
});
219+
220+
test('Get fee rate', async () => {
221+
const request: FeeRateRequest = {
222+
transaction: '0x5e9f3933e358df6a73fec0d47ce3e1062c20812c129f5294e6f37a8d27c051d9',
223+
};
224+
const result = await supertest(api.server).post('/extended/v1/fee_rate').send(request);
225+
expect(result.status).toBe(200);
226+
expect(result.type).toBe('application/json');
227+
expect(result.body.fee_rate).toBe(FEE_RATE);
228+
});
229+
230+
test('400 response errors', async () => {
231+
const tx_id = '0x8407751d1a8d11ee986aca32a6459d9cd798283a12e048ebafcd4cc7dadb29a';
232+
const block_hash = '0xd10ccecfd7ac9e5f8a10de0532fac028559b31a6ff494d82147f6297fb66313';
233+
const principal_addr = 'S.hello-world';
234+
const odd_tx_error = {
235+
error: `Hex string is an odd number of digits: ${tx_id}`,
236+
};
237+
const odd_block_error = {
238+
error: `Hex string is an odd number of digits: ${block_hash}`,
239+
};
240+
const metadata_error = { error: `Unexpected value for 'include_metadata' parameter: "bac"` };
241+
const principal_error = { error: 'invalid STX address "S.hello-world"' };
242+
const pagination_error = { error: '`limit` must be equal to or less than 200' };
243+
// extended/v1/tx
244+
const searchResult1 = await supertest(api.server).get(`/extended/v1/tx/${tx_id}`);
245+
expect(JSON.parse(searchResult1.text)).toEqual(odd_tx_error);
246+
expect(searchResult1.status).toBe(400);
247+
const searchResult2 = await supertest(api.server).get(
248+
`/extended/v1/tx/multiple?tx_id=${tx_id}`
249+
);
250+
expect(JSON.parse(searchResult2.text)).toEqual(odd_tx_error);
251+
expect(searchResult2.status).toBe(400);
252+
const searchResult3 = await supertest(api.server).get(`/extended/v1/tx/${tx_id}/raw`);
253+
expect(JSON.parse(searchResult3.text)).toEqual(odd_tx_error);
254+
expect(searchResult3.status).toBe(400);
255+
const searchResult4 = await supertest(api.server).get(`/extended/v1/tx/block/${block_hash}`);
256+
expect(JSON.parse(searchResult4.text)).toEqual(odd_block_error);
257+
expect(searchResult4.status).toBe(400);
258+
259+
// extended/v1/block
260+
const searchResult5 = await supertest(api.server).get(`/extended/v1/block/${block_hash}`);
261+
expect(JSON.parse(searchResult5.text)).toEqual(odd_block_error);
262+
expect(searchResult5.status).toBe(400);
263+
264+
// extended/v1/microblock
265+
const searchResult6 = await supertest(api.server).get(`/extended/v1/microblock/${block_hash}`);
266+
expect(JSON.parse(searchResult6.text)).toEqual(odd_block_error);
267+
expect(searchResult6.status).toBe(400);
268+
269+
// extended/v1/search
270+
const searchResult7 = await supertest(api.server).get(
271+
`/extended/v1/search/${block_hash}?include_metadata=bac`
272+
);
273+
expect(JSON.parse(searchResult7.text)).toEqual(metadata_error);
274+
expect(searchResult7.status).toBe(400);
275+
276+
// extended/v1/address
277+
const searchResult8 = await supertest(api.server).get(
278+
`/extended/v1/address/${principal_addr}/stx`
279+
);
280+
expect(JSON.parse(searchResult8.text)).toEqual(principal_error);
281+
expect(searchResult8.status).toBe(400);
282+
283+
// pagination queries
284+
const searchResult9 = await supertest(api.server).get(
285+
'/extended/v1/tx/mempool?limit=201&offset=2'
286+
);
287+
expect(JSON.parse(searchResult9.text)).toEqual(pagination_error);
288+
expect(searchResult9.status).toBe(400);
289+
});
290+
291+
test('active status', async () => {
292+
const result = await supertest(api.server).get(`/extended/v1/status/`);
293+
expect(result.body.status).toBe('ready');
294+
});
295+
296+
afterEach(async () => {
297+
await api.terminate();
298+
await db?.close();
299+
await runMigrations(undefined, 'down');
300+
});
301+
});

0 commit comments

Comments
 (0)