Skip to content
This repository was archived by the owner on Aug 1, 2023. It is now read-only.

Commit 278ebc5

Browse files
authored
Start to Improve Scenarios as Regression Tests (#275)
* Start to Improve Scenarios as Regression Tests This patch starts to improve scenarios so that they can pass consistently. We make a few changes: 1. We add a `QUIET_SCENARIOS` flag that pushes all scenario output to temp files. This makes it possible to run scenarios and see the output and not 1,000 pages of validator text. 2. We add an `EventTracker` module that handles tracking events without using global vars (which was probably messing up test cases). Events are hard because they come in from a subscription in PolkadotJS, but our scenarios often ask "Have you seen any Substrate `Lock()` events?" and we have to say something like "Yes, we saw one more recently than the last time you asked." That can be a bit tricky and now that state is encapsulated and doesn't leak from one scenario to the next (this may have been a large bug in running sequential tests). 3. We start to move back away from `--runInBand` which means tests will run in separate processes and concurrently again. We may want to make it easier to not run in band for building tests (it's just a matter of passing the flag, but engineers might forget/not know how to do this, so we should make that clear). 4. We remove `only: true` and start to add back multiple tests so we can measure what is working and not. So far the results are not too excessively shabby. * Continue to fix integration tests * Add RPC decoration to preclude warnings * Make scenarios quiet in CI * Fix line number errors * Track sleeps for better teardown procedure * Try to quiet them down * Increase timeout * Try again * Get more tests passing * Get last upgrade scen working again * Finish prices tests * Add complex scenario for borrow cash interest * Add features for integration mode * More cleanup and fixes * Clean up Gov tests * Clean up more tests, including prices * Fix some types issues and merge conflicts * It was always a String, let's make it so
1 parent 80d6720 commit 278ebc5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1474
-715
lines changed

.github/workflows/test-workflow.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -237,14 +237,14 @@ jobs:
237237
238238
- name: Build Gateway
239239
run: |
240-
cargo build
240+
cargo build --release --features freeze-time --features runtime-debug
241241
242242
- name: Run Integration Test
243-
timeout-minutes: 20
243+
timeout-minutes: 40
244244
run: |
245245
set -eo pipefail
246246
cd integration
247-
sudo npx jest --ci --reporters=default --reporters=jest-junit
247+
sudo PROFILE=release QUIET_SCENARIOS=true npx jest --ci --reporters=default --reporters=jest-junit
248248
249249
- name: Prepublish Integration results
250250
if: always()

base_types.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
"Keys": "SessionKeys",
66
"SignedPayload": "Vec<u8>",
77
"VersionedAuthorityList": {
8-
"authorityList": "AuthorityList",
9-
"version": "u8"
8+
"version": "u8",
9+
"authorityList": "AuthorityList"
1010
},
1111
"LookupSource": "MultiAddress",
1212
"SessionKeys": {

integration/__tests__/borrow_scen.js

+14-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
const {
2-
buildScenarios,
3-
sleep,
2+
buildScenarios
43
} = require('../util/scenario');
54
const { getNotice } = require('../util/substrate');
65

@@ -22,13 +21,15 @@ async function lockZRX({ ashley, bert, bat, zrx }) {
2221
buildScenarios('Borrow Scenarios', borrow_scen_info, { beforeEach: lockZRX }, [
2322
{
2423
name: "Borrow BAT and Garner Interest",
25-
scenario: async ({ ashley, bert, bat, zrx, chain, starport, log, cash }) => {
24+
notes: "This test allows arbitrary time passage, and thus has some estimation",
25+
scenario: async ({ ashley, bert, bat, zrx, chain, starport, log, cash, sleep }) => {
2626
let cashBalance0 = await ashley.chainBalance(cash);
2727
let cashIndex0 = await chain.cashIndex();
2828
let cash0 = await ashley.cash();
2929

3030
expect(cash0).toEqual(0);
3131

32+
// Ashley Borrows BAT
3233
let notice = getNotice(await ashley.extract(1_000_000, bat));
3334

3435
// Check totals
@@ -37,24 +38,32 @@ buildScenarios('Borrow Scenarios', borrow_scen_info, { beforeEach: lockZRX }, [
3738
expect(await bat.totalChainSupply()).toEqual(2_000_000);
3839
expect(await bat.totalChainBorrows()).toEqual(1_000_000);
3940

41+
// Pull BAT from the Starport
4042
let signatures = await chain.getNoticeSignatures(notice);
4143
await starport.invoke(notice, signatures);
44+
45+
// Check totals
4246
expect(await ashley.tokenBalance(bat)).toEqual(1_000_000);
4347
expect(await ashley.chainBalance(zrx)).toEqual(10_000_000);
4448
expect(await ashley.chainBalance(bat)).toEqual(-1_000_000);
49+
50+
// See that we've had _any_ cash interest accrued (assume it's less than a dime)
4551
let cashBalance1 = await ashley.chainBalance(cash);
4652
let cashIndex1 = await chain.cashIndex();
4753
let cash1 = await ashley.cash();
4854
expect(cash1).toBeLessThan(0);
49-
expect(cash1).toBeGreaterThan(-0.001);
55+
expect(cash1).toBeGreaterThan(-0.10);
56+
5057
await sleep(20000);
58+
59+
// See that we've had _more_ cash interest accrued (assume it's less than a quarter)
5160
let cashBalance2 = await ashley.chainBalance(cash);
5261
let cashIndex2 = await chain.cashIndex();
5362
let cash2 = await ashley.cash();
5463

5564
// Nothing is exact here.
5665
expect(cash2).toBeLessThan(cash1);
57-
expect(cash2).toBeGreaterThan(-0.01);
66+
expect(cash2).toBeGreaterThan(-0.25);
5867
}
5968
}
6069
]);

integration/__tests__/cash_scen.js

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
const { buildScenarios } = require('../util/scenario');
2+
3+
let now = Date.now();
4+
5+
let cash_scen_info = {
6+
tokens: [
7+
{ token: 'usdc', balances: { ashley: 1000 } },
8+
{ token: 'zrx', balances: { bert: 1000000 } },
9+
{ token: 'comp' }
10+
],
11+
validators: ['alice', 'bob'],
12+
freeze_time: now,
13+
initial_yield: 300,
14+
initial_yield_start_ms: now
15+
};
16+
17+
buildScenarios('Cash Scenarios', cash_scen_info, [
18+
{
19+
name: 'Cash Interest',
20+
scenario: async ({ ashley, bert, cash, chain, usdc }) => {
21+
await ashley.lock(1000, usdc);
22+
await ashley.transfer(10, cash, bert);
23+
expect(await ashley.chainBalance(usdc)).toEqual(1000);
24+
expect(await ashley.chainBalance(cash)).toEqual(-10.01); // $10 + 1¢ transfer fee
25+
expect(await bert.chainBalance(cash)).toEqual(10);
26+
await chain.accelerateTime({years: 1});
27+
expect(await ashley.chainBalance(usdc)).toEqual(1000);
28+
expect(await ashley.chainBalance(cash)).toBeCloseTo(-10.314849, 4); // $10.01 @ 3% for 1 Year Continously Compounding
29+
expect(await bert.chainBalance(cash)).toBeCloseTo(10.304545, 4); // // $10 @ 3% for 1 Year Continously Compounding
30+
}
31+
},
32+
{
33+
name: 'Collateral Borrowed Interest Lump Sum',
34+
scenario: async ({ ashley, bert, chuck, cash, chain, usdc, zrx }) => {
35+
await chain.setFixedRate(usdc, 500); // 5% APY fixed
36+
await bert.lock(1000000, zrx);
37+
await bert.transfer(1000, usdc, chuck);
38+
expect(await bert.chainBalance(usdc)).toEqual(-1000);
39+
expect(await chuck.chainBalance(usdc)).toEqual(1000);
40+
expect(await bert.chainBalance(cash)).toEqual(-0.01); // 1¢ transfer fee
41+
expect(await chuck.chainBalance(cash)).toEqual(0);
42+
await chain.accelerateTime({years: 1});
43+
expect(await bert.chainBalance(usdc)).toEqual(-1000);
44+
expect(await chuck.chainBalance(usdc)).toEqual(1000);
45+
expect(await bert.chainBalance(cash)).toBeCloseTo(-51.53272669767585, 3); // -50 * Math.exp(0.03) - 0.01
46+
expect(await chuck.chainBalance(cash)).toBeCloseTo(51.52272669767585, 3); // 50 * Math.exp(0.03)
47+
}
48+
},
49+
{
50+
name: 'Collateral Borrowed Interest 12-Month Chunked',
51+
scenario: async ({ ashley, bert, chuck, cash, chain, usdc, zrx }) => {
52+
await chain.setFixedRate(usdc, 500); // 5% APY fixed
53+
await bert.lock(1000000, zrx);
54+
await bert.transfer(1000, usdc, chuck);
55+
expect(await bert.chainBalance(usdc)).toEqual(-1000);
56+
expect(await chuck.chainBalance(usdc)).toEqual(1000);
57+
expect(await bert.chainBalance(cash)).toEqual(-0.01); // 1¢ transfer fee
58+
expect(await chuck.chainBalance(cash)).toEqual(0);
59+
for (const i in [...new Array(12)]) {
60+
await chain.accelerateTime({months: 1});
61+
}
62+
expect(await bert.chainBalance(usdc)).toEqual(-1000);
63+
expect(await chuck.chainBalance(usdc)).toEqual(1000);
64+
expect(await bert.chainBalance(cash)).toBeCloseTo(-50.79, 1); // ~ -50*(1+0.015) - 0.01
65+
expect(await chuck.chainBalance(cash)).toBeCloseTo(50.78, 1); // ~ -50*(1+0.015)
66+
}
67+
},
68+
{
69+
name: 'Multi-Collateral and Cash Netting',
70+
scenario: async ({ ashley, bert, chuck, cash, chain, comp, usdc, zrx }) => {
71+
await chain.setFixedRate(usdc, 500); // 5% APY fixed
72+
await chain.setFixedRate(comp, 1000); // 10% APY fixed
73+
await bert.lock(1000000, zrx);
74+
await bert.transfer(300.01, cash, chuck);
75+
await bert.transfer(1000, usdc, chuck);
76+
await chuck.transfer(1, comp, bert);
77+
// Chuck has +1000 USDC @ 5% [Price=$1] [Util=100%]
78+
// Chuck has -1 COMP @ 10% [Price=$229.125] [Util=100%]
79+
// Chuck has 300 Cash @ 3% APY
80+
expect(await chuck.chainBalance(usdc)).toEqual(1000);
81+
expect(await chuck.chainBalance(comp)).toEqual(-1);
82+
expect(await chuck.chainBalance(cash)).toEqual(300);
83+
await chain.accelerateTime({years: 1});
84+
expect(await chuck.chainBalance(usdc)).toEqual(1000);
85+
expect(await chuck.chainBalance(comp)).toEqual(-1);
86+
/*
87+
{ Cash } { USDC Interest } { Comp Interest } { Cash APY }
88+
89+
( 300 + 1000 * 1 * 0.05 - 1 * 229.125 * 0.1 ) * Math.exp(0.03)
90+
*/
91+
expect(await chuck.chainBalance(cash)).toBeCloseTo(337.048797374521, 3);
92+
}
93+
}
94+
]);

integration/__tests__/extract_scen.js

+12-6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ const {
33
} = require('../util/scenario');
44
const { getNotice } = require('../util/substrate');
55

6+
let now = Date.now();
7+
68
let extract_scen_info = {
79
tokens: [
810
{ token: "zrx", balances: { ashley: 1000 } },
@@ -43,7 +45,6 @@ buildScenarios('Extract Scenarios', extract_scen_info, { beforeEach: lockUSDC },
4345
}
4446
},
4547
{
46-
only: true,
4748
name: "Extract Cash",
4849
scenario: async ({ ashley, zrx, chain, starport, cash, log }) => {
4950
let notice = getNotice(await ashley.extract(20, cash));
@@ -72,23 +73,28 @@ buildScenarios('Extract Scenarios', extract_scen_info, { beforeEach: lockUSDC },
7273
{
7374
name: "Extract Comp Torrey",
7475
beforeEach: null,
76+
info: {
77+
freeze_time: now,
78+
},
7579
scenario: async ({ ashley, bert, usdc, comp, chain, starport, cash, log }) => {
76-
// User A Supplied 100k USDC
80+
// Alice supplies 100K USDC
7781
await ashley.lock(100_000, usdc);
78-
// User B Supplied 200 COMP
82+
// Bert supplies 200 COMP
7983
await bert.lock(200, comp);
80-
// User A downloaded 50 COMP
84+
// Alice extracts 50 COMP
8185
let notice = getNotice(await ashley.extract(50, comp));
8286
let signatures = await chain.getNoticeSignatures(notice);
8387

88+
await chain.accelerateTime({days: 1});
89+
8490
expect(await ashley.tokenBalance(comp)).toEqual(0);
8591
let tx = await starport.invoke(notice, signatures);
8692
let ashleyComp = await ashley.tokenBalance(comp);
8793
let ashleyCash = await ashley.cash();
8894
let ashleyLiquidity = await ashley.liquidity();
8995
expect(ashleyComp).toEqual(50);
90-
expect(ashleyCash).toBeCloseTo(-0.0003809713723277, 4);
91-
expect(ashleyLiquidity).toBeCloseTo(64724.99962, 2);
96+
expect(ashleyCash).toBeCloseTo(-2.743447, 4);
97+
expect(ashleyLiquidity).toBeCloseTo(64700, -3);
9298
}
9399
},
94100
{

0 commit comments

Comments
 (0)