Skip to content

Commit 499347d

Browse files
authored
feat: thor solo node setup (#164)
* feat: added global coverage folder for unit & integration coverage reports merged * chore: gitignore * feat: thor-solo docker compose * feat: root package.json unit & integration scripts with merge coverage * chore: turbo config * refactor: coverage-results artifact download path * feat: network package jest config for setup & teardown * feat: jest global setup & teardown implementation * feat: setup & teardown usage * refactor: core package.json * feat: integration tests in network package.json * test: initial integration tests * test: incease timeout for testnet tests * test: refactor timeout * refactor: sonar properties lcov report path * fix: lcov report path sonar properties * refactor: coverage paths back to each package * fix: removed lcov info versioning * fix: sonar lcov report paths * fix: sonar lcov report paths * fix: pipeline coverage artifact path * refactor: restore lcov report path sonar properties * feat: merge-coverage script with nyc * refactor: coverage report merging configs * refactor: sonar test inclusions * refactor: sonar test inclusions * refactor: restore sonar properties * refactor: removing coverage report merging * feat: add jest files to coverage exclusions * chore: minor polishing * feat: ignore all coverage files * feat: updated thor image tag * refactor: removed sonar coverage exclusions errors * refactor: removed empty comment * refactor: added gas limit comment
1 parent 886b0ee commit 499347d

20 files changed

+658
-39
lines changed

.github/workflows/unit-integration-test.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,4 @@ jobs:
2727
with:
2828
name: coverage-results
2929
path: |
30-
packages/**/lcov.info
30+
packages/**/coverage/lcov.info

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ apps/**/node_modules
88

99
yarn-error.log
1010
# Code coverage folder for tests
11-
coverage
11+
coverage*
1212
**/.DS_Store
1313

1414
# Turborepo

docker-compose.yaml

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
version: "3.9"
2+
3+
services:
4+
thor-solo:
5+
image: vechain/thor:v2.1.0
6+
container_name: thor-solo
7+
ports:
8+
- 8669:8669
9+
command:
10+
- solo
11+
- --on-demand # create new block when there is pending transaction
12+
- --api-addr=0.0.0.0:8669 # Enable remote connections
13+
- --api-cors=* # comma separated list of domains to accept cross origin requests to API
14+
- --gas-limit=10000000000000 # block gas limit
15+
- --api-call-gas-limit=10000000000000 # limit contract call gas
16+
- --txpool-limit=100000000000 # limit txpool size
17+
- --txpool-limit-per-account=256 # limit txpool size per account
18+
- --cache=1024 # megabytes of ram allocated to trie nodes cache
19+
healthcheck:
20+
# We run the health check using standard UNIX tools so we don't have to
21+
# install additional dependencies in the container.
22+
test: wget -O- http://localhost:8669/blocks/0
23+
interval: 5s
24+
timeout: 10s
25+
retries: 10

package.json

+7-6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"lint": "turbo lint",
1212
"test": "turbo test",
1313
"test:unit": "turbo test:unit",
14+
"test:integration": "turbo test:integration",
1415
"format": "turbo format",
1516
"test:docs": "turbo test:docs",
1617
"test:examples": "turbo test:examples"
@@ -22,6 +23,8 @@
2223
"docs"
2324
],
2425
"devDependencies": {
26+
"@commitlint/cli": "^18.1.0",
27+
"@commitlint/config-conventional": "^18.1.0",
2528
"@jest/globals": "^29.7.0",
2629
"@typescript-eslint/eslint-plugin": "^6.8.0",
2730
"@typescript-eslint/parser": "^6.0.0",
@@ -32,17 +35,15 @@
3235
"eslint-plugin-n": "^15.0.0 || ^16.0.0 ",
3336
"eslint-plugin-prettier": "^5.0.1",
3437
"eslint-plugin-promise": "^6.0.0",
38+
"husky": "^8.0.3",
3539
"jest": "^29.7.0",
36-
"jest-runner": "^29.7.0",
3740
"jest-docblock": "^24",
41+
"jest-runner": "^29.7.0",
3842
"jest-runner-groups": "^2.2.0",
3943
"prettier": "^3.0.3",
4044
"ts-jest": "^29.1.1",
4145
"tsup": "^7.2.0",
42-
"typescript": "*",
43-
"@commitlint/cli": "^18.1.0",
44-
"@commitlint/config-conventional": "^18.1.0",
45-
"husky": "^8.0.3",
46-
"turbo": "^1.10.15"
46+
"turbo": "^1.10.15",
47+
"typescript": "*"
4748
}
4849
}

packages/core/package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
"scripts": {
88
"build": "rm -rf ./dist && tsup src/index.ts --format cjs,esm --dts",
99
"lint": "eslint --ext .ts src --ext .ts tests",
10-
"test": "rm -rf ./coverage && jest --coverage",
11-
"test:unit": "rm -rf ./coverage && jest --coverage --group=unit",
10+
"test:unit": "rm -rf ./coverageUnit && jest --coverage --coverageDirectory=coverageUnit --group=unit",
11+
"test:integration": "export JEST_INTEGRATION=true; rm -rf ./coverageIntegration && jest --coverage --coverageDirectory=coverageIntegration --group=integration",
12+
"test": "export JEST_INTEGRATION=true; rm -rf ./coverage && jest --coverage --coverageDirectory=coverage --group=integration --group=unit",
1213
"format": "prettier --write src/**/*.ts tests/**/*.ts"
1314
},
1415
"dependencies": {

packages/errors/jest.config.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/** @type {import('ts-jest').JestConfigWithTsJest} */
22
module.exports = {
3-
preset: 'ts-jest',
4-
testEnvironment: 'node',
5-
coverageReporters: ['html', 'lcov']
6-
}
3+
preset: 'ts-jest',
4+
testEnvironment: 'node',
5+
coverageReporters: ['html', 'lcov']
6+
};

packages/errors/package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
"scripts": {
88
"build": "rm -rf ./dist && tsup src/index.ts --format cjs,esm --dts",
99
"lint": "eslint --ext .ts src --ext .ts tests",
10-
"test": "rm -rf ./coverage && jest --coverage",
10+
"test:unit": "rm -rf ./coverageUnit && jest --coverage --coverageDirectory=coverageUnit --group=unit",
11+
"test:integration": "export JEST_INTEGRATION=true; rm -rf ./coverageIntegration && jest --coverage --coverageDirectory=coverageIntegration --group=integration",
12+
"test": "export JEST_INTEGRATION=true; rm -rf ./coverage && jest --coverage --coverageDirectory=coverage --group=integration --group=unit",
1113
"format": "prettier --write src/**/*.ts tests/**/*.ts"
1214
},
1315
"devDependencies": {

packages/network/jest.config.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
/** @type {import('ts-jest').JestConfigWithTsJest} */
22
module.exports = {
3+
globalSetup: '<rootDir>/jest.setup.ts',
4+
globalTeardown: '<rootDir>/jest.teardown.ts',
35
preset: 'ts-jest',
46
testEnvironment: 'node',
57
coverageReporters: ['html', 'lcov'],

packages/network/jest.global.ts

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import {
2+
DockerComposeEnvironment,
3+
type StartedDockerComposeEnvironment,
4+
Wait
5+
} from 'testcontainers';
6+
7+
/** Instance of the started Docker Compose environment. */
8+
let dockerEnvironment: StartedDockerComposeEnvironment;
9+
10+
/** Path to the directory containing the Docker Compose file. */
11+
const DOCKER_COMPOSE_FILE_PATH = '../../';
12+
13+
/** Name of the Docker Compose file. */
14+
const DOCKER_COMPOSE_FILE_NAME = 'docker-compose.yaml';
15+
16+
/** Name of the service within the Docker Compose file. */
17+
const THOR_SOLO_SERVICE_NAME = 'thor-solo';
18+
19+
/**
20+
* Set up the Docker Compose environment if the `JEST_INTEGRATION` environment variable is set to 'true'.
21+
*/
22+
export const setup = async (): Promise<void> => {
23+
if (process.env.JEST_INTEGRATION !== 'true') return;
24+
25+
console.log('Starting thor-solo node...');
26+
27+
dockerEnvironment = await new DockerComposeEnvironment(
28+
DOCKER_COMPOSE_FILE_PATH,
29+
DOCKER_COMPOSE_FILE_NAME
30+
)
31+
.withStartupTimeout(60_000)
32+
.withWaitStrategy(THOR_SOLO_SERVICE_NAME, Wait.forHealthCheck())
33+
.up();
34+
35+
console.log('thor-solo node started');
36+
};
37+
38+
/**
39+
* Tear down the Docker Compose environment if the `JEST_INTEGRATION` environment variable is set to 'true'.
40+
* If `dockerEnvironment` is defined, stops the Docker Compose environment, otherwise logs that it won't be stopped.
41+
*/
42+
export const teardown = async (): Promise<void> => {
43+
if (process.env.JEST_INTEGRATION !== 'true') return;
44+
45+
try {
46+
if (dockerEnvironment !== undefined) {
47+
console.log('\nStopping thor-solo node...');
48+
await dockerEnvironment.down();
49+
console.log('thor-solo node stopped');
50+
} else {
51+
console.log(
52+
'Not stopping thor-solo node because it was not started'
53+
);
54+
}
55+
} catch (e) {
56+
console.error(e);
57+
}
58+
};

packages/network/jest.setup.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { setup } from './jest.global';
2+
3+
export default setup;

packages/network/jest.teardown.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { teardown } from './jest.global';
2+
3+
export default teardown;

packages/network/package.json

+6-3
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77
"scripts": {
88
"build": "rm -rf ./dist && tsup src/index.ts --format cjs,esm --dts",
99
"lint": "eslint --ext .ts src --ext .ts tests",
10-
"test": "rm -rf ./coverage && jest --coverage",
11-
"test:unit": "rm -rf ./coverage && jest --coverage --group=unit"
10+
"test:unit": "rm -rf ./coverageUnit && jest --coverage --coverageDirectory=coverageUnit --group=unit",
11+
"test:integration": "export JEST_INTEGRATION=true; rm -rf ./coverageIntegration && jest --coverage --coverageDirectory=coverageIntegration --group=integration",
12+
"test": "export JEST_INTEGRATION=true; rm -rf ./coverage && jest --coverage --coverageDirectory=coverage --group=integration --group=unit",
13+
"format": "prettier --write src/**/*.ts tests/**/*.ts"
1214
},
1315
"dependencies": {
14-
"axios": "^1.5.1"
16+
"axios": "^1.5.1",
17+
"testcontainers": "^10.2.1"
1518
}
1619
}

packages/network/tests/driver/driver.test.ts packages/network/tests/driver/driver.solo.test.ts

+17-10
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
11
import { describe, expect, test } from '@jest/globals';
2+
import {
3+
ZERO_ADDRESS,
4+
soloNetwork,
5+
testAccount,
6+
zeroAddressAccountDetails
7+
} from './fixture';
28
import { type NetParams } from '../../src';
3-
import { firstTestnetBlock, network, testAccount } from './fixture';
49

510
/**
611
* SimpleNet class tests
12+
* @group integration/network
713
*/
8-
describe('Test SimpleNet class', () => {
14+
describe('Test SimpleNet class on Solo', () => {
915
/**
1016
* HTTP Request tests
1117
*/
1218
test('Should perform an HTTP GET request and resolve with response data', async () => {
13-
// Perform an HTTP GET request using the SimpleNet instance
14-
const response = await network.http('GET', '/blocks/1?expanded=false');
19+
const response = await soloNetwork.http(
20+
'GET',
21+
`/accounts/${ZERO_ADDRESS}`
22+
);
1523

16-
// Assert that the response matches the expected firstTestnetBlock
1724
expect(JSON.stringify(response)).toEqual(
18-
JSON.stringify(firstTestnetBlock)
25+
JSON.stringify(zeroAddressAccountDetails)
1926
);
2027
});
2128

@@ -24,9 +31,9 @@ describe('Test SimpleNet class', () => {
2431
*/
2532
test('Should reject with an error if the HTTP request fails', async () => {
2633
// Assert that the HTTP request fails with an error
27-
await expect(network.http('GET', '/error-test-path')).rejects.toThrow(
28-
'404 get /error-test-path: 404 page not found'
29-
);
34+
await expect(
35+
soloNetwork.http('GET', '/error-test-path')
36+
).rejects.toThrow('404 get /error-test-path: 404 page not found');
3037
});
3138

3239
/**
@@ -47,7 +54,7 @@ describe('Test SimpleNet class', () => {
4754
};
4855

4956
// Make an actual HTTP GET request and pass the validateResponseHeaders function
50-
const response = await network.http(
57+
const response = await soloNetwork.http(
5158
'GET',
5259
'/accounts/' + testAccount,
5360
customParams
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { describe, expect, test } from '@jest/globals';
2+
import { type NetParams } from '../../src';
3+
import { firstTestnetBlock, network, testAccount } from './fixture';
4+
5+
/**
6+
* Timeout for each test.
7+
* Overrides the default timeout of 5 seconds due to cases where the network request takes longer than 5 seconds.
8+
*/
9+
const TIMEOUT = 10000;
10+
11+
/**
12+
* SimpleNet class tests
13+
* @group integration/network
14+
*/
15+
describe('Test SimpleNet class on Testnet', () => {
16+
/**
17+
* HTTP Request tests
18+
*/
19+
test(
20+
'Should perform an HTTP GET request and resolve with response data',
21+
async () => {
22+
// Perform an HTTP GET request using the SimpleNet instance
23+
const response = await network.http(
24+
'GET',
25+
'/blocks/1?expanded=false'
26+
);
27+
28+
// Assert that the response matches the expected firstTestnetBlock
29+
expect(JSON.stringify(response)).toEqual(
30+
JSON.stringify(firstTestnetBlock)
31+
);
32+
},
33+
TIMEOUT
34+
);
35+
36+
/**
37+
* HTTP Request tests rejecting with an error
38+
*/
39+
test(
40+
'Should reject with an error if the HTTP request fails',
41+
async () => {
42+
// Assert that the HTTP request fails with an error
43+
await expect(
44+
network.http('GET', '/error-test-path')
45+
).rejects.toThrow('404 get /error-test-path: 404 page not found');
46+
},
47+
TIMEOUT
48+
);
49+
50+
/**
51+
* Request params validation
52+
*/
53+
test(
54+
'Should validate response headers',
55+
async () => {
56+
const customParams: NetParams = {
57+
query: {},
58+
body: {},
59+
headers: {
60+
'X-Custom-Header': 'custom-value'
61+
},
62+
validateResponseHeader: function (
63+
headers: Record<string, string>
64+
): void {
65+
expect(headers).toBeDefined();
66+
}
67+
};
68+
69+
// Make an actual HTTP GET request and pass the validateResponseHeaders function
70+
const response = await network.http(
71+
'GET',
72+
'/accounts/' + testAccount,
73+
customParams
74+
);
75+
76+
// You can also check the response data if needed
77+
expect(response).toBeDefined();
78+
},
79+
TIMEOUT
80+
);
81+
});

0 commit comments

Comments
 (0)