Skip to content

Commit

Permalink
abitest: ensure futures and client dropped first
Browse files Browse the repository at this point in the history
Ensure that the results of any futures are dropped, and that
the gRPC client is dropped, before calling runtime.stop().

This allows the removal of the ThreadSanitizer suppression file.
  • Loading branch information
daviddrysdale committed Jun 25, 2020
1 parent c6544e2 commit 2156b32
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 94 deletions.
1 change: 0 additions & 1 deletion .tsan_suppress

This file was deleted.

188 changes: 96 additions & 92 deletions examples/abitest/module_0/rust/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,123 +75,127 @@ async fn setup() -> (
#[serial]
async fn test_abi() {
let (runtime, mut client) = setup().await;
{
// Skip tests that require the existence of an external service.
let mut req = AbiTestRequest::default();
req.exclude = "(Storage|GrpcClient|Roughtime)".to_string();

// Skip tests that require the existence of an external service.
let mut req = AbiTestRequest::default();
req.exclude = "(Storage|GrpcClient|Roughtime)".to_string();
info!("Sending request: {:?}", req);
let result = client.run_tests(req).await;
assert_matches!(result, Ok(_));

info!("Sending request: {:?}", req);
let result = client.run_tests(req).await;
assert_matches!(result, Ok(_));
info!("Runtime graph at exit is:\n{}", runtime.graph());

info!("Runtime graph at exit is:\n{}", runtime.graph());

runtime.stop();

let mut disabled = 0;
let mut success = true;
let results = result.unwrap().into_inner().results;
for result in results {
if result.disabled {
disabled += 1;
continue;
let mut disabled = 0;
let mut success = true;
let results = result.unwrap().into_inner().results;
for result in results {
if result.disabled {
disabled += 1;
continue;
}
info!(
"[ {} ] {}",
if result.success { " OK " } else { "FAIL" },
result.name
);
if !result.success {
error!("Failure details: {}", result.details);
success = false;
}
}
info!(
"[ {} ] {}",
if result.success { " OK " } else { "FAIL" },
result.name
);
if !result.success {
error!("Failure details: {}", result.details);
success = false;
if disabled > 0 {
info!("YOU HAVE {} DISABLED TESTS", disabled);
}
}
if disabled > 0 {
info!("YOU HAVE {} DISABLED TESTS", disabled);
}
assert_eq!(true, success);
assert_eq!(true, success);
} // ensure futures are all dropped
drop(client);
runtime.stop();
}

#[tokio::test(core_threads = 2)]
#[serial]
async fn test_leaks() {
let (runtime, mut client) = setup().await;

let (before_nodes, before_channels) = runtime.object_counts();
info!(
"Counts before test: Nodes={}, Channels={}",
before_nodes, before_channels
);
{
let (before_nodes, before_channels) = runtime.object_counts();
info!(
"Counts before test: Nodes={}, Channels={}",
before_nodes, before_channels
);

// Run tests that are supposed to leave Node/channel counts in a known state.
let mut req = AbiTestRequest::default();
req.predictable_counts = true;
// Run tests that are supposed to leave Node/channel counts in a known state.
let mut req = AbiTestRequest::default();
req.predictable_counts = true;

debug!("Sending request: {:?}", req);
let result = client.run_tests(req).await;
assert_matches!(result, Ok(_));
let results = result.unwrap().into_inner().results;
debug!("Sending request: {:?}", req);
let result = client.run_tests(req).await;
assert_matches!(result, Ok(_));
let results = result.unwrap().into_inner().results;

let (after_nodes, after_channels) = runtime.object_counts();
info!(
"Counts change from test: Nodes={} => {}, Channels={} => {}",
before_nodes, after_nodes, before_channels, after_channels
);
let (after_nodes, after_channels) = runtime.object_counts();
info!(
"Counts change from test: Nodes={} => {}, Channels={} => {}",
before_nodes, after_nodes, before_channels, after_channels
);

// Calculate the expected change in Node and channel counts for
// these tests.
let mut want_nodes = before_nodes;
let mut want_channels = before_channels;
for result in &results {
assert_eq!(result.predictable_counts, true);
if result.disabled {
continue;
}
want_nodes += result.node_change;
want_channels += result.channel_change;
}

if after_nodes != want_nodes || after_channels != want_channels {
// One of the batch of tests has triggered an unexpected object count.
// Repeat the tests one by one to find out which.
let mut details = Vec::new();
for result in results {
// Calculate the expected change in Node and channel counts for
// these tests.
let mut want_nodes = before_nodes;
let mut want_channels = before_channels;
for result in &results {
assert_eq!(result.predictable_counts, true);
if result.disabled {
continue;
}
want_nodes += result.node_change;
want_channels += result.channel_change;
}

let (before_nodes, before_channels) = runtime.object_counts();
let (want_nodes, want_channels) = (
before_nodes + result.node_change,
before_channels + result.channel_change,
);

let mut req = AbiTestRequest::default();
req.include = format!("^{}$", result.name);
debug!("Sending request: {:?}", req);
let this_result = client.run_tests(req).await;
assert_matches!(this_result, Ok(_));
let (after_nodes, after_channels) = runtime.object_counts();

if after_nodes != want_nodes || after_channels != want_channels {
details.push(format!(
if after_nodes != want_nodes || after_channels != want_channels {
// One of the batch of tests has triggered an unexpected object count.
// Repeat the tests one by one to find out which.
let mut details = Vec::new();
for result in results {
if result.disabled {
continue;
}

let (before_nodes, before_channels) = runtime.object_counts();
let (want_nodes, want_channels) = (
before_nodes + result.node_change,
before_channels + result.channel_change,
);

let mut req = AbiTestRequest::default();
req.include = format!("^{}$", result.name);
debug!("Sending request: {:?}", req);
let this_result = client.run_tests(req).await;
assert_matches!(this_result, Ok(_));
let (after_nodes, after_channels) = runtime.object_counts();

if after_nodes != want_nodes || after_channels != want_channels {
details.push(format!(
"[ LEAK ] {} (got {}=>{} nodes, {}=>{} channels, want {}=>{} nodes, {}=>{} channels)",
result.name, before_nodes, after_nodes, before_channels, after_channels,
before_nodes, want_nodes, before_channels, want_channels,
));
} else {
details.push(format!(
"[ OK ] {} ({}=>{} nodes, {}=>{} channels, as expected)",
result.name, before_nodes, after_nodes, before_channels, after_channels,
));
} else {
details.push(format!(
"[ OK ] {} ({}=>{} nodes, {}=>{} channels, as expected)",
result.name, before_nodes, after_nodes, before_channels, after_channels,
));
}
panic!("Leak of Nodes or channels found");
}
for detail in details {
info!("{}", detail);
}
assert_eq!(want_nodes, after_nodes);
assert_eq!(want_channels, after_channels);
}
for detail in details {
info!("{}", detail);
}
assert_eq!(want_nodes, after_nodes);
assert_eq!(want_channels, after_channels);
}

} // ensure futures are all dropped
drop(client);
runtime.stop();
}
2 changes: 1 addition & 1 deletion scripts/run_tests_tsan
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ source "$SCRIPTS_DIR/common"

export RUST_BACKTRACE=1
export RUSTFLAGS="-Z sanitizer=thread"
export TSAN_OPTIONS="halt_on_error=1 report_atomic_races=0 suppressions=$PWD/.tsan_suppress"
export TSAN_OPTIONS="halt_on_error=1 report_atomic_races=0"

# Just run the abitest example for the moment.
time cargo -Zbuild-std test --manifest-path=./examples/abitest/module_0/rust/Cargo.toml --target=x86_64-unknown-linux-gnu --verbose -- --nocapture
Expand Down

0 comments on commit 2156b32

Please sign in to comment.