Migrate VC tests to tokio::test

This commit is contained in:
Paul Hauner
2022-08-21 18:01:21 +10:00
parent 2677443586
commit 391ece953f
3 changed files with 487 additions and 515 deletions

View File

@@ -25,9 +25,8 @@ use std::marker::PhantomData;
use std::net::{IpAddr, Ipv4Addr}; use std::net::{IpAddr, Ipv4Addr};
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use task_executor::TaskExecutor; use task_executor::test_utils::TestRuntime;
use tempfile::{tempdir, TempDir}; use tempfile::{tempdir, TempDir};
use tokio::runtime::Runtime;
use tokio::sync::oneshot; use tokio::sync::oneshot;
pub const PASSWORD_BYTES: &[u8] = &[42, 50, 37]; pub const PASSWORD_BYTES: &[u8] = &[42, 50, 37];
@@ -57,23 +56,13 @@ pub struct ApiTester {
pub initialized_validators: Arc<RwLock<InitializedValidators>>, pub initialized_validators: Arc<RwLock<InitializedValidators>>,
pub validator_store: Arc<ValidatorStore<TestingSlotClock, E>>, pub validator_store: Arc<ValidatorStore<TestingSlotClock, E>>,
pub url: SensitiveUrl, pub url: SensitiveUrl,
pub test_runtime: TestRuntime,
pub _server_shutdown: oneshot::Sender<()>, pub _server_shutdown: oneshot::Sender<()>,
pub _validator_dir: TempDir, pub _validator_dir: TempDir,
pub _runtime_shutdown: exit_future::Signal,
}
// Builds a runtime to be used in the testing configuration.
pub fn build_runtime() -> Arc<Runtime> {
Arc::new(
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.expect("Should be able to build a testing runtime"),
)
} }
impl ApiTester { impl ApiTester {
pub async fn new(runtime: std::sync::Weak<Runtime>) -> Self { pub async fn new() -> Self {
let log = test_logger(); let log = test_logger();
let validator_dir = tempdir().unwrap(); let validator_dir = tempdir().unwrap();
@@ -105,9 +94,7 @@ impl ApiTester {
let slot_clock = let slot_clock =
TestingSlotClock::new(Slot::new(0), Duration::from_secs(0), Duration::from_secs(1)); TestingSlotClock::new(Slot::new(0), Duration::from_secs(0), Duration::from_secs(1));
let (runtime_shutdown, exit) = exit_future::signal(); let test_runtime = TestRuntime::default();
let (shutdown_tx, _) = futures::channel::mpsc::channel(1);
let executor = TaskExecutor::new(runtime.clone(), exit, log.clone(), shutdown_tx);
let validator_store = Arc::new(ValidatorStore::<_, E>::new( let validator_store = Arc::new(ValidatorStore::<_, E>::new(
initialized_validators, initialized_validators,
@@ -117,7 +104,7 @@ impl ApiTester {
Some(Arc::new(DoppelgangerService::new(log.clone()))), Some(Arc::new(DoppelgangerService::new(log.clone()))),
slot_clock, slot_clock,
&config, &config,
executor.clone(), test_runtime.task_executor.clone(),
log.clone(), log.clone(),
)); ));
@@ -128,7 +115,7 @@ impl ApiTester {
let initialized_validators = validator_store.initialized_validators(); let initialized_validators = validator_store.initialized_validators();
let context = Arc::new(Context { let context = Arc::new(Context {
task_executor: executor, task_executor: test_runtime.task_executor.clone(),
api_secret, api_secret,
validator_dir: Some(validator_dir.path().into()), validator_dir: Some(validator_dir.path().into()),
validator_store: Some(validator_store.clone()), validator_store: Some(validator_store.clone()),
@@ -166,9 +153,9 @@ impl ApiTester {
initialized_validators, initialized_validators,
validator_store, validator_store,
url, url,
test_runtime,
_server_shutdown: shutdown_tx, _server_shutdown: shutdown_tx,
_validator_dir: validator_dir, _validator_dir: validator_dir,
_runtime_shutdown: runtime_shutdown,
} }
} }

View File

@@ -1,337 +1,298 @@
#![cfg(test)] #![cfg(test)]
#![cfg(not(debug_assertions))] // #![cfg(not(debug_assertions))]
mod keystores; mod keystores;
use crate::http_api::test_utils::{ use crate::http_api::test_utils::{
build_runtime, ApiTester, HdValidatorScenario, KeystoreValidatorScenario, ApiTester, HdValidatorScenario, KeystoreValidatorScenario, Web3SignerValidatorScenario,
Web3SignerValidatorScenario, TEST_DEFAULT_FEE_RECIPIENT, TEST_DEFAULT_FEE_RECIPIENT,
}; };
use account_utils::{random_password, random_password_string, ZeroizeString}; use account_utils::{random_password, random_password_string, ZeroizeString};
use eth2::lighthouse_vc::types::*; use eth2::lighthouse_vc::types::*;
use eth2_keystore::KeystoreBuilder; use eth2_keystore::KeystoreBuilder;
use std::future::Future; use std::future::Future;
use std::sync::Arc;
type E = MainnetEthSpec; type E = MainnetEthSpec;
#[test] #[tokio::test]
fn invalid_pubkey() { async fn invalid_pubkey() {
let runtime = build_runtime(); ApiTester::new()
let weak_runtime = Arc::downgrade(&runtime); .await
runtime.block_on(async { .invalidate_api_token()
ApiTester::new(weak_runtime) .test_get_lighthouse_version_invalid()
.await .await;
.invalidate_api_token()
.test_get_lighthouse_version_invalid()
.await;
});
} }
#[test] #[tokio::test]
fn routes_with_invalid_auth() { async fn routes_with_invalid_auth() {
let runtime = build_runtime(); ApiTester::new()
let weak_runtime = Arc::downgrade(&runtime); .await
runtime.block_on(async { .test_with_invalid_auth(|client| async move { client.get_lighthouse_version().await })
ApiTester::new(weak_runtime) .await
.await .test_with_invalid_auth(|client| async move { client.get_lighthouse_health().await })
.test_with_invalid_auth(|client| async move { client.get_lighthouse_version().await }) .await
.await .test_with_invalid_auth(|client| async move {
.test_with_invalid_auth(|client| async move { client.get_lighthouse_health().await }) client.get_lighthouse_spec::<types::Config>().await
.await })
.test_with_invalid_auth(|client| async move { .await
client.get_lighthouse_spec::<types::Config>().await .test_with_invalid_auth(|client| async move { client.get_lighthouse_validators().await })
}) .await
.await .test_with_invalid_auth(|client| async move {
.test_with_invalid_auth( client
|client| async move { client.get_lighthouse_validators().await }, .get_lighthouse_validators_pubkey(&PublicKeyBytes::empty())
) .await
.await })
.test_with_invalid_auth(|client| async move { .await
client .test_with_invalid_auth(|client| async move {
.get_lighthouse_validators_pubkey(&PublicKeyBytes::empty()) client
.await .post_lighthouse_validators(vec![ValidatorRequest {
}) enable: <_>::default(),
.await description: <_>::default(),
.test_with_invalid_auth(|client| async move { graffiti: <_>::default(),
client suggested_fee_recipient: <_>::default(),
.post_lighthouse_validators(vec![ValidatorRequest { gas_limit: <_>::default(),
enable: <_>::default(), builder_proposals: <_>::default(),
description: <_>::default(), deposit_gwei: <_>::default(),
graffiti: <_>::default(), }])
suggested_fee_recipient: <_>::default(), .await
gas_limit: <_>::default(), })
builder_proposals: <_>::default(), .await
deposit_gwei: <_>::default(), .test_with_invalid_auth(|client| async move {
}]) client
.await .post_lighthouse_validators_mnemonic(&CreateValidatorsMnemonicRequest {
}) mnemonic: String::default().into(),
.await key_derivation_path_offset: <_>::default(),
.test_with_invalid_auth(|client| async move { validators: <_>::default(),
client })
.post_lighthouse_validators_mnemonic(&CreateValidatorsMnemonicRequest { .await
mnemonic: String::default().into(), })
key_derivation_path_offset: <_>::default(), .await
validators: <_>::default(), .test_with_invalid_auth(|client| async move {
}) let password = random_password();
.await let keypair = Keypair::random();
}) let keystore = KeystoreBuilder::new(&keypair, password.as_bytes(), String::new())
.await .unwrap()
.test_with_invalid_auth(|client| async move { .build()
let password = random_password(); .unwrap();
let keypair = Keypair::random(); client
let keystore = KeystoreBuilder::new(&keypair, password.as_bytes(), String::new()) .post_lighthouse_validators_keystore(&KeystoreValidatorsPostRequest {
.unwrap() password: String::default().into(),
.build() enable: <_>::default(),
.unwrap(); keystore,
client graffiti: <_>::default(),
.post_lighthouse_validators_keystore(&KeystoreValidatorsPostRequest { suggested_fee_recipient: <_>::default(),
password: String::default().into(), gas_limit: <_>::default(),
enable: <_>::default(), builder_proposals: <_>::default(),
keystore, })
graffiti: <_>::default(), .await
suggested_fee_recipient: <_>::default(), })
gas_limit: <_>::default(), .await
builder_proposals: <_>::default(), .test_with_invalid_auth(|client| async move {
}) client
.await .patch_lighthouse_validators(&PublicKeyBytes::empty(), Some(false), None, None)
}) .await
.await })
.test_with_invalid_auth(|client| async move { .await
client .test_with_invalid_auth(|client| async move { client.get_keystores().await })
.patch_lighthouse_validators(&PublicKeyBytes::empty(), Some(false), None, None) .await
.await .test_with_invalid_auth(|client| async move {
}) let password = random_password_string();
.await let keypair = Keypair::random();
.test_with_invalid_auth(|client| async move { client.get_keystores().await }) let keystore = KeystoreBuilder::new(&keypair, password.as_ref(), String::new())
.await .unwrap()
.test_with_invalid_auth(|client| async move { .build()
let password = random_password_string(); .map(KeystoreJsonStr)
let keypair = Keypair::random(); .unwrap();
let keystore = KeystoreBuilder::new(&keypair, password.as_ref(), String::new()) client
.unwrap() .post_keystores(&ImportKeystoresRequest {
.build() keystores: vec![keystore],
.map(KeystoreJsonStr) passwords: vec![password],
.unwrap(); slashing_protection: None,
client })
.post_keystores(&ImportKeystoresRequest { .await
keystores: vec![keystore], })
passwords: vec![password], .await
slashing_protection: None, .test_with_invalid_auth(|client| async move {
}) let keypair = Keypair::random();
.await client
}) .delete_keystores(&DeleteKeystoresRequest {
.await pubkeys: vec![keypair.pk.compress()],
.test_with_invalid_auth(|client| async move { })
let keypair = Keypair::random(); .await
client })
.delete_keystores(&DeleteKeystoresRequest { .await;
pubkeys: vec![keypair.pk.compress()],
})
.await
})
.await
});
} }
#[test] #[tokio::test]
fn simple_getters() { async fn simple_getters() {
let runtime = build_runtime(); ApiTester::new()
let weak_runtime = Arc::downgrade(&runtime); .await
runtime.block_on(async { .test_get_lighthouse_version()
ApiTester::new(weak_runtime) .await
.await .test_get_lighthouse_health()
.test_get_lighthouse_version() .await
.await .test_get_lighthouse_spec()
.test_get_lighthouse_health() .await;
.await
.test_get_lighthouse_spec()
.await;
});
} }
#[test] #[tokio::test]
fn hd_validator_creation() { async fn hd_validator_creation() {
let runtime = build_runtime(); ApiTester::new()
let weak_runtime = Arc::downgrade(&runtime); .await
runtime.block_on(async { .assert_enabled_validators_count(0)
ApiTester::new(weak_runtime) .assert_validators_count(0)
.await .create_hd_validators(HdValidatorScenario {
.assert_enabled_validators_count(0) count: 2,
.assert_validators_count(0) specify_mnemonic: true,
.create_hd_validators(HdValidatorScenario { key_derivation_path_offset: 0,
count: 2, disabled: vec![],
specify_mnemonic: true, })
key_derivation_path_offset: 0, .await
disabled: vec![], .assert_enabled_validators_count(2)
}) .assert_validators_count(2)
.await .create_hd_validators(HdValidatorScenario {
.assert_enabled_validators_count(2) count: 1,
.assert_validators_count(2) specify_mnemonic: false,
.create_hd_validators(HdValidatorScenario { key_derivation_path_offset: 0,
count: 1, disabled: vec![0],
specify_mnemonic: false, })
key_derivation_path_offset: 0, .await
disabled: vec![0], .assert_enabled_validators_count(2)
}) .assert_validators_count(3)
.await .create_hd_validators(HdValidatorScenario {
.assert_enabled_validators_count(2) count: 0,
.assert_validators_count(3) specify_mnemonic: true,
.create_hd_validators(HdValidatorScenario { key_derivation_path_offset: 4,
count: 0, disabled: vec![],
specify_mnemonic: true, })
key_derivation_path_offset: 4, .await
disabled: vec![], .assert_enabled_validators_count(2)
}) .assert_validators_count(3);
.await
.assert_enabled_validators_count(2)
.assert_validators_count(3);
});
} }
#[test] #[tokio::test]
fn validator_enabling() { async fn validator_enabling() {
let runtime = build_runtime(); ApiTester::new()
let weak_runtime = Arc::downgrade(&runtime); .await
runtime.block_on(async { .create_hd_validators(HdValidatorScenario {
ApiTester::new(weak_runtime) count: 2,
.await specify_mnemonic: false,
.create_hd_validators(HdValidatorScenario { key_derivation_path_offset: 0,
count: 2, disabled: vec![],
specify_mnemonic: false, })
key_derivation_path_offset: 0, .await
disabled: vec![], .assert_enabled_validators_count(2)
}) .assert_validators_count(2)
.await .set_validator_enabled(0, false)
.assert_enabled_validators_count(2) .await
.assert_validators_count(2) .assert_enabled_validators_count(1)
.set_validator_enabled(0, false) .assert_validators_count(2)
.await .set_validator_enabled(0, true)
.assert_enabled_validators_count(1) .await
.assert_validators_count(2) .assert_enabled_validators_count(2)
.set_validator_enabled(0, true) .assert_validators_count(2);
.await
.assert_enabled_validators_count(2)
.assert_validators_count(2);
});
} }
#[test] #[tokio::test]
fn validator_gas_limit() { async fn validator_gas_limit() {
let runtime = build_runtime(); ApiTester::new()
let weak_runtime = Arc::downgrade(&runtime); .await
runtime.block_on(async { .create_hd_validators(HdValidatorScenario {
ApiTester::new(weak_runtime) count: 2,
.await specify_mnemonic: false,
.create_hd_validators(HdValidatorScenario { key_derivation_path_offset: 0,
count: 2, disabled: vec![],
specify_mnemonic: false, })
key_derivation_path_offset: 0, .await
disabled: vec![], .assert_enabled_validators_count(2)
}) .assert_validators_count(2)
.await .set_gas_limit(0, 500)
.assert_enabled_validators_count(2) .await
.assert_validators_count(2) .assert_gas_limit(0, 500)
.set_gas_limit(0, 500) .await
.await // Update gas limit while validator is disabled.
.assert_gas_limit(0, 500) .set_validator_enabled(0, false)
.await .await
// Update gas limit while validator is disabled. .assert_enabled_validators_count(1)
.set_validator_enabled(0, false) .assert_validators_count(2)
.await .set_gas_limit(0, 1000)
.assert_enabled_validators_count(1) .await
.assert_validators_count(2) .set_validator_enabled(0, true)
.set_gas_limit(0, 1000) .await
.await .assert_enabled_validators_count(2)
.set_validator_enabled(0, true) .assert_gas_limit(0, 1000)
.await .await;
.assert_enabled_validators_count(2)
.assert_gas_limit(0, 1000)
.await
});
} }
#[test] #[tokio::test]
fn validator_builder_proposals() { async fn validator_builder_proposals() {
let runtime = build_runtime(); ApiTester::new()
let weak_runtime = Arc::downgrade(&runtime); .await
runtime.block_on(async { .create_hd_validators(HdValidatorScenario {
ApiTester::new(weak_runtime) count: 2,
.await specify_mnemonic: false,
.create_hd_validators(HdValidatorScenario { key_derivation_path_offset: 0,
count: 2, disabled: vec![],
specify_mnemonic: false, })
key_derivation_path_offset: 0, .await
disabled: vec![], .assert_enabled_validators_count(2)
}) .assert_validators_count(2)
.await .set_builder_proposals(0, true)
.assert_enabled_validators_count(2) .await
.assert_validators_count(2) // Test setting builder proposals while the validator is disabled
.set_builder_proposals(0, true) .set_validator_enabled(0, false)
.await .await
// Test setting builder proposals while the validator is disabled .assert_enabled_validators_count(1)
.set_validator_enabled(0, false) .assert_validators_count(2)
.await .set_builder_proposals(0, false)
.assert_enabled_validators_count(1) .await
.assert_validators_count(2) .set_validator_enabled(0, true)
.set_builder_proposals(0, false) .await
.await .assert_enabled_validators_count(2)
.set_validator_enabled(0, true) .assert_builder_proposals(0, false)
.await .await;
.assert_enabled_validators_count(2)
.assert_builder_proposals(0, false)
.await
});
} }
#[test] #[tokio::test]
fn keystore_validator_creation() { async fn keystore_validator_creation() {
let runtime = build_runtime(); ApiTester::new()
let weak_runtime = Arc::downgrade(&runtime); .await
runtime.block_on(async { .assert_enabled_validators_count(0)
ApiTester::new(weak_runtime) .assert_validators_count(0)
.await .create_keystore_validators(KeystoreValidatorScenario {
.assert_enabled_validators_count(0) correct_password: true,
.assert_validators_count(0) enabled: true,
.create_keystore_validators(KeystoreValidatorScenario { })
correct_password: true, .await
enabled: true, .assert_enabled_validators_count(1)
}) .assert_validators_count(1)
.await .create_keystore_validators(KeystoreValidatorScenario {
.assert_enabled_validators_count(1) correct_password: false,
.assert_validators_count(1) enabled: true,
.create_keystore_validators(KeystoreValidatorScenario { })
correct_password: false, .await
enabled: true, .assert_enabled_validators_count(1)
}) .assert_validators_count(1)
.await .create_keystore_validators(KeystoreValidatorScenario {
.assert_enabled_validators_count(1) correct_password: true,
.assert_validators_count(1) enabled: false,
.create_keystore_validators(KeystoreValidatorScenario { })
correct_password: true, .await
enabled: false, .assert_enabled_validators_count(1)
}) .assert_validators_count(2);
.await
.assert_enabled_validators_count(1)
.assert_validators_count(2);
});
} }
#[test] #[tokio::test]
fn web3signer_validator_creation() { async fn web3signer_validator_creation() {
let runtime = build_runtime(); ApiTester::new()
let weak_runtime = Arc::downgrade(&runtime); .await
runtime.block_on(async { .assert_enabled_validators_count(0)
ApiTester::new(weak_runtime) .assert_validators_count(0)
.await .create_web3signer_validators(Web3SignerValidatorScenario {
.assert_enabled_validators_count(0) count: 1,
.assert_validators_count(0) enabled: true,
.create_web3signer_validators(Web3SignerValidatorScenario { })
count: 1, .await
enabled: true, .assert_enabled_validators_count(1)
}) .assert_validators_count(1);
.await
.assert_enabled_validators_count(1)
.assert_validators_count(1);
});
} }

View File

@@ -12,6 +12,7 @@ use itertools::Itertools;
use rand::{rngs::SmallRng, Rng, SeedableRng}; use rand::{rngs::SmallRng, Rng, SeedableRng};
use slashing_protection::interchange::{Interchange, InterchangeMetadata}; use slashing_protection::interchange::{Interchange, InterchangeMetadata};
use std::{collections::HashMap, path::Path}; use std::{collections::HashMap, path::Path};
use tokio::runtime::Handle;
use types::Address; use types::Address;
fn new_keystore(password: ZeroizeString) -> Keystore { fn new_keystore(password: ZeroizeString) -> Keystore {
@@ -64,31 +65,23 @@ fn remotekey_validator_with_pubkey(pubkey: PublicKey) -> SingleImportRemotekeysR
} }
} }
fn run_test<F, V>(f: F) async fn run_test<F, V>(f: F)
where where
F: FnOnce(ApiTester) -> V, F: FnOnce(ApiTester) -> V,
V: Future<Output = ()>, V: Future<Output = ()>,
{ {
let runtime = build_runtime(); let tester = ApiTester::new().await;
let weak_runtime = Arc::downgrade(&runtime); f(tester).await
runtime.block_on(async {
let tester = ApiTester::new(weak_runtime).await;
f(tester).await
});
} }
fn run_dual_vc_test<F, V>(f: F) async fn run_dual_vc_test<F, V>(f: F)
where where
F: FnOnce(ApiTester, ApiTester) -> V, F: FnOnce(ApiTester, ApiTester) -> V,
V: Future<Output = ()>, V: Future<Output = ()>,
{ {
let runtime = build_runtime(); let tester1 = ApiTester::new().await;
let weak_runtime = Arc::downgrade(&runtime); let tester2 = ApiTester::new().await;
runtime.block_on(async { f(tester1, tester2).await
let tester1 = ApiTester::new(weak_runtime.clone()).await;
let tester2 = ApiTester::new(weak_runtime).await;
f(tester1, tester2).await
});
} }
fn keystore_pubkey(keystore: &Keystore) -> PublicKeyBytes { fn keystore_pubkey(keystore: &Keystore) -> PublicKeyBytes {
@@ -199,8 +192,8 @@ fn check_remotekey_delete_response(
} }
} }
#[test] #[tokio::test]
fn get_auth_no_token() { async fn get_auth_no_token() {
run_test(|mut tester| async move { run_test(|mut tester| async move {
let _ = &tester; let _ = &tester;
tester.client.send_authorization_header(false); tester.client.send_authorization_header(false);
@@ -213,19 +206,21 @@ fn get_auth_no_token() {
// The token should match the one that the client was originally initialised with. // The token should match the one that the client was originally initialised with.
assert!(tester.client.api_token() == Some(&token)); assert!(tester.client.api_token() == Some(&token));
}) })
.await;
} }
#[test] #[tokio::test]
fn get_empty_keystores() { async fn get_empty_keystores() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
let res = tester.client.get_keystores().await.unwrap(); let res = tester.client.get_keystores().await.unwrap();
assert_eq!(res, ListKeystoresResponse { data: vec![] }); assert_eq!(res, ListKeystoresResponse { data: vec![] });
}) })
.await;
} }
#[test] #[tokio::test]
fn import_new_keystores() { async fn import_new_keystores() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
let password = random_password_string(); let password = random_password_string();
@@ -250,10 +245,11 @@ fn import_new_keystores() {
let get_res = tester.client.get_keystores().await.unwrap(); let get_res = tester.client.get_keystores().await.unwrap();
check_keystore_get_response(&get_res, &keystores); check_keystore_get_response(&get_res, &keystores);
}) })
.await;
} }
#[test] #[tokio::test]
fn import_only_duplicate_keystores() { async fn import_only_duplicate_keystores() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
let password = random_password_string(); let password = random_password_string();
@@ -279,10 +275,11 @@ fn import_only_duplicate_keystores() {
let get_res = tester.client.get_keystores().await.unwrap(); let get_res = tester.client.get_keystores().await.unwrap();
check_keystore_get_response(&get_res, &keystores); check_keystore_get_response(&get_res, &keystores);
}) })
.await;
} }
#[test] #[tokio::test]
fn import_some_duplicate_keystores() { async fn import_some_duplicate_keystores() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
let password = random_password_string(); let password = random_password_string();
@@ -330,10 +327,11 @@ fn import_some_duplicate_keystores() {
let import_res = tester.client.post_keystores(&req2).await.unwrap(); let import_res = tester.client.post_keystores(&req2).await.unwrap();
check_keystore_import_response(&import_res, expected); check_keystore_import_response(&import_res, expected);
}) })
.await;
} }
#[test] #[tokio::test]
fn import_wrong_number_of_passwords() { async fn import_wrong_number_of_passwords() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
let password = random_password_string(); let password = random_password_string();
@@ -352,10 +350,11 @@ fn import_wrong_number_of_passwords() {
.unwrap_err(); .unwrap_err();
assert_eq!(err.status().unwrap(), 400); assert_eq!(err.status().unwrap(), 400);
}) })
.await;
} }
#[test] #[tokio::test]
fn get_web3_signer_keystores() { async fn get_web3_signer_keystores() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
let num_local = 3; let num_local = 3;
@@ -412,10 +411,11 @@ fn get_web3_signer_keystores() {
assert!(get_res.data.contains(&response), "{:?}", response); assert!(get_res.data.contains(&response), "{:?}", response);
} }
}) })
.await;
} }
#[test] #[tokio::test]
fn import_and_delete_conflicting_web3_signer_keystores() { async fn import_and_delete_conflicting_web3_signer_keystores() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
let num_keystores = 3; let num_keystores = 3;
@@ -477,10 +477,11 @@ fn import_and_delete_conflicting_web3_signer_keystores() {
let delete_res = tester.client.delete_keystores(&delete_req).await.unwrap(); let delete_res = tester.client.delete_keystores(&delete_req).await.unwrap();
check_keystore_delete_response(&delete_res, all_delete_error(keystores.len())); check_keystore_delete_response(&delete_res, all_delete_error(keystores.len()));
}) })
.await;
} }
#[test] #[tokio::test]
fn import_keystores_wrong_password() { async fn import_keystores_wrong_password() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
let num_keystores = 4; let num_keystores = 4;
@@ -551,11 +552,12 @@ fn import_keystores_wrong_password() {
&import_res, &import_res,
(0..num_keystores).map(|_| ImportKeystoreStatus::Duplicate), (0..num_keystores).map(|_| ImportKeystoreStatus::Duplicate),
); );
}); })
.await;
} }
#[test] #[tokio::test]
fn import_invalid_slashing_protection() { async fn import_invalid_slashing_protection() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
let password = random_password_string(); let password = random_password_string();
@@ -589,10 +591,11 @@ fn import_invalid_slashing_protection() {
let get_res = tester.client.get_keystores().await.unwrap(); let get_res = tester.client.get_keystores().await.unwrap();
check_keystore_get_response(&get_res, &[]); check_keystore_get_response(&get_res, &[]);
}) })
.await;
} }
#[test] #[tokio::test]
fn check_get_set_fee_recipient() { async fn check_get_set_fee_recipient() {
run_test(|tester: ApiTester| async move { run_test(|tester: ApiTester| async move {
let _ = &tester; let _ = &tester;
let password = random_password_string(); let password = random_password_string();
@@ -768,6 +771,7 @@ fn check_get_set_fee_recipient() {
); );
} }
}) })
.await;
} }
#[test] #[test]
@@ -949,8 +953,8 @@ fn all_indices(count: usize) -> Vec<usize> {
(0..count).collect() (0..count).collect()
} }
#[test] #[tokio::test]
fn migrate_all_with_slashing_protection() { async fn migrate_all_with_slashing_protection() {
let n = 3; let n = 3;
generic_migration_test( generic_migration_test(
n, n,
@@ -967,11 +971,12 @@ fn migrate_all_with_slashing_protection() {
(1, make_attestation(2, 3), false), (1, make_attestation(2, 3), false),
(2, make_attestation(1, 2), false), (2, make_attestation(1, 2), false),
], ],
); )
.await;
} }
#[test] #[tokio::test]
fn migrate_some_with_slashing_protection() { async fn migrate_some_with_slashing_protection() {
let n = 3; let n = 3;
generic_migration_test( generic_migration_test(
n, n,
@@ -989,11 +994,12 @@ fn migrate_some_with_slashing_protection() {
(0, make_attestation(2, 3), true), (0, make_attestation(2, 3), true),
(1, make_attestation(3, 4), true), (1, make_attestation(3, 4), true),
], ],
); )
.await;
} }
#[test] #[tokio::test]
fn migrate_some_missing_slashing_protection() { async fn migrate_some_missing_slashing_protection() {
let n = 3; let n = 3;
generic_migration_test( generic_migration_test(
n, n,
@@ -1010,11 +1016,12 @@ fn migrate_some_missing_slashing_protection() {
(1, make_attestation(2, 3), true), (1, make_attestation(2, 3), true),
(0, make_attestation(2, 3), true), (0, make_attestation(2, 3), true),
], ],
); )
.await;
} }
#[test] #[tokio::test]
fn migrate_some_extra_slashing_protection() { async fn migrate_some_extra_slashing_protection() {
let n = 3; let n = 3;
generic_migration_test( generic_migration_test(
n, n,
@@ -1033,7 +1040,8 @@ fn migrate_some_extra_slashing_protection() {
(1, make_attestation(3, 4), true), (1, make_attestation(3, 4), true),
(2, make_attestation(2, 3), false), (2, make_attestation(2, 3), false),
], ],
); )
.await;
} }
/// Run a test that creates some validators on one VC, and then migrates them to a second VC. /// Run a test that creates some validators on one VC, and then migrates them to a second VC.
@@ -1051,7 +1059,7 @@ fn migrate_some_extra_slashing_protection() {
/// - `import_indices`: validators to transfer. It needn't be a subset of `delete_indices`. /// - `import_indices`: validators to transfer. It needn't be a subset of `delete_indices`.
/// - `second_vc_attestations`: attestations to sign on the second VC after the transfer. The bool /// - `second_vc_attestations`: attestations to sign on the second VC after the transfer. The bool
/// indicates whether the signing should be successful. /// indicates whether the signing should be successful.
fn generic_migration_test( async fn generic_migration_test(
num_validators: usize, num_validators: usize,
first_vc_attestations: Vec<(usize, Attestation<E>)>, first_vc_attestations: Vec<(usize, Attestation<E>)>,
delete_indices: Vec<usize>, delete_indices: Vec<usize>,
@@ -1169,11 +1177,12 @@ fn generic_migration_test(
Err(e) => assert!(!should_succeed, "{:?}", e), Err(e) => assert!(!should_succeed, "{:?}", e),
} }
} }
}); })
.await
} }
#[test] #[tokio::test]
fn delete_keystores_twice() { async fn delete_keystores_twice() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
let password = random_password_string(); let password = random_password_string();
@@ -1201,10 +1210,11 @@ fn delete_keystores_twice() {
let delete_res = tester.client.delete_keystores(&delete_req).await.unwrap(); let delete_res = tester.client.delete_keystores(&delete_req).await.unwrap();
check_keystore_delete_response(&delete_res, all_not_active(keystores.len())); check_keystore_delete_response(&delete_res, all_not_active(keystores.len()));
}) })
.await
} }
#[test] #[tokio::test]
fn delete_nonexistent_keystores() { async fn delete_nonexistent_keystores() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
let password = random_password_string(); let password = random_password_string();
@@ -1219,6 +1229,7 @@ fn delete_nonexistent_keystores() {
let delete_res = tester.client.delete_keystores(&delete_req).await.unwrap(); let delete_res = tester.client.delete_keystores(&delete_req).await.unwrap();
check_keystore_delete_response(&delete_res, all_not_found(keystores.len())); check_keystore_delete_response(&delete_res, all_not_found(keystores.len()));
}) })
.await
} }
fn make_attestation(source_epoch: u64, target_epoch: u64) -> Attestation<E> { fn make_attestation(source_epoch: u64, target_epoch: u64) -> Attestation<E> {
@@ -1242,9 +1253,9 @@ fn make_attestation(source_epoch: u64, target_epoch: u64) -> Attestation<E> {
} }
} }
#[test] #[tokio::test]
fn delete_concurrent_with_signing() { async fn delete_concurrent_with_signing() {
let runtime = build_runtime(); let handle = Handle::try_current().unwrap();
let num_keys = 8; let num_keys = 8;
let num_signing_threads = 8; let num_signing_threads = 8;
let num_attestations = 100; let num_attestations = 100;
@@ -1257,115 +1268,112 @@ fn delete_concurrent_with_signing() {
"num_keys should be divisible by num threads for simplicity" "num_keys should be divisible by num threads for simplicity"
); );
let weak_runtime = Arc::downgrade(&runtime); let tester = ApiTester::new().await;
runtime.block_on(async {
let tester = ApiTester::new(weak_runtime).await;
// Generate a lot of keys and import them. // Generate a lot of keys and import them.
let password = random_password_string(); let password = random_password_string();
let keystores = (0..num_keys) let keystores = (0..num_keys)
.map(|_| new_keystore(password.clone())) .map(|_| new_keystore(password.clone()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let all_pubkeys = keystores.iter().map(keystore_pubkey).collect::<Vec<_>>(); let all_pubkeys = keystores.iter().map(keystore_pubkey).collect::<Vec<_>>();
let import_res = tester let import_res = tester
.client .client
.post_keystores(&ImportKeystoresRequest { .post_keystores(&ImportKeystoresRequest {
keystores: keystores.clone(), keystores: keystores.clone(),
passwords: vec![password.clone(); keystores.len()], passwords: vec![password.clone(); keystores.len()],
slashing_protection: None, slashing_protection: None,
}) })
.await .await
.unwrap(); .unwrap();
check_keystore_import_response(&import_res, all_imported(keystores.len())); check_keystore_import_response(&import_res, all_imported(keystores.len()));
// Start several threads signing attestations at sequential epochs. // Start several threads signing attestations at sequential epochs.
let mut join_handles = vec![]; let mut join_handles = vec![];
for thread_index in 0..num_signing_threads { for thread_index in 0..num_signing_threads {
let keys_per_thread = num_keys / num_signing_threads; let keys_per_thread = num_keys / num_signing_threads;
let validator_store = tester.validator_store.clone(); let validator_store = tester.validator_store.clone();
let thread_pubkeys = all_pubkeys let thread_pubkeys = all_pubkeys
[thread_index * keys_per_thread..(thread_index + 1) * keys_per_thread] [thread_index * keys_per_thread..(thread_index + 1) * keys_per_thread]
.to_vec(); .to_vec();
let handle = runtime.spawn(async move { let handle = handle.spawn(async move {
for j in 0..num_attestations { for j in 0..num_attestations {
let mut att = make_attestation(j, j + 1); let mut att = make_attestation(j, j + 1);
for (_validator_id, public_key) in thread_pubkeys.iter().enumerate() { for (_validator_id, public_key) in thread_pubkeys.iter().enumerate() {
let _ = validator_store let _ = validator_store
.sign_attestation(*public_key, 0, &mut att, Epoch::new(j + 1)) .sign_attestation(*public_key, 0, &mut att, Epoch::new(j + 1))
.await; .await;
}
} }
});
join_handles.push(handle);
}
// Concurrently, delete each validator one at a time. Store the slashing protection
// data so we can ensure it doesn't change after a key is exported.
let mut delete_handles = vec![];
for _ in 0..num_delete_threads {
let client = tester.client.clone();
let all_pubkeys = all_pubkeys.clone();
let handle = runtime.spawn(async move {
let mut rng = SmallRng::from_entropy();
let mut slashing_protection = vec![];
for _ in 0..num_delete_attempts {
let to_delete = all_pubkeys
.iter()
.filter(|_| rng.gen_bool(delete_prob))
.copied()
.collect::<Vec<_>>();
if !to_delete.is_empty() {
let delete_res = client
.delete_keystores(&DeleteKeystoresRequest { pubkeys: to_delete })
.await
.unwrap();
for status in delete_res.data.iter() {
assert_ne!(status.status, DeleteKeystoreStatus::Error);
}
slashing_protection.push(delete_res.slashing_protection);
}
}
slashing_protection
});
delete_handles.push(handle);
}
// Collect slashing protection.
let mut slashing_protection_map = HashMap::new();
let collected_slashing_protection = futures::future::join_all(delete_handles).await;
for interchange in collected_slashing_protection
.into_iter()
.flat_map(Result::unwrap)
{
for validator_data in interchange.data {
slashing_protection_map
.entry(validator_data.pubkey)
.and_modify(|existing| {
assert_eq!(
*existing, validator_data,
"slashing protection data changed after first export"
)
})
.or_insert(validator_data);
} }
} });
join_handles.push(handle);
}
futures::future::join_all(join_handles).await // Concurrently, delete each validator one at a time. Store the slashing protection
}); // data so we can ensure it doesn't change after a key is exported.
let mut delete_handles = vec![];
for _ in 0..num_delete_threads {
let client = tester.client.clone();
let all_pubkeys = all_pubkeys.clone();
let handle = handle.spawn(async move {
let mut rng = SmallRng::from_entropy();
let mut slashing_protection = vec![];
for _ in 0..num_delete_attempts {
let to_delete = all_pubkeys
.iter()
.filter(|_| rng.gen_bool(delete_prob))
.copied()
.collect::<Vec<_>>();
if !to_delete.is_empty() {
let delete_res = client
.delete_keystores(&DeleteKeystoresRequest { pubkeys: to_delete })
.await
.unwrap();
for status in delete_res.data.iter() {
assert_ne!(status.status, DeleteKeystoreStatus::Error);
}
slashing_protection.push(delete_res.slashing_protection);
}
}
slashing_protection
});
delete_handles.push(handle);
}
// Collect slashing protection.
let mut slashing_protection_map = HashMap::new();
let collected_slashing_protection = futures::future::join_all(delete_handles).await;
for interchange in collected_slashing_protection
.into_iter()
.flat_map(Result::unwrap)
{
for validator_data in interchange.data {
slashing_protection_map
.entry(validator_data.pubkey)
.and_modify(|existing| {
assert_eq!(
*existing, validator_data,
"slashing protection data changed after first export"
)
})
.or_insert(validator_data);
}
}
futures::future::join_all(join_handles).await;
} }
#[test] #[tokio::test]
fn delete_then_reimport() { async fn delete_then_reimport() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
let password = random_password_string(); let password = random_password_string();
@@ -1396,19 +1404,21 @@ fn delete_then_reimport() {
let import_res = tester.client.post_keystores(&import_req).await.unwrap(); let import_res = tester.client.post_keystores(&import_req).await.unwrap();
check_keystore_import_response(&import_res, all_imported(keystores.len())); check_keystore_import_response(&import_res, all_imported(keystores.len()));
}) })
.await
} }
#[test] #[tokio::test]
fn get_empty_remotekeys() { async fn get_empty_remotekeys() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
let res = tester.client.get_remotekeys().await.unwrap(); let res = tester.client.get_remotekeys().await.unwrap();
assert_eq!(res, ListRemotekeysResponse { data: vec![] }); assert_eq!(res, ListRemotekeysResponse { data: vec![] });
}) })
.await
} }
#[test] #[tokio::test]
fn import_new_remotekeys() { async fn import_new_remotekeys() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
@@ -1443,10 +1453,11 @@ fn import_new_remotekeys() {
let get_res = tester.client.get_remotekeys().await.unwrap(); let get_res = tester.client.get_remotekeys().await.unwrap();
check_remotekey_get_response(&get_res, expected_responses); check_remotekey_get_response(&get_res, expected_responses);
}) })
.await
} }
#[test] #[tokio::test]
fn import_same_remotekey_different_url() { async fn import_same_remotekey_different_url() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
@@ -1485,10 +1496,11 @@ fn import_same_remotekey_different_url() {
}], }],
); );
}) })
.await
} }
#[test] #[tokio::test]
fn delete_remotekey_then_reimport_different_url() { async fn delete_remotekey_then_reimport_different_url() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
@@ -1534,10 +1546,11 @@ fn delete_remotekey_then_reimport_different_url() {
vec![ImportRemotekeyStatus::Imported].into_iter(), vec![ImportRemotekeyStatus::Imported].into_iter(),
); );
}) })
.await
} }
#[test] #[tokio::test]
fn import_only_duplicate_remotekeys() { async fn import_only_duplicate_remotekeys() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
let remotekeys = (0..3) let remotekeys = (0..3)
@@ -1582,10 +1595,11 @@ fn import_only_duplicate_remotekeys() {
let get_res = tester.client.get_remotekeys().await.unwrap(); let get_res = tester.client.get_remotekeys().await.unwrap();
check_remotekey_get_response(&get_res, expected_responses); check_remotekey_get_response(&get_res, expected_responses);
}) })
.await
} }
#[test] #[tokio::test]
fn import_some_duplicate_remotekeys() { async fn import_some_duplicate_remotekeys() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
let num_remotekeys = 5; let num_remotekeys = 5;
@@ -1649,10 +1663,11 @@ fn import_some_duplicate_remotekeys() {
let get_res = tester.client.get_remotekeys().await.unwrap(); let get_res = tester.client.get_remotekeys().await.unwrap();
check_remotekey_get_response(&get_res, expected_responses); check_remotekey_get_response(&get_res, expected_responses);
}) })
.await
} }
#[test] #[tokio::test]
fn import_remote_and_local_keys() { async fn import_remote_and_local_keys() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
let num_local = 3; let num_local = 3;
@@ -1714,10 +1729,11 @@ fn import_remote_and_local_keys() {
assert!(get_res.data.contains(&response), "{:?}", response); assert!(get_res.data.contains(&response), "{:?}", response);
} }
}) })
.await
} }
#[test] #[tokio::test]
fn import_same_local_and_remote_keys() { async fn import_same_local_and_remote_keys() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
let num_local = 3; let num_local = 3;
@@ -1782,9 +1798,10 @@ fn import_same_local_and_remote_keys() {
assert!(get_res.data.contains(&response), "{:?}", response); assert!(get_res.data.contains(&response), "{:?}", response);
} }
}) })
.await
} }
#[test] #[tokio::test]
fn import_same_remote_and_local_keys() { async fn import_same_remote_and_local_keys() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
let num_local = 3; let num_local = 3;
@@ -1847,10 +1864,11 @@ fn import_same_remote_and_local_keys() {
let get_res = tester.client.get_remotekeys().await.unwrap(); let get_res = tester.client.get_remotekeys().await.unwrap();
check_remotekey_get_response(&get_res, expected_responses); check_remotekey_get_response(&get_res, expected_responses);
}) })
.await
} }
#[test] #[tokio::test]
fn delete_remotekeys_twice() { async fn delete_remotekeys_twice() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
@@ -1893,10 +1911,11 @@ fn delete_remotekeys_twice() {
let get_res = tester.client.get_remotekeys().await.unwrap(); let get_res = tester.client.get_remotekeys().await.unwrap();
check_remotekey_get_response(&get_res, Vec::new()); check_remotekey_get_response(&get_res, Vec::new());
}) })
.await
} }
#[test] #[tokio::test]
fn delete_nonexistent_remotekey() { async fn delete_nonexistent_remotekey() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
@@ -1919,10 +1938,11 @@ fn delete_nonexistent_remotekey() {
let get_res = tester.client.get_remotekeys().await.unwrap(); let get_res = tester.client.get_remotekeys().await.unwrap();
check_remotekey_get_response(&get_res, Vec::new()); check_remotekey_get_response(&get_res, Vec::new());
}) })
.await
} }
#[test] #[tokio::test]
fn delete_then_reimport_remotekeys() { async fn delete_then_reimport_remotekeys() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
@@ -1984,10 +2004,11 @@ fn delete_then_reimport_remotekeys() {
let get_res = tester.client.get_remotekeys().await.unwrap(); let get_res = tester.client.get_remotekeys().await.unwrap();
check_remotekey_get_response(&get_res, expected_responses); check_remotekey_get_response(&get_res, expected_responses);
}) })
.await
} }
#[test] #[tokio::test]
fn import_remotekey_web3signer() { async fn import_remotekey_web3signer() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
@@ -2043,10 +2064,11 @@ fn import_remotekey_web3signer() {
let get_res = tester.client.get_remotekeys().await.unwrap(); let get_res = tester.client.get_remotekeys().await.unwrap();
check_remotekey_get_response(&get_res, expected_responses); check_remotekey_get_response(&get_res, expected_responses);
}) })
.await
} }
#[test] #[tokio::test]
fn import_remotekey_web3signer_disabled() { async fn import_remotekey_web3signer_disabled() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
@@ -2096,10 +2118,11 @@ fn import_remotekey_web3signer_disabled() {
let get_res = tester.client.get_remotekeys().await.unwrap(); let get_res = tester.client.get_remotekeys().await.unwrap();
check_remotekey_get_response(&get_res, expected_responses); check_remotekey_get_response(&get_res, expected_responses);
}) })
.await
} }
#[test] #[tokio::test]
fn import_remotekey_web3signer_enabled() { async fn import_remotekey_web3signer_enabled() {
run_test(|tester| async move { run_test(|tester| async move {
let _ = &tester; let _ = &tester;
@@ -2156,4 +2179,5 @@ fn import_remotekey_web3signer_enabled() {
let get_res = tester.client.get_remotekeys().await.unwrap(); let get_res = tester.client.get_remotekeys().await.unwrap();
check_remotekey_get_response(&get_res, expected_responses); check_remotekey_get_response(&get_res, expected_responses);
}) })
.await
} }