Skip to content

Commit

Permalink
single-pool: improve tests
Browse files Browse the repository at this point in the history
* allow minimum delegation to be disabled, and do this by default
* test initialize, deposit, and withdraw with and without minimum
* test that deposit and withdraw work with sub-minium values
* test that initialize fails with a sub-minimum starting amount
  • Loading branch information
2501babe committed Jan 19, 2024
1 parent 2cefc84 commit c01db92
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 53 deletions.
4 changes: 2 additions & 2 deletions single-pool/program/tests/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ async fn build_instructions(
.await;

let rent = context.banks_client.get_rent().await.unwrap();
let minimum_delegation = get_minimum_delegation(
let minimum_delegation = get_pool_minimum_delegation(
&mut context.banks_client,
&context.payer,
&context.last_blockhash,
Expand Down Expand Up @@ -145,7 +145,7 @@ async fn build_instructions(
#[test_case(TestMode::Withdraw; "withdraw")]
#[tokio::test]
async fn fail_account_checks(test_mode: TestMode) {
let mut context = program_test().start_with_context().await;
let mut context = program_test(false).start_with_context().await;
let accounts = SinglePoolAccounts::default();
let (instructions, i) = build_instructions(&mut context, &accounts, test_mode).await;

Expand Down
4 changes: 2 additions & 2 deletions single-pool/program/tests/create_pool_token_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ fn assert_metadata(vote_account: &Pubkey, metadata: &Metadata) {

#[tokio::test]
async fn success() {
let mut context = program_test().start_with_context().await;
let mut context = program_test(false).start_with_context().await;
let accounts = SinglePoolAccounts::default();
accounts.initialize(&mut context).await;

Expand All @@ -34,7 +34,7 @@ async fn success() {

#[tokio::test]
async fn fail_double_init() {
let mut context = program_test().start_with_context().await;
let mut context = program_test(false).start_with_context().await;
let accounts = SinglePoolAccounts::default();
accounts.initialize(&mut context).await;
refresh_blockhash(&mut context).await;
Expand Down
62 changes: 40 additions & 22 deletions single-pool/program/tests/deposit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,32 @@ use {
test_case::test_case,
};

#[test_case(true, 0, false; "activated")]
#[test_case(false, 0, false; "activating")]
#[test_case(true, 100_000, false; "activated_extra")]
#[test_case(false, 100_000, false; "activating_extra")]
#[test_case(true, 0, true; "activated_second")]
#[test_case(false, 0, true; "activating_second")]
#[test_case(true, 0, false, false, false; "activated::minimum_disabled")]
#[test_case(true, 0, false, false, true; "activated::minimum_disabled::small")]
#[test_case(true, 0, false, true, false; "activated::minimum_enabled")]
#[test_case(false, 0, false, false, false; "activating::minimum_disabled")]
#[test_case(false, 0, false, false, true; "activating::minimum_disabled::small")]
#[test_case(false, 0, false, true, false; "activating::minimum_enabled")]
#[test_case(true, 100_000, false, false, false; "activated::extra")]
#[test_case(false, 100_000, false, false, false; "activating::extra")]
#[test_case(true, 0, true, false, false; "activated::second")]
#[test_case(false, 0, true, false, false; "activating::second")]
#[tokio::test]
async fn success(activate: bool, extra_lamports: u64, prior_deposit: bool) {
let mut context = program_test().start_with_context().await;
async fn success(
activate: bool,
extra_lamports: u64,
prior_deposit: bool,
enable_minimum_delegation: bool,
small_deposit: bool,
) {
let mut context = program_test(enable_minimum_delegation)
.start_with_context()
.await;
let accounts = SinglePoolAccounts::default();
accounts
.initialize_for_deposit(
&mut context,
TEST_STAKE_AMOUNT,
if small_deposit { 1 } else { TEST_STAKE_AMOUNT },
if prior_deposit {
Some(TEST_STAKE_AMOUNT * 10)
} else {
Expand Down Expand Up @@ -158,11 +170,17 @@ async fn success(activate: bool, extra_lamports: u64, prior_deposit: bool) {
);
}

#[test_case(true; "activated")]
#[test_case(false; "activating")]
#[test_case(true, false, false; "activated::minimum_disabled")]
#[test_case(true, false, true; "activated::minimum_disabled::small")]
#[test_case(true, true, false; "activated::minimum_enabled")]
#[test_case(false, false, false; "activating::minimum_disabled")]
#[test_case(false, false, true; "activating::minimum_disabled::small")]
#[test_case(false, true, false; "activating::minimum_enabled")]
#[tokio::test]
async fn success_with_seed(activate: bool) {
let mut context = program_test().start_with_context().await;
async fn success_with_seed(activate: bool, enable_minimum_delegation: bool, small_deposit: bool) {
let mut context = program_test(enable_minimum_delegation)
.start_with_context()
.await;
let accounts = SinglePoolAccounts::default();
let rent = context.banks_client.get_rent().await.unwrap();
let minimum_stake = accounts.initialize(&mut context).await;
Expand All @@ -174,7 +192,7 @@ async fn success_with_seed(activate: bool) {
&accounts.vote_account.pubkey(),
&accounts.alice.pubkey(),
&rent,
minimum_stake,
if small_deposit { 1 } else { minimum_stake },
);
let transaction = Transaction::new_signed_with_payer(
&instructions,
Expand Down Expand Up @@ -261,7 +279,7 @@ async fn success_with_seed(activate: bool) {
#[test_case(false; "activating")]
#[tokio::test]
async fn fail_uninitialized(activate: bool) {
let mut context = program_test().start_with_context().await;
let mut context = program_test(false).start_with_context().await;
let accounts = SinglePoolAccounts::default();
let stake_account = Keypair::new();

Expand Down Expand Up @@ -331,13 +349,13 @@ async fn fail_uninitialized(activate: bool) {
check_error(e, SinglePoolError::InvalidPoolAccount);
}

#[test_case(true, true; "activated_automorph")]
#[test_case(false, true; "activating_automorph")]
#[test_case(true, false; "activated_unauth")]
#[test_case(false, false; "activating_unauth")]
#[test_case(true, true; "activated::automorph")]
#[test_case(false, true; "activating::automorph")]
#[test_case(true, false; "activated::unauth")]
#[test_case(false, false; "activating::unauth")]
#[tokio::test]
async fn fail_bad_account(activate: bool, automorph: bool) {
let mut context = program_test().start_with_context().await;
let mut context = program_test(false).start_with_context().await;
let accounts = SinglePoolAccounts::default();
accounts
.initialize_for_deposit(&mut context, TEST_STAKE_AMOUNT, None)
Expand Down Expand Up @@ -382,10 +400,10 @@ async fn fail_bad_account(activate: bool, automorph: bool) {
#[test_case(false; "user_active")]
#[tokio::test]
async fn fail_activation_mismatch(pool_first: bool) {
let mut context = program_test().start_with_context().await;
let mut context = program_test(false).start_with_context().await;
let accounts = SinglePoolAccounts::default();

let minimum_delegation = get_minimum_delegation(
let minimum_delegation = get_pool_minimum_delegation(
&mut context.banks_client,
&context.payer,
&context.last_blockhash,
Expand Down
13 changes: 9 additions & 4 deletions single-pool/program/tests/helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use {
solana_program_test::*,
solana_sdk::{
account::Account as SolanaAccount,
feature_set::stake_raise_minimum_delegation_to_1_sol,
hash::Hash,
program_error::ProgramError,
pubkey::Pubkey,
Expand Down Expand Up @@ -34,13 +35,17 @@ pub use stake::*;
pub const FIRST_NORMAL_EPOCH: u64 = 15;
pub const USER_STARTING_LAMPORTS: u64 = 10_000_000_000_000; // 10k sol

pub fn program_test() -> ProgramTest {
pub fn program_test(enable_minimum_delegation: bool) -> ProgramTest {
let mut program_test = ProgramTest::default();
program_test.add_program("mpl_token_metadata", inline_mpl_token_metadata::id(), None);

program_test.add_program("mpl_token_metadata", inline_mpl_token_metadata::id(), None);
program_test.add_program("spl_single_pool", id(), processor!(Processor::process));

program_test.prefer_bpf(false);

if !enable_minimum_delegation {
program_test.deactivate_feature(stake_raise_minimum_delegation_to_1_sol::id());
}

program_test
}

Expand Down Expand Up @@ -227,7 +232,7 @@ impl SinglePoolAccounts {
.await;

let rent = context.banks_client.get_rent().await.unwrap();
let minimum_delegation = get_minimum_delegation(
let minimum_delegation = get_pool_minimum_delegation(
&mut context.banks_client,
&context.payer,
&context.last_blockhash,
Expand Down
7 changes: 5 additions & 2 deletions single-pool/program/tests/helpers/stake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use {
solana_program_test::BanksClient,
solana_sdk::{
hash::Hash,
native_token::LAMPORTS_PER_SOL,
pubkey::Pubkey,
signature::{Keypair, Signer},
stake::{
Expand Down Expand Up @@ -38,7 +39,7 @@ pub async fn get_stake_account_rent(banks_client: &mut BanksClient) -> u64 {
rent.minimum_balance(std::mem::size_of::<stake::state::StakeStateV2>())
}

pub async fn get_minimum_delegation(
pub async fn get_pool_minimum_delegation(
banks_client: &mut BanksClient,
payer: &Keypair,
recent_blockhash: &Hash,
Expand All @@ -59,7 +60,9 @@ pub async fn get_minimum_delegation(
.unwrap()
.data;
data.resize(8, 0);
data.try_into().map(u64::from_le_bytes).unwrap()
let stake_program_minimum = data.try_into().map(u64::from_le_bytes).unwrap();

std::cmp::max(stake_program_minimum, LAMPORTS_PER_SOL)
}

#[allow(clippy::too_many_arguments)]
Expand Down
63 changes: 60 additions & 3 deletions single-pool/program/tests/initialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,16 @@ use {
solana_sdk::{program_pack::Pack, signature::Signer, stake, transaction::Transaction},
spl_single_pool::{error::SinglePoolError, id, instruction},
spl_token::state::Mint,
test_case::test_case,
};

#[test_case(true; "minimum_enabled")]
#[test_case(false; "minimum_disabled")]
#[tokio::test]
async fn success() {
let mut context = program_test().start_with_context().await;
async fn success(enable_minimum_delegation: bool) {
let mut context = program_test(enable_minimum_delegation)
.start_with_context()
.await;
let accounts = SinglePoolAccounts::default();
accounts.initialize(&mut context).await;

Expand All @@ -28,7 +33,7 @@ async fn success() {

#[tokio::test]
async fn fail_double_init() {
let mut context = program_test().start_with_context().await;
let mut context = program_test(false).start_with_context().await;
let accounts = SinglePoolAccounts::default();
let minimum_delegation = accounts.initialize(&mut context).await;
refresh_blockhash(&mut context).await;
Expand Down Expand Up @@ -56,4 +61,56 @@ async fn fail_double_init() {
check_error(e, SinglePoolError::PoolAlreadyInitialized);
}

#[test_case(true; "minimum_enabled")]
#[test_case(false; "minimum_disabled")]
#[tokio::test]
async fn fail_below_pool_minimum(enable_minimum_delegation: bool) {
let mut context = program_test(enable_minimum_delegation)
.start_with_context()
.await;
let accounts = SinglePoolAccounts::default();
let slot = context.genesis_config().epoch_schedule.first_normal_slot + 1;
context.warp_to_slot(slot).unwrap();

create_vote(
&mut context.banks_client,
&context.payer,
&context.last_blockhash,
&accounts.validator,
&accounts.voter.pubkey(),
&accounts.withdrawer.pubkey(),
&accounts.vote_account,
)
.await;

let rent = context.banks_client.get_rent().await.unwrap();
let minimum_delegation = get_pool_minimum_delegation(
&mut context.banks_client,
&context.payer,
&context.last_blockhash,
)
.await;

let instructions = instruction::initialize(
&id(),
&accounts.vote_account.pubkey(),
&context.payer.pubkey(),
&rent,
minimum_delegation - 1,
);
let transaction = Transaction::new_signed_with_payer(
&instructions,
Some(&context.payer.pubkey()),
&[&context.payer],
context.last_blockhash,
);

let e = context
.banks_client
.process_transaction(transaction)
.await
.unwrap_err();
check_error(e, SinglePoolError::WrongRentAmount);
}

// TODO test that init can succeed without mpl program
4 changes: 2 additions & 2 deletions single-pool/program/tests/reactivate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use {

#[tokio::test]
async fn success() {
let mut context = program_test().start_with_context().await;
let mut context = program_test(false).start_with_context().await;
let accounts = SinglePoolAccounts::default();
accounts
.initialize_for_deposit(&mut context, TEST_STAKE_AMOUNT, None)
Expand Down Expand Up @@ -131,7 +131,7 @@ async fn success() {
#[test_case(false; "activating")]
#[tokio::test]
async fn fail_not_deactivated(activate: bool) {
let mut context = program_test().start_with_context().await;
let mut context = program_test(false).start_with_context().await;
let accounts = SinglePoolAccounts::default();
accounts.initialize(&mut context).await;

Expand Down
6 changes: 3 additions & 3 deletions single-pool/program/tests/update_pool_token_metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const UPDATED_URI: &str = "updated_uri";

#[tokio::test]
async fn success_update_pool_token_metadata() {
let mut context = program_test().start_with_context().await;
let mut context = program_test(false).start_with_context().await;
let accounts = SinglePoolAccounts::default();
accounts.initialize(&mut context).await;

Expand Down Expand Up @@ -51,7 +51,7 @@ async fn success_update_pool_token_metadata() {

#[tokio::test]
async fn fail_no_signature() {
let mut context = program_test().start_with_context().await;
let mut context = program_test(false).start_with_context().await;
let accounts = SinglePoolAccounts::default();
accounts.initialize(&mut context).await;

Expand Down Expand Up @@ -92,7 +92,7 @@ enum BadWithdrawer {
#[test_case(BadWithdrawer::VoteAccount; "vote_account")]
#[tokio::test]
async fn fail_bad_withdrawer(withdrawer_type: BadWithdrawer) {
let mut context = program_test().start_with_context().await;
let mut context = program_test(false).start_with_context().await;
let accounts = SinglePoolAccounts::default();
accounts.initialize(&mut context).await;

Expand Down
Loading

0 comments on commit c01db92

Please sign in to comment.