Skip to content

Commit

Permalink
Merge pull request #253 from logion-network/feature/fix-para-integrat…
Browse files Browse the repository at this point in the history
…ion-tests

Adapt client integration tests to Parachain
  • Loading branch information
benoitdevos authored Apr 19, 2024
2 parents 60e93bd + fafdc4f commit d9d47cd
Show file tree
Hide file tree
Showing 25 changed files with 364 additions and 408 deletions.
2 changes: 2 additions & 0 deletions packages/client-node/.env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# See README
RPC_WS="172.19.0.1:9944"
1 change: 1 addition & 0 deletions packages/client-node/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.env
16 changes: 16 additions & 0 deletions packages/client-node/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,19 @@ Use your favorite package manager (e.g. yarn) and install package `@logion/clien
## Usage

See [core client](../client/README.md).

## Integration tests

### Pre-requisites

Below steps must be executed only if you did not yet create the `logion-test` network.

- Create `logion-test` network: `docker network create logion-test`
- Get network's gateway IP address: `docker network inspect logion-test | jq '.[0].IPAM.Config[0].Gateway'`
- Set `RPC_WS` variable in `.env` file (see `.env.sample` for an example) with the above IP address

### Running the tests

- Start the Logion chain locally (see [here](https://github.com/logion-network/logion-collator/?tab=readme-ov-file#test-locally))
- In another terminal, run the tests: `yarn integration-test`
- Stop Zombienet
52 changes: 12 additions & 40 deletions packages/client-node/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
version: "3.6"
networks:
default:
name: logion-test
external: true

services:
# ----------------------------------------- Logion node 1 --------------------------------------------------------------
private-database1:
image: logionnetwork/logion-postgres:${PG_TAG:-latest}
environment:
- POSTGRES_PASSWORD=secret
node1:
image: logionnetwork/logion-node:${NODE_TAG:-latest}
environment:
- NODE_KEY=c12b6d18942f5ee8528c8e2baf4e147b5c5c18710926ea492d09cbd9f6c9f82a
- CUSTOM_OPTIONS=--alice --no-mdns --rpc-external --rpc-cors all
- CHAIN_SPEC=test
backend1:
image: logionnetwork/logion-backend:${BACKEND_TAG:-latest}
environment:
- JWT_SECRET=c12b6d18942f5ee8528c8e2baf4e147b5c5c18710926ea492d09cbd9f6c9f82a
- JWT_ISSUER=12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2
- TYPEORM_HOST=private-database1
- WS_PROVIDER_URL=ws://node1:9944
- WS_PROVIDER_URL=ws://$RPC_WS
- OWNER=5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
- DIRECTORY_URL=http://directory:8080
- SMTP_ENABLED=false
Expand All @@ -27,24 +25,21 @@ services:
- IPFS_MAX_REPLICA=2
- ENC_PASSWORD=test
depends_on:
- node1
- private-database1
- ipfs-cluster1
frontend1:
image: logionnetwork/logion-frontend:${FRONTEND_TAG:-latest}
ports:
- 127.0.0.1:8080:80
- 127.0.0.1:9944:9944
volumes:
- ./front_config.js:/usr/share/nginx/html/config.js
- ./front_web1.conf:/etc/nginx/conf.d/default.conf
depends_on:
- backend1
- node1
environment:
- [email protected]
- BACKEND_HOST_PORT=backend1:8080
- NODE_HOST_PORT=node1:9944
- NODE_HOST_PORT=$RPC_WS
ipfs1:
image: ipfs/go-ipfs:v0.12.0
ports:
Expand All @@ -68,21 +63,13 @@ services:
image: logionnetwork/logion-postgres:${PG_TAG:-latest}
environment:
- POSTGRES_PASSWORD=secret
node2:
image: logionnetwork/logion-node:${NODE_TAG:-latest}
environment:
- NODE_KEY=6ce3be907dbcabf20a9a5a60a712b4256a54196000a8ed4050d352bc113f8c58
- CUSTOM_OPTIONS=--bob --no-mdns --bootnodes /dns4/node1/tcp/30333/p2p/12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2 --rpc-external --rpc-cors all
- CHAIN_SPEC=test
depends_on:
- node1
backend2:
image: logionnetwork/logion-backend:${BACKEND_TAG:-latest}
environment:
- JWT_SECRET=6ce3be907dbcabf20a9a5a60a712b4256a54196000a8ed4050d352bc113f8c58
- JWT_ISSUER=12D3KooWQYV9dGMFoRzNStwpXztXaBUjtPqi6aU76ZgUriHhKust
- TYPEORM_HOST=private-database2
- WS_PROVIDER_URL=ws://node2:9944
- WS_PROVIDER_URL=ws://$RPC_WS
- OWNER=5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty
- DIRECTORY_URL=http://directory:8080
- SMTP_ENABLED=false
Expand All @@ -92,24 +79,21 @@ services:
- IPFS_MAX_REPLICA=2
- ENC_PASSWORD=test
depends_on:
- node2
- private-database2
- ipfs-cluster2
frontend2:
image: logionnetwork/logion-frontend:${FRONTEND_TAG:-latest}
ports:
- 127.0.0.1:8081:80
- 127.0.0.1:9945:9944
volumes:
- ./front_config.js:/usr/share/nginx/html/config.js
- ./front_web2.conf:/etc/nginx/conf.d/default.conf
depends_on:
- backend2
- node2
environment:
- [email protected]
- BACKEND_HOST_PORT=backend2:8080
- NODE_HOST_PORT=node2:9944
- NODE_HOST_PORT=$RPC_WS
ipfs2:
image: ipfs/go-ipfs:v0.12.0
volumes:
Expand All @@ -132,21 +116,13 @@ services:
image: logionnetwork/logion-postgres:${PG_TAG:-latest}
environment:
- POSTGRES_PASSWORD=secret
node3:
image: logionnetwork/logion-node:${NODE_TAG:-latest}
environment:
- NODE_KEY=3a9d5b35b9fb4c42aafadeca046f6bf56107bd2579687f069b42646684b94d9e
- CUSTOM_OPTIONS=--charlie --no-mdns --bootnodes /dns4/node1/tcp/30333/p2p/12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2 --rpc-external --rpc-cors all
- CHAIN_SPEC=test
depends_on:
- node1
backend3:
image: logionnetwork/logion-backend:${BACKEND_TAG:-latest}
environment:
- JWT_SECRET=3a9d5b35b9fb4c42aafadeca046f6bf56107bd2579687f069b42646684b94d9e
- JWT_ISSUER=12D3KooWJvyP3VJYymTqG7eH4PM5rN4T2agk5cdNCfNymAqwqcvZ
- TYPEORM_HOST=private-database3
- WS_PROVIDER_URL=ws://node3:9944
- WS_PROVIDER_URL=ws://$RPC_WS
- OWNER=5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y
- DIRECTORY_URL=http://directory:8080
- SMTP_ENABLED=false
Expand All @@ -156,24 +132,21 @@ services:
- IPFS_MAX_REPLICA=2
- ENC_PASSWORD=test
depends_on:
- node3
- private-database3
- ipfs-cluster3
frontend3:
image: logionnetwork/logion-frontend:${FRONTEND_TAG:-latest}
ports:
- 127.0.0.1:8082:80
- 127.0.0.1:9946:9944
volumes:
- ./front_config.js:/usr/share/nginx/html/config.js
- ./front_web3.conf:/etc/nginx/conf.d/default.conf
depends_on:
- backend3
- node3
environment:
- [email protected]
- BACKEND_HOST_PORT=backend3:8080
- NODE_HOST_PORT=node3:9944
- NODE_HOST_PORT=$RPC_WS
ipfs3:
image: ipfs/go-ipfs:v0.12.0
volumes:
Expand Down Expand Up @@ -205,8 +178,7 @@ services:
environment:
- JWT_SECRET=c12b6d18942f5ee8528c8e2baf4e147b5c5c18710926ea492d09cbd9f6c9f82a
- JWT_ISSUER=12D3KooWBmAwcd4PJNJvfV89HwE48nwkRmAgo8Vy3uQEyNNHBox2
- WS_PROVIDER_URL=ws://node1:9944
- WS_PROVIDER_URL=ws://$RPC_WS
- TYPEORM_HOST=directory-database
depends_on:
- node1
- directory-database
17 changes: 0 additions & 17 deletions packages/client-node/front_web1.conf
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,3 @@ server {
root /usr/share/nginx/html;
}
}

server {
listen 9944;
listen [::]:9944;
server_name localhost;

location / {
proxy_pass http://node1:9944;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
17 changes: 0 additions & 17 deletions packages/client-node/front_web2.conf
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,3 @@ server {
root /usr/share/nginx/html;
}
}

server {
listen 9944;
listen [::]:9944;
server_name localhost;

location / {
proxy_pass http://node2:9944;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
17 changes: 0 additions & 17 deletions packages/client-node/front_web3.conf
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,3 @@ server {
root /usr/share/nginx/html;
}
}

server {
listen 9944;
listen [::]:9944;
server_name localhost;

location / {
proxy_pass http://node3:9944;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
69 changes: 47 additions & 22 deletions packages/client-node/integration/Balance.ts
Original file line number Diff line number Diff line change
@@ -1,89 +1,114 @@
import { Numbers, CoinBalance, Lgnt } from "@logion/node-api";
import { BalanceState, waitFor } from "@logion/client";

import { State, REQUESTER_ADDRESS } from "./Utils.js";
import { ALICE } from "./Utils.js";
import { State } from "./Utils.js";

export async function transfers(state: State) {
const { client, signer, aliceAccount, requesterAccount } = state;
const { client, signer, alice, requesterAccount } = state;

// Alice transfers to user.
const aliceClient = client.withCurrentAddress(aliceAccount)
const aliceClient = client.withCurrentAccount(alice.account)
let aliceState = await aliceClient.balanceState();

checkBalance(aliceState, "99.99k");
let aliceSnapshot = takeSnapshot(aliceState);
expect(aliceState.transactions.length).toBe(0);
aliceState = await aliceState.transfer({
signer,
amount: Lgnt.from(5000n),
destination: REQUESTER_ADDRESS
destination: requesterAccount,
});
checkBalance(aliceState, "94.99k");
checkBalanceDelta(aliceState, "-4.99k", aliceSnapshot);
aliceState = await waitFor({
producer: async state => state ? await state.refresh() : aliceState,
predicate: state => state.transactions.length === 2,
predicate: state => {
if (state.transactions.length > 0) {
const transaction = state.transactions[0];
return transaction.pallet === "balances" && transaction.method === "transferKeepAlive"
} else {
return false;
}
}
});
expect(aliceState.transactions[0].fees.inclusion).toBeGreaterThan(0);
expect(aliceState.transactions[0].fees.storage).toBeUndefined();
expect(aliceState.transactions[0].transferValue).toBe(Lgnt.fromPrefixedNumber(new Numbers.PrefixedNumber("5", Numbers.KILO)).toString());

// User transfers to Alice.
const userClient = client.withCurrentAddress(requesterAccount)
const userClient = client.withCurrentAccount(requesterAccount)
let userState = await userClient.balanceState();

aliceSnapshot = takeSnapshot(await aliceState.refresh());

checkBalance(userState, "5.00k");
userState = await userState.transfer({
signer,
amount: Lgnt.from(2000n),
destination: ALICE
destination: alice.account,
});
checkBalance(userState, "2.99k");

// TODO: the balance of a LO is not stable as it increases with block rewards
// this integration test should be rewritten with regular users.
//
// Alice checks her balance.
// aliceState = await aliceState.refresh();
// checkBalance(aliceState, "97.00k"); // is sometimes 96.99k depending on block reward.
aliceState = await aliceState.refresh();
checkBalanceDelta(aliceState, "2.00k", aliceSnapshot);
}

export function checkBalance(balanceState: BalanceState, expectedValue: string) {
const balance = balanceState.balances[0];
checkCoinBalance(balance, expectedValue);
}

export function takeSnapshot(balanceState: BalanceState): CoinBalance {
return balanceState.balances[0];
}

export function checkBalanceDelta(current: BalanceState, expectedDelta: string, previous: CoinBalance) {
checkCoinBalanceDelta(takeSnapshot(current), expectedDelta, previous);
}

export function checkCoinBalanceDelta(current: CoinBalance, expectedDelta: string, previous: CoinBalance) {
expect(current.coin).toEqual(previous.coin);
const delta: CoinBalance = {
coin: current.coin,
available: current.available.subtract(previous.available),
reserved: current.reserved.subtract(previous.reserved),
total: current.total.subtract(previous.total),
level: current.level - previous.level,
}
checkCoinBalance(delta, expectedDelta);
}

export function checkCoinBalance(balance: CoinBalance, expectedValue: string) {
const formatted = formatBalance(balance);
expect(formatted).toEqual(expectedValue)
expect(expectedValue).toEqual(formatted)
}

export function formatBalance(balance: CoinBalance): string {
return `${balance.total.coefficient.toInteger()}.${balance.total.coefficient.toFixedPrecisionDecimals(2)}${balance.total.prefix.symbol}`;
}

export async function transferAndCannotPayFees(state: State) {
const { client, signer, requesterAccount } = state;
const { client, signer, requesterAccount, alice } = state;

const requesterClient = client.withCurrentAddress(requesterAccount)
const requesterClient = client.withCurrentAccount(requesterAccount)
let balanceState = await requesterClient.balanceState();

await expectAsync(balanceState.transfer({
signer,
amount: Lgnt.from(1n),
destination: ALICE,
destination: alice.account,
})).toBeRejectedWithError("Not enough funds available to pay fees");
}

export async function transferWithInsufficientFunds(state: State) {
const { client, signer, aliceAccount } = state;
const { client, signer, alice, requesterAccount } = state;

// Alice transfers to user.
const aliceClient = client.withCurrentAddress(aliceAccount)
const aliceClient = client.withCurrentAccount(alice.account)
let aliceState = await aliceClient.balanceState();

await expectAsync(aliceState.transfer({
signer,
amount: Lgnt.fromCanonicalPrefixedNumber(aliceState.balances[0].available).add(Lgnt.from(1)),
destination: REQUESTER_ADDRESS
destination: requesterAccount,
})).toBeRejectedWithError("Insufficient balance");
}
Loading

0 comments on commit d9d47cd

Please sign in to comment.