solana-program-library/record/program/tests/functional.rs

553 lines
16 KiB
Rust

// Mark this test as BPF-only due to current `ProgramTest` limitations when CPIing into the system program
#![cfg(feature = "test-bpf")]
use {
borsh::BorshSerialize,
solana_program::{
borsh::get_packed_len,
instruction::{AccountMeta, Instruction, InstructionError},
pubkey::Pubkey,
rent::Rent,
system_instruction,
},
solana_program_test::*,
solana_sdk::{
signature::{Keypair, Signer},
transaction::{Transaction, TransactionError},
transport,
},
spl_record::{
error::RecordError,
id, instruction,
processor::process_instruction,
state::{Data, RecordData},
},
};
fn program_test() -> ProgramTest {
ProgramTest::new("spl_record", id(), processor!(process_instruction))
}
async fn initialize_storage_account(
context: &mut ProgramTestContext,
authority: &Keypair,
account: &Keypair,
data: Data,
) -> transport::Result<()> {
let transaction = Transaction::new_signed_with_payer(
&[
system_instruction::create_account(
&context.payer.pubkey(),
&account.pubkey(),
1.max(Rent::default().minimum_balance(get_packed_len::<RecordData>())),
get_packed_len::<RecordData>() as u64,
&id(),
),
instruction::initialize(&account.pubkey(), &authority.pubkey()),
instruction::write(
&account.pubkey(),
&authority.pubkey(),
0,
data.try_to_vec().unwrap(),
),
],
Some(&context.payer.pubkey()),
&[&context.payer, account, authority],
context.last_blockhash,
);
context.banks_client.process_transaction(transaction).await
}
#[tokio::test]
async fn initialize_success() {
let mut context = program_test().start_with_context().await;
let authority = Keypair::new();
let account = Keypair::new();
let data = Data {
bytes: [111u8; Data::DATA_SIZE],
};
initialize_storage_account(&mut context, &authority, &account, data.clone())
.await
.unwrap();
let account_data = context
.banks_client
.get_account_data_with_borsh::<RecordData>(account.pubkey())
.await
.unwrap();
assert_eq!(account_data.data, data);
assert_eq!(account_data.authority, authority.pubkey());
assert_eq!(account_data.version, RecordData::CURRENT_VERSION);
}
#[tokio::test]
async fn initialize_with_seed_success() {
let mut context = program_test().start_with_context().await;
let authority = Keypair::new();
let seed = "storage";
let account = Pubkey::create_with_seed(&authority.pubkey(), seed, &id()).unwrap();
let data = Data {
bytes: [111u8; Data::DATA_SIZE],
};
let transaction = Transaction::new_signed_with_payer(
&[
system_instruction::create_account_with_seed(
&context.payer.pubkey(),
&account,
&authority.pubkey(),
seed,
1.max(Rent::default().minimum_balance(get_packed_len::<RecordData>())),
get_packed_len::<RecordData>() as u64,
&id(),
),
instruction::initialize(&account, &authority.pubkey()),
instruction::write(&account, &authority.pubkey(), 0, data.try_to_vec().unwrap()),
],
Some(&context.payer.pubkey()),
&[&context.payer, &authority],
context.last_blockhash,
);
context
.banks_client
.process_transaction(transaction)
.await
.unwrap();
let account_data = context
.banks_client
.get_account_data_with_borsh::<RecordData>(account)
.await
.unwrap();
assert_eq!(account_data.data, data);
assert_eq!(account_data.authority, authority.pubkey());
assert_eq!(account_data.version, RecordData::CURRENT_VERSION);
}
#[tokio::test]
async fn initialize_twice_fail() {
let mut context = program_test().start_with_context().await;
let authority = Keypair::new();
let account = Keypair::new();
let data = Data {
bytes: [111u8; Data::DATA_SIZE],
};
initialize_storage_account(&mut context, &authority, &account, data)
.await
.unwrap();
let transaction = Transaction::new_signed_with_payer(
&[instruction::initialize(
&account.pubkey(),
&authority.pubkey(),
)],
Some(&context.payer.pubkey()),
&[&context.payer],
context.last_blockhash,
);
assert_eq!(
context
.banks_client
.process_transaction(transaction)
.await
.unwrap_err()
.unwrap(),
TransactionError::InstructionError(0, InstructionError::AccountAlreadyInitialized)
);
}
#[tokio::test]
async fn write_success() {
let mut context = program_test().start_with_context().await;
let authority = Keypair::new();
let account = Keypair::new();
let data = Data {
bytes: [222u8; Data::DATA_SIZE],
};
initialize_storage_account(&mut context, &authority, &account, data)
.await
.unwrap();
let new_data = Data {
bytes: [200u8; Data::DATA_SIZE],
};
let transaction = Transaction::new_signed_with_payer(
&[instruction::write(
&account.pubkey(),
&authority.pubkey(),
0,
new_data.try_to_vec().unwrap(),
)],
Some(&context.payer.pubkey()),
&[&context.payer, &authority],
context.last_blockhash,
);
context
.banks_client
.process_transaction(transaction)
.await
.unwrap();
let account_data = context
.banks_client
.get_account_data_with_borsh::<RecordData>(account.pubkey())
.await
.unwrap();
assert_eq!(account_data.data, new_data);
assert_eq!(account_data.authority, authority.pubkey());
assert_eq!(account_data.version, RecordData::CURRENT_VERSION);
}
#[tokio::test]
async fn write_fail_wrong_authority() {
let mut context = program_test().start_with_context().await;
let authority = Keypair::new();
let account = Keypair::new();
let data = Data {
bytes: [222u8; Data::DATA_SIZE],
};
initialize_storage_account(&mut context, &authority, &account, data)
.await
.unwrap();
let new_data = Data {
bytes: [200u8; Data::DATA_SIZE],
};
let wrong_authority = Keypair::new();
let transaction = Transaction::new_signed_with_payer(
&[instruction::write(
&account.pubkey(),
&wrong_authority.pubkey(),
0,
new_data.try_to_vec().unwrap(),
)],
Some(&context.payer.pubkey()),
&[&context.payer, &wrong_authority],
context.last_blockhash,
);
assert_eq!(
context
.banks_client
.process_transaction(transaction)
.await
.unwrap_err()
.unwrap(),
TransactionError::InstructionError(
0,
InstructionError::Custom(RecordError::IncorrectAuthority as u32)
)
);
}
#[tokio::test]
async fn write_fail_unsigned() {
let mut context = program_test().start_with_context().await;
let authority = Keypair::new();
let account = Keypair::new();
let data = Data {
bytes: [222u8; Data::DATA_SIZE],
};
initialize_storage_account(&mut context, &authority, &account, data)
.await
.unwrap();
let data = Data {
bytes: [200u8; Data::DATA_SIZE],
}
.try_to_vec()
.unwrap();
let transaction = Transaction::new_signed_with_payer(
&[Instruction::new_with_borsh(
id(),
&instruction::RecordInstruction::Write { offset: 0, data },
vec![
AccountMeta::new(account.pubkey(), false),
AccountMeta::new_readonly(authority.pubkey(), false),
],
)],
Some(&context.payer.pubkey()),
&[&context.payer],
context.last_blockhash,
);
assert_eq!(
context
.banks_client
.process_transaction(transaction)
.await
.unwrap_err()
.unwrap(),
TransactionError::InstructionError(0, InstructionError::MissingRequiredSignature)
);
}
#[tokio::test]
async fn close_account_success() {
let mut context = program_test().start_with_context().await;
let authority = Keypair::new();
let account = Keypair::new();
let data = Data {
bytes: [222u8; Data::DATA_SIZE],
};
initialize_storage_account(&mut context, &authority, &account, data)
.await
.unwrap();
let recipient = Pubkey::new_unique();
let transaction = Transaction::new_signed_with_payer(
&[instruction::close_account(
&account.pubkey(),
&authority.pubkey(),
&recipient,
)],
Some(&context.payer.pubkey()),
&[&context.payer, &authority],
context.last_blockhash,
);
context
.banks_client
.process_transaction(transaction)
.await
.unwrap();
let account = context
.banks_client
.get_account(recipient)
.await
.unwrap()
.unwrap();
assert_eq!(
account.lamports,
1.max(Rent::default().minimum_balance(get_packed_len::<RecordData>()))
);
}
#[tokio::test]
async fn close_account_fail_wrong_authority() {
let mut context = program_test().start_with_context().await;
let authority = Keypair::new();
let account = Keypair::new();
let data = Data {
bytes: [222u8; Data::DATA_SIZE],
};
initialize_storage_account(&mut context, &authority, &account, data)
.await
.unwrap();
let wrong_authority = Keypair::new();
let transaction = Transaction::new_signed_with_payer(
&[Instruction::new_with_borsh(
id(),
&instruction::RecordInstruction::CloseAccount,
vec![
AccountMeta::new(account.pubkey(), false),
AccountMeta::new_readonly(wrong_authority.pubkey(), true),
AccountMeta::new(Pubkey::new_unique(), false),
],
)],
Some(&context.payer.pubkey()),
&[&context.payer, &wrong_authority],
context.last_blockhash,
);
assert_eq!(
context
.banks_client
.process_transaction(transaction)
.await
.unwrap_err()
.unwrap(),
TransactionError::InstructionError(
0,
InstructionError::Custom(RecordError::IncorrectAuthority as u32)
)
);
}
#[tokio::test]
async fn close_account_fail_unsigned() {
let mut context = program_test().start_with_context().await;
let authority = Keypair::new();
let account = Keypair::new();
let data = Data {
bytes: [222u8; Data::DATA_SIZE],
};
initialize_storage_account(&mut context, &authority, &account, data)
.await
.unwrap();
let transaction = Transaction::new_signed_with_payer(
&[Instruction::new_with_borsh(
id(),
&instruction::RecordInstruction::CloseAccount,
vec![
AccountMeta::new(account.pubkey(), false),
AccountMeta::new_readonly(authority.pubkey(), false),
AccountMeta::new(Pubkey::new_unique(), false),
],
)],
Some(&context.payer.pubkey()),
&[&context.payer],
context.last_blockhash,
);
assert_eq!(
context
.banks_client
.process_transaction(transaction)
.await
.unwrap_err()
.unwrap(),
TransactionError::InstructionError(0, InstructionError::MissingRequiredSignature)
);
}
#[tokio::test]
async fn set_authority_success() {
let mut context = program_test().start_with_context().await;
let authority = Keypair::new();
let account = Keypair::new();
let data = Data {
bytes: [222u8; Data::DATA_SIZE],
};
initialize_storage_account(&mut context, &authority, &account, data)
.await
.unwrap();
let new_authority = Keypair::new();
let transaction = Transaction::new_signed_with_payer(
&[instruction::set_authority(
&account.pubkey(),
&authority.pubkey(),
&new_authority.pubkey(),
)],
Some(&context.payer.pubkey()),
&[&context.payer, &authority],
context.last_blockhash,
);
context
.banks_client
.process_transaction(transaction)
.await
.unwrap();
let account_data = context
.banks_client
.get_account_data_with_borsh::<RecordData>(account.pubkey())
.await
.unwrap();
assert_eq!(account_data.authority, new_authority.pubkey());
let new_data = Data {
bytes: [200u8; Data::DATA_SIZE],
};
let transaction = Transaction::new_signed_with_payer(
&[instruction::write(
&account.pubkey(),
&new_authority.pubkey(),
0,
new_data.try_to_vec().unwrap(),
)],
Some(&context.payer.pubkey()),
&[&context.payer, &new_authority],
context.last_blockhash,
);
context
.banks_client
.process_transaction(transaction)
.await
.unwrap();
let account_data = context
.banks_client
.get_account_data_with_borsh::<RecordData>(account.pubkey())
.await
.unwrap();
assert_eq!(account_data.data, new_data);
assert_eq!(account_data.authority, new_authority.pubkey());
assert_eq!(account_data.version, RecordData::CURRENT_VERSION);
}
#[tokio::test]
async fn set_authority_fail_wrong_authority() {
let mut context = program_test().start_with_context().await;
let authority = Keypair::new();
let account = Keypair::new();
let data = Data {
bytes: [222u8; Data::DATA_SIZE],
};
initialize_storage_account(&mut context, &authority, &account, data)
.await
.unwrap();
let wrong_authority = Keypair::new();
let transaction = Transaction::new_signed_with_payer(
&[Instruction::new_with_borsh(
id(),
&instruction::RecordInstruction::SetAuthority,
vec![
AccountMeta::new(account.pubkey(), false),
AccountMeta::new_readonly(wrong_authority.pubkey(), true),
AccountMeta::new(Pubkey::new_unique(), false),
],
)],
Some(&context.payer.pubkey()),
&[&context.payer, &wrong_authority],
context.last_blockhash,
);
assert_eq!(
context
.banks_client
.process_transaction(transaction)
.await
.unwrap_err()
.unwrap(),
TransactionError::InstructionError(
0,
InstructionError::Custom(RecordError::IncorrectAuthority as u32)
)
);
}
#[tokio::test]
async fn set_authority_fail_unsigned() {
let mut context = program_test().start_with_context().await;
let authority = Keypair::new();
let account = Keypair::new();
let data = Data {
bytes: [222u8; Data::DATA_SIZE],
};
initialize_storage_account(&mut context, &authority, &account, data)
.await
.unwrap();
let transaction = Transaction::new_signed_with_payer(
&[Instruction::new_with_borsh(
id(),
&instruction::RecordInstruction::SetAuthority,
vec![
AccountMeta::new(account.pubkey(), false),
AccountMeta::new_readonly(authority.pubkey(), false),
AccountMeta::new(Pubkey::new_unique(), false),
],
)],
Some(&context.payer.pubkey()),
&[&context.payer],
context.last_blockhash,
);
assert_eq!(
context
.banks_client
.process_transaction(transaction)
.await
.unwrap_err()
.unwrap(),
TransactionError::InstructionError(0, InstructionError::MissingRequiredSignature)
);
}