Tests: Fix concurrent log capture
This commit is contained in:
parent
d6d66402f7
commit
e1adbf0217
|
@ -52,7 +52,7 @@ impl AddPacked for ProgramTest {
|
||||||
|
|
||||||
struct LoggerWrapper {
|
struct LoggerWrapper {
|
||||||
inner: env_logger::Logger,
|
inner: env_logger::Logger,
|
||||||
program_log: Arc<RwLock<Vec<String>>>,
|
capture: Arc<RwLock<Vec<String>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Log for LoggerWrapper {
|
impl Log for LoggerWrapper {
|
||||||
|
@ -67,9 +67,9 @@ impl Log for LoggerWrapper {
|
||||||
{
|
{
|
||||||
let msg = record.args().to_string();
|
let msg = record.args().to_string();
|
||||||
if let Some(data) = msg.strip_prefix("Program log: ") {
|
if let Some(data) = msg.strip_prefix("Program log: ") {
|
||||||
self.program_log.write().unwrap().push(data.into());
|
self.capture.write().unwrap().push(data.into());
|
||||||
} else if let Some(data) = msg.strip_prefix("Program data: ") {
|
} else if let Some(data) = msg.strip_prefix("Program data: ") {
|
||||||
self.program_log.write().unwrap().push(data.into());
|
self.capture.write().unwrap().push(data.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.inner.log(record);
|
self.inner.log(record);
|
||||||
|
@ -87,12 +87,13 @@ pub struct MarginTradeCookie {
|
||||||
|
|
||||||
pub struct TestContextBuilder {
|
pub struct TestContextBuilder {
|
||||||
test: ProgramTest,
|
test: ProgramTest,
|
||||||
program_log_capture: Arc<RwLock<Vec<String>>>,
|
logger_capture: Arc<RwLock<Vec<String>>>,
|
||||||
mint0: Pubkey,
|
mint0: Pubkey,
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref PROGRAM_LOG_CAPTURE: Arc<RwLock<Vec<String>>> = Arc::new(RwLock::new(vec![]));
|
static ref LOGGER_CAPTURE: Arc<RwLock<Vec<String>>> = Arc::new(RwLock::new(vec![]));
|
||||||
|
static ref LOGGER_LOCK: Arc<RwLock<()>> = Arc::new(RwLock::new(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestContextBuilder {
|
impl TestContextBuilder {
|
||||||
|
@ -108,7 +109,7 @@ impl TestContextBuilder {
|
||||||
.build();
|
.build();
|
||||||
let _ = log::set_boxed_logger(Box::new(LoggerWrapper {
|
let _ = log::set_boxed_logger(Box::new(LoggerWrapper {
|
||||||
inner: env_logger,
|
inner: env_logger,
|
||||||
program_log: PROGRAM_LOG_CAPTURE.clone(),
|
capture: LOGGER_CAPTURE.clone(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let mut test = ProgramTest::new("mango_v4", mango_v4::id(), processor!(mango_v4::entry));
|
let mut test = ProgramTest::new("mango_v4", mango_v4::id(), processor!(mango_v4::entry));
|
||||||
|
@ -118,7 +119,7 @@ impl TestContextBuilder {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
test,
|
test,
|
||||||
program_log_capture: PROGRAM_LOG_CAPTURE.clone(),
|
logger_capture: LOGGER_CAPTURE.clone(),
|
||||||
mint0: Pubkey::new_unique(),
|
mint0: Pubkey::new_unique(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,7 +283,9 @@ impl TestContextBuilder {
|
||||||
let solana = Arc::new(SolanaCookie {
|
let solana = Arc::new(SolanaCookie {
|
||||||
context: RefCell::new(context),
|
context: RefCell::new(context),
|
||||||
rent,
|
rent,
|
||||||
program_log: self.program_log_capture.clone(),
|
logger_capture: self.logger_capture.clone(),
|
||||||
|
logger_lock: LOGGER_LOCK.clone(),
|
||||||
|
last_transaction_log: RefCell::new(vec![]),
|
||||||
});
|
});
|
||||||
|
|
||||||
solana
|
solana
|
||||||
|
|
|
@ -17,7 +17,9 @@ use spl_token::*;
|
||||||
pub struct SolanaCookie {
|
pub struct SolanaCookie {
|
||||||
pub context: RefCell<ProgramTestContext>,
|
pub context: RefCell<ProgramTestContext>,
|
||||||
pub rent: Rent,
|
pub rent: Rent,
|
||||||
pub program_log: Arc<RwLock<Vec<String>>>,
|
pub logger_capture: Arc<RwLock<Vec<String>>>,
|
||||||
|
pub logger_lock: Arc<RwLock<()>>,
|
||||||
|
pub last_transaction_log: RefCell<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SolanaCookie {
|
impl SolanaCookie {
|
||||||
|
@ -27,7 +29,15 @@ impl SolanaCookie {
|
||||||
instructions: &[Instruction],
|
instructions: &[Instruction],
|
||||||
signers: Option<&[&Keypair]>,
|
signers: Option<&[&Keypair]>,
|
||||||
) -> Result<(), BanksClientError> {
|
) -> Result<(), BanksClientError> {
|
||||||
self.program_log.write().unwrap().clear();
|
// The locking in this function is convoluted:
|
||||||
|
// We capture the program log output by overriding the global logger and capturing
|
||||||
|
// messages there. This logger is potentially shared among multiple tests that run
|
||||||
|
// concurrently.
|
||||||
|
// To allow each independent SolanaCookie to capture only the logs from the transaction
|
||||||
|
// passed to process_transaction, wo globally hold the "program_log_lock" for the
|
||||||
|
// duration that the tx needs to process. So only a single one can run at a time.
|
||||||
|
let tx_log_lock = Arc::new(self.logger_lock.write().unwrap());
|
||||||
|
self.logger_capture.write().unwrap().clear();
|
||||||
|
|
||||||
let mut context = self.context.borrow_mut();
|
let mut context = self.context.borrow_mut();
|
||||||
|
|
||||||
|
@ -45,13 +55,19 @@ impl SolanaCookie {
|
||||||
|
|
||||||
transaction.sign(&all_signers, context.last_blockhash);
|
transaction.sign(&all_signers, context.last_blockhash);
|
||||||
|
|
||||||
context
|
let result = context
|
||||||
.banks_client
|
.banks_client
|
||||||
.process_transaction_with_commitment(
|
.process_transaction_with_commitment(
|
||||||
transaction,
|
transaction,
|
||||||
solana_sdk::commitment_config::CommitmentLevel::Processed,
|
solana_sdk::commitment_config::CommitmentLevel::Processed,
|
||||||
)
|
)
|
||||||
.await
|
.await;
|
||||||
|
|
||||||
|
*self.last_transaction_log.borrow_mut() = self.logger_capture.read().unwrap().clone();
|
||||||
|
|
||||||
|
drop(tx_log_lock);
|
||||||
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_clock(&self) -> solana_program::clock::Clock {
|
pub async fn get_clock(&self) -> solana_program::clock::Clock {
|
||||||
|
@ -221,7 +237,7 @@ impl SolanaCookie {
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn program_log(&self) -> Vec<String> {
|
pub fn program_log(&self) -> Vec<String> {
|
||||||
self.program_log.read().unwrap().clone()
|
self.last_transaction_log.borrow().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn program_log_events<T: anchor_lang::Event + anchor_lang::AnchorDeserialize>(
|
pub fn program_log_events<T: anchor_lang::Event + anchor_lang::AnchorDeserialize>(
|
||||||
|
|
Loading…
Reference in New Issue