Skip to content

Integration Tests: balance, tx-history, address-info and transaction routes #149

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

Merged
merged 40 commits into from
Mar 3, 2022
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
32d426c
test: Implementing first integrated tests with the fullnode
tuliomir Feb 8, 2022
74ae7df
test: Working proof-of-concept
tuliomir Feb 9, 2022
b4d171f
refactor: moved integration test to separate folder + config file
tuliomir Feb 10, 2022
d7d9928
feat: first draft for logging test network transactions
tuliomir Feb 10, 2022
5d809f1
test: first balance tests
tuliomir Feb 10, 2022
ffef8f4
feat: log filename indicates the suite it tested
tuliomir Feb 10, 2022
1109c6c
test: implementing private network on docker images
tuliomir Feb 15, 2022
d352c11
test: mining private network on docker images
tuliomir Feb 15, 2022
0011c2b
test: testing on github workflow
tuliomir Feb 16, 2022
074f93b
fix: uploading artifacts despite failure for debugging
tuliomir Feb 16, 2022
15f0952
feat: single command to build network environment, test and cleanup
tuliomir Feb 17, 2022
48b6721
fix: delaying injectFundsIntoAddress to avoid workflow failures
tuliomir Feb 17, 2022
bca7248
test: create token test
tuliomir Feb 18, 2022
6943285
test: testing failure, but did not work with local cache
tuliomir Feb 19, 2022
79d82c4
test: tx history tests without error handling
tuliomir Feb 19, 2022
499e6ca
test: address info tests without error handling
tuliomir Feb 20, 2022
cf62ff3
test: transaction route tests without error handling
tuliomir Feb 21, 2022
8a560b5
chore: changed integration test workflow to run on dev and master
tuliomir Feb 21, 2022
b1b6637
docs: Adds various comments and documentations to the Integration Tests
tuliomir Feb 21, 2022
c0f84c5
fix: lgtm raised issues
tuliomir Feb 22, 2022
97840f3
fix: mocked tests ignore paths
tuliomir Feb 22, 2022
4c5505c
style: integration tests linting
tuliomir Feb 24, 2022
9605fbe
fix: getRandomInt function had incorrect logic
tuliomir Feb 24, 2022
3b0c73b
chore: removing proof of concept file
tuliomir Feb 24, 2022
3562086
style: eslint fixes
tuliomir Feb 24, 2022
88f7061
docs: clarifying jsdocs and comments
tuliomir Feb 24, 2022
b7c31f0
fix: minor failures on log helpers
tuliomir Feb 24, 2022
693025a
test: new tests for locked balances
tuliomir Feb 24, 2022
f0adf8f
test: new assertions for transaction order
tuliomir Feb 24, 2022
b033b81
style: fix eslint parens
tuliomir Feb 24, 2022
f58a436
refactor: improve wallet startup's "status" validation
tuliomir Feb 25, 2022
4b9be13
refactor: using the WalletHelper.createToken instead of a direct http
tuliomir Feb 25, 2022
4173e04
fix: locked amount on addresses is not fixed as supposed
tuliomir Feb 25, 2022
080bc76
refactor: improving lib code reuse
tuliomir Feb 25, 2022
a1e6341
Update __tests__/integration/utils/test-utils-integration.js
tuliomir Feb 25, 2022
ccdb2d8
Update __tests__/integration/utils/wallet-helper.js
tuliomir Feb 25, 2022
7e43ad6
refactor: error handling on logger
tuliomir Mar 2, 2022
41c4600
refactor: txLogger now using winston instead of direct fs
tuliomir Mar 2, 2022
e6dc2e4
refactor: txLogger adapter to better use of winston logs
tuliomir Mar 3, 2022
72f8898
refactor: logs folder now fetched from config file
tuliomir Mar 3, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"extends": "airbnb-base",
"parser": "@babel/eslint-parser",
"rules": {
"arrow-parens": ["error", "as-needed"],
"import/no-named-as-default": 0,
"import/prefer-default-export": 0,
"quotes": ["error", "single", { "avoidEscape": true, "allowTemplateLiterals": true }],
"comma-dangle": 0,
"object-curly-newline": ["error", {"ObjectPattern": { "multiline": true }}],
"eqeqeq": [1, "allow-null"],
"no-continue": 0,
"no-cond-assign": 1,
"no-constant-condition": 0,
"no-control-regex": 1,
"no-debugger": 1,
"no-dupe-keys": 1,
"no-ex-assign": 1,
"no-extra-boolean-cast": 1,
"no-func-assign": 1,
"no-regex-spaces": 1,
"no-unreachable": 1,
"no-fallthrough": 1,
"no-lone-blocks": 1,
"no-delete-var": 1,
"no-shadow": 1,
"no-shadow-restricted-names": 1,
"no-undef": 2,
"no-undef-init": 1,
"no-use-before-define": 0,
"no-unused-vars": [1, {"vars": "all", "args": "none"}],
"no-underscore-dangle": 0,
"no-restricted-syntax": ["error", "LabeledStatement", "WithStatement"],
"no-await-in-loop": "off",
"no-plusplus": "off",
"guard-for-in": "off"
},
"overrides": [
{
"files": [
"**/*.test.js"
],
"env": {
"jest": true
}
}
]
}
44 changes: 44 additions & 0 deletions .github/workflows/integration-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: integration-test
on:
push:
branches:
- master
- dev
tags:
- v*
pull_request:
branches:
- dev
- master
jobs:
itest:
runs-on: ubuntu-20.04
timeout-minutes: 20

strategy:
matrix:
node-version: [14.x]

steps:
- uses: actions/checkout@v2

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}

- name: Install dependencies
run: npm install

- name: Copy config file
run: cp ./__tests__/integration/configuration/config.js.template ./src/config.js

- name: Run the tests
run: npm run test_integration

- name: Upload debug transaction logs
if: always()
uses: actions/upload-artifact@v2
with:
name: test-transacion-logs
path: tmp
176 changes: 176 additions & 0 deletions __tests__/integration/address-info.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import {
getRandomInt,
HATHOR_TOKEN_ID,
TestUtils,
WALLET_CONSTANTS
} from './utils/test-utils-integration';
import { WalletHelper } from './utils/wallet-helper';

describe('address-info routes', () => {
let wallet1;
let wallet2;
const address1balance = getRandomInt(200, 100);
let customTokenHash;

beforeAll(async () => {
try {
// A random HTR value for the first wallet
wallet1 = new WalletHelper('addinfo-1');
await wallet1.start();
await wallet1.injectFunds(address1balance, 1);

// A fixed custom token amount for the second wallet
wallet2 = new WalletHelper('addinfo-2');
await wallet2.start();
await wallet2.injectFunds(10);
const customToken = await wallet2.createToken({
amount: 500,
name: 'AddInfo Token',
symbol: 'AIT',
address: await wallet2.getAddressAt(1),
change_address: await wallet2.getAddressAt(0)
});
customTokenHash = customToken.hash;

/*
* The state here should be:
* wallet1[1] with some value between 100 and 200 HTR
* wallet2[0] with 5 HTR
* wallet2[1] with 500 AIT
*/
} catch (err) {
TestUtils.logError(err.stack);
}
});

afterAll(async () => {
await wallet1.stop();
await wallet2.stop();
});

it('should return results for an address (empty)', async done => {
const response = await TestUtils.request
.get('/wallet/address-info')
.query({ address: await wallet1.getAddressAt(0) })
.set({ 'x-wallet-id': wallet1.walletId });

expect(response.status).toBe(200);

const results = response.body;
expect(results.success).toBeTruthy();
expect(results.token).toBe(HATHOR_TOKEN_ID);
expect(results.index).toBe(0);
expect(results.total_amount_received).toBe(0);
expect(results.total_amount_sent).toBe(0);
expect(results.total_amount_available).toBe(0);
expect(results.total_amount_locked).toBe(0);
done();
});

it('should return results for an address with a single receiving transaction', async done => {
const response = await TestUtils.request
.get('/wallet/address-info')
.query({ address: await wallet1.getAddressAt(1) })
.set({ 'x-wallet-id': wallet1.walletId });

expect(response.status).toBe(200);

const results = response.body;
expect(results.success).toBeTruthy();
expect(results.token).toBe(HATHOR_TOKEN_ID);
expect(results.index).toBe(1);
expect(results.total_amount_received).toBe(address1balance);
expect(results.total_amount_sent).toBe(0);
expect(results.total_amount_available).toBe(address1balance);
expect(results.total_amount_locked).toBe(0);
done();
});

it('should return correct locked balance for an address with miner rewards', async done => {
const response = await TestUtils.request
.get('/wallet/address-info')
.query({ address: WALLET_CONSTANTS.genesis.addresses[1] }) // Miner rewards address
.set({ 'x-wallet-id': WALLET_CONSTANTS.genesis.walletId });

expect(response.status).toBe(200);

const results = response.body;
expect(results.success).toBeTruthy();
expect(results.token).toBe(HATHOR_TOKEN_ID);
expect(results.index).toBe(2);
expect(results.total_amount_received).toBeGreaterThan(0);

/*
* According to the REWARD_SPEND_MIN_BLOCKS variable in the ./configuration/privnet.py file
* the miner rewards are locked for exactly one block. Since we have only one miner reward
* address, this value should be always 6400 or greater.
*
* Should another miner reward address be included later, this assertion must be recalculated.
*/
expect(results.total_amount_locked).toBeGreaterThanOrEqual(6400);
done();
});

it('should return results for an address with send/receive transactions', async done => {
const response = await TestUtils.request
.get('/wallet/address-info')
.query({ address: await wallet2.getAddressAt(0) })
.set({ 'x-wallet-id': wallet2.walletId });

expect(response.status).toBe(200);

const results = response.body;
expect(results.success).toBeTruthy();
expect(results.token).toBe(HATHOR_TOKEN_ID);
expect(results.index).toBe(0);
expect(results.total_amount_received).toBe(15); // 10 from genesis, 5 from token creation change
expect(results.total_amount_sent).toBe(10); // token creation tx
expect(results.total_amount_available).toBe(5); // change
expect(results.total_amount_locked).toBe(0);
done();
});

it('should return results for custom token for an address (empty)', async done => {
const response = await TestUtils.request
.get('/wallet/address-info')
.query({
address: await wallet2.getAddressAt(0),
token: customTokenHash,
})
.set({ 'x-wallet-id': wallet2.walletId });

expect(response.status).toBe(200);

const results = response.body;
expect(results.success).toBeTruthy();
expect(results.token).toBe(customTokenHash);
expect(results.index).toBe(0);
expect(results.total_amount_received).toBe(0);
expect(results.total_amount_sent).toBe(0);
expect(results.total_amount_available).toBe(0);
expect(results.total_amount_locked).toBe(0);
done();
});

it('should return results for custom token on an address with a single transaction', async done => {
const response = await TestUtils.request
.get('/wallet/address-info')
.query({
address: await wallet2.getAddressAt(1),
token: customTokenHash,
})
.set({ 'x-wallet-id': wallet2.walletId });

expect(response.status).toBe(200);

const results = response.body;
expect(results.success).toBeTruthy();
expect(results.token).toBe(customTokenHash);
expect(results.index).toBe(1);
expect(results.total_amount_received).toBe(500);
expect(results.total_amount_sent).toBe(0);
expect(results.total_amount_available).toBe(500);
expect(results.total_amount_locked).toBe(0);
done();
});
});
102 changes: 102 additions & 0 deletions __tests__/integration/balance.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { getRandomInt, TestUtils, WALLET_CONSTANTS } from './utils/test-utils-integration';
import { WalletHelper } from './utils/wallet-helper';

describe('balance routes', () => {
/** @type WalletHelper */
let wallet1;
let wallet2;
let wallet3;
const wallet2Balance = getRandomInt(200);

beforeAll(async () => {
try {
// First wallet, no balance
wallet1 = new WalletHelper('balance1');
await wallet1.start();

// Second wallet, random balance
wallet2 = new WalletHelper('balance2');
await wallet2.start();
await wallet2.injectFunds(wallet2Balance);

// Third wallet, balance to be used for custom tokens
wallet3 = new WalletHelper('custom3');
await wallet3.start();
await wallet3.injectFunds(100);
} catch (err) {
TestUtils.logError(err.stack);
}
});

afterAll(async () => {
await wallet1.stop();
await wallet2.stop();
await wallet3.stop();
});

it('should return zero for an empty wallet', async done => {
const balanceResult = await TestUtils.request
.get('/wallet/balance')
.set({ 'x-wallet-id': wallet1.walletId });

expect(balanceResult.body.available).toBe(0);
expect(balanceResult.body.locked).toBe(0);
done();
});

it('should return correct balance for a wallet with one transaction', async done => {
const balanceResult = await TestUtils.request
.get('/wallet/balance')
.set({ 'x-wallet-id': wallet2.walletId });

expect(balanceResult.body.available).toBe(wallet2Balance);
expect(balanceResult.body.locked).toBe(0);
done();
});

it('should return some locked balance for the miner wallet', async done => {
const balanceResult = await TestUtils.request
.get('/wallet/balance')
.set({ 'x-wallet-id': WALLET_CONSTANTS.genesis.walletId });

/*
* According to the REWARD_SPEND_MIN_BLOCKS variable in the ./configuration/privnet.py file
* the miner rewards are locked for exactly one block. Since we have only one miner reward
* address, this value should be always 6400 or greater.
*
* Should another miner reward address be included later, this assertion must be recalculated.
*/
expect(balanceResult.body.locked).toBeGreaterThanOrEqual(6400);
done();
});

it('should return correct balance for a custom token (empty)', async done => {
const balanceResult = await TestUtils.request
.get('/wallet/balance')
.query({ token: 'TST' })
.set({ 'x-wallet-id': wallet1.walletId });

expect(balanceResult.body.available).toBe(0);
expect(balanceResult.body.locked).toBe(0);
done();
});

it('should return correct balance for a custom token', async done => {
const tokenAmount = getRandomInt(200, 100);
const newToken = await wallet3.createToken({
name: 'Test Token',
symbol: 'TST',
amount: tokenAmount,
});
const tokenHash = newToken.hash;

const balanceResult = await TestUtils.request
.get('/wallet/balance')
.query({ token: tokenHash })
.set({ 'x-wallet-id': wallet3.walletId });

expect(balanceResult.body.available).toBe(tokenAmount);
expect(balanceResult.body.locked).toBe(0);
done();
});
});
Loading