This project enables writing and running end-to-end tests on Ark core (v2).
Install the project dependencies :
npm install
Now to run the tests locally, you need to have Docker installed. Then, run this command to initialize docker swarm feature :
docker swarm init
You can now run the configured tests like this :
bin/e2e generate -n e2enet -c 3
sudo chmod +x dist/e2enet/docker*
cd dist/e2enet && ./docker-init.sh && ./docker-start.sh && cd ../..
bin/e2e run-tests -n e2enet -s scenario1
This will generate the configured network e2enet
with 3 nodes and run the tests defined in scenario1
. (it can take some time depending on your machine resources)
To see the existing tests or create new tests, have a look at the tests
folder. You will find 2 sub-folders : networks
and scenarios
.
We will just look at the scenarios
sub-folder as we don't want to set up a new network, we already have the default e2enet
which we will use.
scenarios / scenario1 / config.js
scenarios / scenario1 / doublespend1
So we find our scenario1
that we executed before. It contains one file for configuration, and (currently) one sub-folder named doublespend1
which contains one complete test case for double spending.
Let's first look at config.js
:
module.exports = {
network: 'e2enet',
enabledTests: [
'doublespend1'
]
}
Pretty straightforward : the network on which we want to execute the scenario, and the test cases we want to run on it.
A test case typically contains some actions to be executed on the network (transactions for example), and some tests to check that the behavior is correct. Let's have a look at the doublespend1
folder :
0.transfer-new-wallet.action.js
1.doublespend.action.js
2.check-tx.test.js
config.js
utils.js
We can notice a few things here :
- The test case steps are prefixed by a number for clarity
- The actions steps are suffixed by
action.js
and the test steps are suffixed by.test.js
- There is a configuration file
config.js
and a helper fileutils.js
config.js
defines the steps to be run to execute the test case :
module.exports = {
events: {
newBlock: {
8: [ '0.transfer-new-wallet.action' ],
11: [ '1.doublespend.action' ],
14: [ '2.check-tx.test' ]
}
}
}
The steps are plugged into the network's events : right now the only events available are new block events. Here we can see at block 8 we transfer some coins to a new wallet, then at block 11 we perform a double spend action, finally at block 14 we check the last transactions (to see if the double spend was accepted by the network or not).
To create action files, we just export (module.export
) a function containing what we want to execute.
To create test files, we write Jest tests as we would do with unit tests (describe
etc).
You can have a look at doublespend1
folder to have examples of actions and tests.
To perform some actions (like creating a new transaction), we want to send requests to one node's API.
The nodes between themselves interact through classic 4000 / 4003 ports. But externally their ports are mapped so in our test we interact with them differently :
- For API calls we request localhost on port ( 4300 + node number ) to access a specific node (node numbers start from zero, so node0 will be requested on port 4300, node1 on port 4301...)
- For P2P calls we request localhost on port ( 4000 + node number )
Here are some tips :
- Create one folder for one coherent test case
- Initialize what you need in your test case, don't re-use something from another test case : create your own wallets (transfer coins from genesis), your own transactions etc.
- Use an
utils.js
file if you need, also have a look atutils.js
in thenetworks
folder and in thelib
folder
The end-to-end tests are configured to run on CircleCI every day : to see which network and scenarios are configured, you can have a look at .circleci/config.yml
file.
To understand how this end-to-end testing framework works behind the scenes, have a look at TechnicalDetails.md.
Please create new issues, or contact me if you want to discuss about it.