Skip to content

Commit

Permalink
add test which validates if vote with invalid choice would be rejecte…
Browse files Browse the repository at this point in the history
…d. (#3868)
  • Loading branch information
dkijania authored Mar 7, 2022
1 parent a268afa commit 27aaf32
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -803,3 +803,51 @@ pub fn non_duplicated_vote() {
vec![0, (*alice_account_state.value()).into(), 0],
);
}

#[test]
pub fn vote_outside_of_choices_is_rejected_in_tally() {
let mut alice = thor::Wallet::default();
let options_size = 2;

let vote_plan = VotePlanBuilder::new()
.proposals_count(1)
.options_size(options_size)
.action_type(VoteAction::OffChain)
.vote_start(BlockDate::from_epoch_slot_id(1, 0))
.tally_start(BlockDate::from_epoch_slot_id(2, 0))
.tally_end(BlockDate::from_epoch_slot_id(3, 0))
.public()
.build();

let minting_policy = MintingPolicy::new();
let token_id = vote_plan.voting_token();

let jormungandr = startup::start_bft(
vec![&alice],
ConfigurationBuilder::new()
.with_slots_per_epoch(10)
.with_slot_duration(2)
.with_linear_fees(LinearFee::new(0, 0, 0))
.with_token(InitialToken {
token_id: token_id.clone().into(),
policy: minting_policy.into(),
to: vec![alice.to_initial_token(1_000_000_000)],
}),
)
.unwrap();

thor::FragmentChainSender::from_with_setup(
jormungandr.block0_configuration(),
jormungandr.to_remote(),
FragmentSenderSetup::no_verify(),
)
.send_vote_plan(&mut alice, &vote_plan)
.unwrap()
.and_verify_is_in_block(Duration::from_secs(2))
.unwrap()
.then_wait_for_epoch(1)
.cast_vote(&mut alice, &vote_plan, 0, &Choice::new(options_size))
.unwrap()
.and_verify_is_rejected_with_message(Duration::from_secs(2), "Invalid option choice")
.unwrap();
}
14 changes: 14 additions & 0 deletions testing/thor/src/fragment/chain_sender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,20 @@ impl<'a, S: SyncNode + Send> FragmentChainSender<'a, S> {
Ok(self)
}

pub fn and_verify_is_rejected_with_message(
self,
duration: std::time::Duration,
message: impl Into<String>,
) -> Result<Self, FragmentChainSenderError> {
FragmentVerifier::wait_and_verify_is_rejected_with_message(
duration,
self.get_last_mempool_check()?,
message,
&self.node,
)?;
Ok(self)
}

pub fn update_wallet(self, wallet: &mut Wallet, f: &dyn Fn(&mut Wallet)) -> Self {
f(wallet);
self
Expand Down
38 changes: 38 additions & 0 deletions testing/thor/src/fragment/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ pub enum FragmentVerifierError {
#[debug(skip)]
logs: Vec<String>,
},
#[error("cannot match rejection reason '{message}' does not contains '{expected_part}'")]
UnexpectedRejectionReason {
message: String,
expected_part: String,
},
#[error("fragment sent to node: {alias} is not rejected :({status:?})")]
FragmentNotRejected {
alias: String,
Expand Down Expand Up @@ -73,6 +78,7 @@ impl FragmentVerifierError {
AtLeastOneRejectedFragment { logs, .. } => Some(logs),
TimeoutReachedWhileWaitingForAllFragmentsInBlock { logs } => Some(logs),
FragmentNode(_) => None,
UnexpectedRejectionReason { .. } => None,
};
maybe_logs
.into_iter()
Expand Down Expand Up @@ -146,6 +152,16 @@ impl FragmentVerifier {
Self::is_rejected(status, node)
}

pub fn wait_and_verify_is_rejected_with_message<A: FragmentNode + ?Sized, S: Into<String>>(
duration: Duration,
check: MemPoolCheck,
message: S,
node: &A,
) -> Result<(), FragmentVerifierError> {
let status = Self::wait_fragment(duration, check, Default::default(), node)?;
Self::is_rejected_with_message(status, message, node)
}

pub fn is_in_block<A: FragmentNode + ?Sized>(
status: FragmentStatus,
node: &A,
Expand Down Expand Up @@ -174,6 +190,28 @@ impl FragmentVerifier {
Ok(())
}

pub fn is_rejected_with_message<A: FragmentNode + ?Sized, S: Into<String>>(
status: FragmentStatus,
expected_part: S,
node: &A,
) -> Result<(), FragmentVerifierError> {
if let FragmentStatus::Rejected { reason } = status {
let expected_part = expected_part.into();
reason.contains(&expected_part).then(|| ()).ok_or(
FragmentVerifierError::UnexpectedRejectionReason {
message: reason,
expected_part,
},
)
} else {
Err(FragmentVerifierError::FragmentNotRejected {
alias: node.alias(),
status,
logs: node.log_content(),
})
}
}

pub fn fragment_status<A: FragmentNode + ?Sized>(
check: MemPoolCheck,
node: &A,
Expand Down

0 comments on commit 27aaf32

Please sign in to comment.