Skip to content
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

add a stress test #14

Merged
merged 1 commit into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
**/target
**/tests/tmp
**/tests/mainnet
/.vim
/test-data
36 changes: 33 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,45 @@ Note: after checking out to another commit, remember to run:
git submodule update
```

Then, from the project root, run the tests by running:
### Integration tests

To run the integration tests, from the project root, execute:
```sh
cargo test
cargo test --test issuance --test transfers
```

:warning: **Warning:** if your machine has a lot of CPU cores, it could
happen that calls to indexers fail because of too many parallel requests. To
limit the test threads and avoid this issue set the `--test-threads` option
(e.g. `cargo test -- --test-threads=8`).
(e.g. `cargo test --test issuance --test transfers -- --test-threads=8`).

### Validation tests

To run consignment validation tests, from the project root, execute:

```sh
cargo test --test validation
```

### Stress tests

To run a single stress test, set the `LOOPS` variable to the requested number
of loops and then, from the project root, for example execute:
```sh
LOOPS=20 cargo test --test stress back_and_forth::case_1 -- --ignored
```

This will produce a CSV report file that can be opened in a spreadsheet program
manually or by running:
```sh
open test-data/stress/<timestamp>.csv
```

Stress tests have been parametrized the same way some integration tests are.
To select which test case you want to run, find the case attribute you want to
use (e.g. `#[case(TT::Witness, DT::Wpkh, DT::Tr)]`) and if, as an example, it's
the 4th one, run `<test_name>::case_4`. Note that case numbers are zero-padded
so if for example there are 20 test cases, case 4 would be called `case_04`.

### Test services

Expand Down
4 changes: 2 additions & 2 deletions tests/start_services.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fi
COMPOSE_BASE="$COMPOSE_BASE -f tests/docker-compose.yml"
PROFILE=${PROFILE:-"esplora"}
COMPOSE="$COMPOSE_BASE --profile $PROFILE"
TEST_DIR="./tests/tmp"
TEST_DATA_DIR="./test-data"

# see docker-compose.yml for the exposed ports
if [ "$PROFILE" == "esplora" ]; then
Expand All @@ -29,7 +29,7 @@ fi

# restart services (down + up) checking for ports availability
$COMPOSE_BASE --profile '*' down -v --remove-orphans
mkdir -p $TEST_DIR
mkdir -p $TEST_DATA_DIR
for port in "${EXPOSED_PORTS[@]}"; do
if [ -n "$(ss -HOlnt "sport = :$port")" ];then
_die "port $port is already bound, services can't be started"
Expand Down
92 changes: 92 additions & 0 deletions tests/stress.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
pub mod utils;

use utils::*;

type TT = TransferType;
type DT = DescriptorType;

#[rstest]
// blinded
#[case(TT::Blinded, DT::Wpkh, DT::Wpkh)]
#[case(TT::Blinded, DT::Wpkh, DT::Tr)]
#[case(TT::Blinded, DT::Tr, DT::Tr)]
// witness
#[case(TT::Witness, DT::Wpkh, DT::Wpkh)]
#[case(TT::Witness, DT::Wpkh, DT::Tr)]
#[case(TT::Witness, DT::Tr, DT::Tr)]
#[ignore = "run a single case if desired"]
fn back_and_forth(
#[case] transfer_type: TransferType,
#[case] wlt_1_desc: DescriptorType,
#[case] wlt_2_desc: DescriptorType,
) {
println!("transfer_type {transfer_type:?} wlt_1_desc {wlt_1_desc:?} wlt_2_desc {wlt_2_desc:?}");

initialize();

let stress_tests_dir = PathBuf::from(TEST_DATA_DIR).join(STRESS_DATA_DIR);
std::fs::create_dir_all(&stress_tests_dir).unwrap();
let fname = OffsetDateTime::unix_timestamp(OffsetDateTime::now_utc()).to_string();
let mut fpath = stress_tests_dir.join(fname);
fpath.set_extension("csv");
println!("report path: {}", fpath.to_string_lossy());
let report = Report { report_path: fpath };
report.write_header(&[
"wlt_1_pay",
"wlt_2_validate",
"wlt_2_accept",
"wlt_2_pay",
"wlt_1_validate",
"wlt_1_accept",
"send_1_tot",
"send_2_tot",
]);

let mut wlt_1 = get_wallet(&wlt_1_desc);
let mut wlt_2 = get_wallet(&wlt_2_desc);

let issued_supply = u64::MAX;

let (contract_id, iface_type_name) = wlt_1.issue_nia(issued_supply, wlt_1.close_method(), None);

let loops = match std::env::var("LOOPS") {
Ok(val) if u16::from_str(&val).is_ok() => u16::from_str(&val).unwrap(),
Err(VarError::NotPresent) => 50,
_ => {
panic!("invalid loops value: must be a u16 number")
}
};

let now = Instant::now();
for i in 1..=loops {
println!("loop {i}/{loops}");
let wlt_1_send_start = Instant::now();
wlt_1.send(
&mut wlt_2,
transfer_type,
contract_id,
&iface_type_name,
issued_supply - i as u64,
1000,
Some(&report),
);
let wlt_1_send_duration = wlt_1_send_start.elapsed();
let wlt_2_send_start = Instant::now();
wlt_2.send(
&mut wlt_1,
transfer_type,
contract_id,
&iface_type_name,
issued_supply - i as u64 - 1,
1000,
Some(&report),
);
let wlt_2_send_duration = wlt_2_send_start.elapsed();

report.write_duration(wlt_1_send_duration);
report.write_duration(wlt_2_send_duration);
report.end_line();
}
let elapsed = now.elapsed();
println!("elapsed: {:.2?}", elapsed);
}
22 changes: 16 additions & 6 deletions tests/transfers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ fn transfer_loop(
&iface_type_name_1,
amount_1,
sats,
None,
);
wlt_1.check_allocations(
contract_id_1,
Expand Down Expand Up @@ -192,6 +193,7 @@ fn transfer_loop(
&iface_type_name_1,
amount_2,
sats,
None,
);
wlt_1.check_allocations(
contract_id_1,
Expand Down Expand Up @@ -229,6 +231,7 @@ fn transfer_loop(
&iface_type_name_2,
amount_3,
sats,
None,
);
wlt_1.check_allocations(
contract_id_1,
Expand Down Expand Up @@ -273,6 +276,7 @@ fn transfer_loop(
&iface_type_name_1,
amount_4,
sats,
None,
);
wlt_1.check_allocations(
contract_id_1,
Expand Down Expand Up @@ -317,6 +321,7 @@ fn transfer_loop(
&iface_type_name_2,
amount_5,
sats,
None,
);
wlt_1.check_allocations(
contract_id_1,
Expand Down Expand Up @@ -361,6 +366,7 @@ fn transfer_loop(
&iface_type_name_1,
amount_6,
sats,
None,
);
wlt_1.check_allocations(
contract_id_1,
Expand Down Expand Up @@ -405,6 +411,7 @@ fn transfer_loop(
&iface_type_name_2,
amount_7,
sats,
None,
);
wlt_1.check_allocations(
contract_id_1,
Expand Down Expand Up @@ -457,13 +464,13 @@ fn same_transfer_twice() {
wlt_2.close_method(),
InvoiceType::Witness,
);
let _ = wlt_1.transfer(invoice.clone(), None, Some(500));
let _ = wlt_1.transfer(invoice.clone(), None, Some(500), None);

// retry with higher fees, TX hasn't been mined
let mid_height = get_height();
assert_eq!(initial_height, mid_height);

let _ = wlt_1.transfer(invoice, None, Some(1000));
let _ = wlt_1.transfer(invoice, None, Some(1000), None);

let final_height = get_height();
assert_eq!(initial_height, final_height);
Expand All @@ -488,9 +495,9 @@ fn accept_0conf() {
wlt_2.close_method(),
InvoiceType::Witness,
);
let (consignment, _) = wlt_1.transfer(invoice.clone(), None, None);
let (consignment, _) = wlt_1.transfer(invoice.clone(), None, None, None);

wlt_2.accept_transfer(consignment.clone());
wlt_2.accept_transfer(consignment.clone(), None);

// TODO: check if it's correct that sender sees 2 allocations
/*
Expand Down Expand Up @@ -692,6 +699,7 @@ fn ln_transfers() {
&iface_type_name,
500,
1000,
None,
);
}

Expand All @@ -714,7 +722,7 @@ fn mainnet_wlt_receiving_test_asset() {
wlt_2.close_method(),
InvoiceType::Blinded(Some(utxo)),
);
let (consignment, tx) = wlt_1.transfer(invoice.clone(), None, Some(500));
let (consignment, tx) = wlt_1.transfer(invoice.clone(), None, Some(500), None);
wlt_1.mine_tx(&tx.txid(), false);
match consignment.validate(&wlt_2.get_resolver(), wlt_2.testnet()) {
Err((status, _invalid_consignment)) => {
Expand Down Expand Up @@ -745,6 +753,7 @@ fn tapret_wlt_receiving_opret() {
&iface_type_name,
400,
5000,
None,
);

println!("2nd transfer");
Expand All @@ -755,7 +764,7 @@ fn tapret_wlt_receiving_opret() {
CloseMethod::OpretFirst,
InvoiceType::Witness,
);
wlt_2.send_to_invoice(&mut wlt_1, invoice, None, None);
wlt_2.send_to_invoice(&mut wlt_1, invoice, None, None, None);

println!("3rd transfer");
wlt_1.send(
Expand All @@ -765,5 +774,6 @@ fn tapret_wlt_receiving_opret() {
&iface_type_name,
300,
1000,
None,
);
}
8 changes: 4 additions & 4 deletions tests/utils/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ pub fn mine(resume: bool) {
if mined {
break;
}
std::thread::sleep(std::time::Duration::from_millis(500));
std::thread::sleep(Duration::from_millis(500));
}
}

Expand All @@ -141,7 +141,7 @@ pub fn mine_but_no_resume() {
break;
}
drop(miner);
std::thread::sleep(std::time::Duration::from_millis(500));
std::thread::sleep(Duration::from_millis(500));
}
}

Expand All @@ -162,7 +162,7 @@ pub fn stop_mining_when_alone() {
break;
}
drop(miner);
std::thread::sleep(std::time::Duration::from_millis(500));
std::thread::sleep(Duration::from_millis(500));
}
}

Expand Down Expand Up @@ -195,7 +195,7 @@ fn _wait_indexer_sync() {
let t_0 = OffsetDateTime::now_utc();
let blockcount = get_height();
loop {
std::thread::sleep(std::time::Duration::from_millis(100));
std::thread::sleep(Duration::from_millis(100));
match INDEXER.get().unwrap() {
Indexer::Electrum => {
let electrum_client =
Expand Down
Loading