Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactoring(gtest): Introduce gear_commons mailbox to gtest #4010

Merged
merged 47 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
47d5769
Port gas tree into gtest
techraed May 13, 2024
3e48d8b
Fix CI, introduce `System` singleton
techraed May 14, 2024
9bea502
Todos
techraed May 18, 2024
cf5ab4e
Fix auxiliary use
techraed May 20, 2024
85d479a
Trigger CI
techraed May 21, 2024
2211e7f
Fix tests
techraed May 21, 2024
ef5078e
Make `System` panic on second instance creation, adjust test
techraed Jun 3, 2024
5300294
Introduce alias, fmt
techraed Jun 3, 2024
cf0693d
feat(gtest): Introduce gas allowance to `gtest` (#3996)
techraed Jun 5, 2024
c429766
Apply review results #1
techraed Jun 6, 2024
768f0e0
Remove re-export
techraed Jun 6, 2024
c2906fc
feat(gear-common,gtest): Introduce proper mailbox for `gtest` (part 1…
techraed Jun 11, 2024
39f6ae5
Port gas tree into gtest
techraed May 13, 2024
1fc6d3d
Fix CI, introduce `System` singleton
techraed May 14, 2024
57f4722
Trigger CI
techraed May 21, 2024
ab1d30f
Make `System` panic on second instance creation, adjust test
techraed Jun 3, 2024
d36ee5f
Separate block info management
techraed Jun 4, 2024
72ce684
Introduce a separate auxiliary module for all auxiliary ds
techraed Jun 4, 2024
40137e1
Introduce auxiliary mailbox
techraed Jun 5, 2024
30c279d
Rename module
techraed Jun 5, 2024
1813b6d
Add docs, fmt
techraed Jun 6, 2024
52d4b6a
Fix check & clippy
techraed Jun 6, 2024
7dd7eb8
Port gas tree into gtest
techraed May 13, 2024
c762b14
Fix CI, introduce `System` singleton
techraed May 14, 2024
9704665
Trigger CI
techraed May 21, 2024
a9ee843
Make `System` panic on second instance creation, adjust test
techraed Jun 3, 2024
acd6b58
Separate block info management
techraed Jun 4, 2024
70c54bc
Introduce a separate auxiliary module for all auxiliary ds
techraed Jun 4, 2024
69866b0
Introduce auxiliary mailbox
techraed Jun 5, 2024
8337915
Introduce auxiliary mailbox to gtest
techraed Jun 6, 2024
83104f2
Unify usage of mailbox in gtest::manager
techraed Jun 6, 2024
7a148e4
fmt, remove redundant
techraed Jun 6, 2024
9a2db6b
Change `MailboxManager` insert type
techraed Jun 6, 2024
f24d4d0
Adjust mailbox logic in gtest so it uses auxiliary mailbox (prepare r…
techraed Jun 10, 2024
f31fd30
Fix cargo warnings and notes
techraed Jun 12, 2024
1bd26dc
Separate interface and manager modules
techraed Jun 12, 2024
07a02d3
Fix mailbox related tests in `gtest::program`
techraed Jun 12, 2024
d4b8d6c
Introduce claim_value test
techraed Jun 12, 2024
32d1686
Fix tests
techraed Jun 13, 2024
fcd56c0
Resolve some todos, adjust tests
techraed Jun 15, 2024
c577b31
Fix typo
techraed Jun 15, 2024
a2105b5
Merge branch 'master' of github.com:gear-tech/gear into st-gtest-mail…
techraed Jun 15, 2024
df2477c
rebase
techraed Jul 14, 2024
8256714
apply some of review results
techraed Jul 14, 2024
1e85938
make clippy happy
techraed Jul 15, 2024
2954392
Remove value claim from `System`, rename mailbox
techraed Jul 16, 2024
c27ca32
Remove module
techraed Jul 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion common/src/auxiliary/mailbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@

use crate::{
auxiliary::DoubleBTreeMap,
storage::{DoubleMapStorage, Interval, MailboxError, MailboxImpl, MailboxKeyGen},
storage::{
CountedByKey, DoubleMapStorage, GetSecondPos, Interval, IterableByKeyMap, IteratorWrap,
MailboxError, MailboxImpl, MailboxKeyGen,
},
};
use alloc::collections::btree_map::IntoIter;
use core::cell::RefCell;
use gear_core::{
ids::{MessageId, ProgramId},
Expand Down Expand Up @@ -97,6 +101,41 @@ impl DoubleMapStorage for MailboxStorageWrap {
}
}

impl CountedByKey for MailboxStorageWrap {
type Key = ProgramId;
type Length = usize;

fn len(key: &Self::Key) -> Self::Length {
MAILBOX_STORAGE.with_borrow(|map| map.count_key(key))
}
}

impl IterableByKeyMap<(MailboxedMessage, Interval<BlockNumber>)> for MailboxStorageWrap {
type Key = ProgramId;

type DrainIter = IteratorWrap<
IntoIter<MessageId, (MailboxedMessage, Interval<BlockNumber>)>,
(MailboxedMessage, Interval<BlockNumber>),
GetSecondPos,
>;

type Iter = IteratorWrap<
IntoIter<MessageId, (MailboxedMessage, Interval<BlockNumber>)>,
(MailboxedMessage, Interval<BlockNumber>),
GetSecondPos,
>;

fn drain_key(key: Self::Key) -> Self::DrainIter {
MAILBOX_STORAGE
.with_borrow_mut(|map| map.drain_key(&key))
.into()
}

fn iter_key(key: Self::Key) -> Self::Iter {
MAILBOX_STORAGE.with_borrow(|map| map.iter_key(&key)).into()
}
}

/// An implementor of the error returned from calling `Mailbox` trait functions.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum MailboxErrorImpl {
Expand Down
38 changes: 37 additions & 1 deletion common/src/auxiliary/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
pub mod gas_provider;
pub mod mailbox;

use alloc::collections::btree_map::{BTreeMap, Entry};
use alloc::collections::btree_map::{BTreeMap, Entry, IntoIter};

/// Double key `BTreeMap`.
///
Expand Down Expand Up @@ -52,6 +52,16 @@ impl<K1, K2, V> DoubleBTreeMap<K1, K2, V> {
.unwrap_or_default()
}

pub fn count_key(&self, key1: &K1) -> usize
where
K1: Ord,
{
self.inner
.get(key1)
.map(|key2_map| key2_map.len())
.unwrap_or_default()
}

/// Returns a reference to the value corresponding to the keys.
pub fn get(&self, key1: &K1, key2: &K2) -> Option<&V>
where
Expand Down Expand Up @@ -95,6 +105,32 @@ impl<K1, K2, V> DoubleBTreeMap<K1, K2, V> {
}
}

// Iterator related impl
impl<K1, K2, V> DoubleBTreeMap<K1, K2, V> {
pub fn iter_key(&self, key1: &K1) -> IntoIter<K2, V>
where
K1: Ord,
K2: Clone,
V: Clone,
{
self.inner
.get(key1)
.cloned()
.map(|key2_map| key2_map.into_iter())
.unwrap_or_default()
}

pub fn drain_key(&mut self, key1: &K1) -> IntoIter<K2, V>
where
K1: Ord,
{
self.inner
.remove(key1)
.map(|key2_map| key2_map.into_iter())
.unwrap_or_default()
}
}

impl<K1, K2, V> Default for DoubleBTreeMap<K1, K2, V> {
fn default() -> Self {
Self::new()
Expand Down
4 changes: 2 additions & 2 deletions common/src/gas_provider/property_tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@
//!
//! 14. Value catch can be performed only on consumed nodes (not tested).

use super::{auxiliary::gas_provider::*, *};
use crate::storage::MapStorage;
use super::*;
use crate::{auxiliary::gas_provider::*, storage::MapStorage};
use core::iter::FromIterator;
use enum_iterator::all;
use frame_support::{assert_err, assert_ok};
Expand Down
2 changes: 1 addition & 1 deletion examples/piggy-bank/src/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ extern "C" fn handle() {

if msg.expect("Failed to load payload bytes") == b"smash" {
debug!("smashing, total: {available_value}");
msg::reply_bytes(b"send", available_value).unwrap();
msg::send(msg::source(), b"send", available_value).unwrap();
}
});
}
81 changes: 67 additions & 14 deletions gtest/src/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,35 +29,42 @@ use crate::BLOCK_DURATION_IN_MSECS;
thread_local! {
/// Definition of the storage value storing block info (timestamp and height).
static BLOCK_INFO_STORAGE: RefCell<Option<BlockInfo>> = const { RefCell::new(None) };
techraed marked this conversation as resolved.
Show resolved Hide resolved
/// `BlocksManager` instances counter.
///
/// Used as a reference counter in order to nulify `BLOCK_INFO_STORAGE`,
/// if all instances are dropped.
static INSTANCES: RefCell<u32> = const { RefCell::new(0) };
}

/// Block info storage manager.
#[derive(Debug, Default)]
#[derive(Debug)]
pub(crate) struct BlocksManager(());

impl BlocksManager {
/// Create block info storage manager with a further initialization of the
/// storage.
pub(crate) fn new() -> Self {
BLOCK_INFO_STORAGE.with_borrow_mut(|block_info| {
let info = BlockInfo {
height: 0,
timestamp: now(),
};
INSTANCES.with_borrow_mut(|instances| {
*instances += 1;
});

block_info.replace(info);
BLOCK_INFO_STORAGE.with_borrow_mut(|block_info| {
if block_info.is_none() {
let info = BlockInfo {
height: 0,
timestamp: now(),
};

*block_info = Some(info)
}
});

Self(())
}

/// Get current block info.
pub(crate) fn get(&self) -> BlockInfo {
BLOCK_INFO_STORAGE.with_borrow(|cell| {
cell.as_ref()
.copied()
.expect("must be initialized in a `BlocksManager::new`")
})
BLOCK_INFO_STORAGE
.with_borrow(|cell| cell.as_ref().copied().expect("instance always initialized"))
}

/// Move blocks by one.
Expand All @@ -69,7 +76,7 @@ impl BlocksManager {
pub(crate) fn move_blocks_by(&self, amount: u32) -> BlockInfo {
BLOCK_INFO_STORAGE.with_borrow_mut(|block_info| {
let Some(block_info) = block_info.as_mut() else {
panic!("must initialized in a `BlocksManager::new`");
panic!("instance always initialized");
};
block_info.height += amount;
let duration = BLOCK_DURATION_IN_MSECS.saturating_mul(amount as u64);
Expand All @@ -80,9 +87,55 @@ impl BlocksManager {
}
}

impl Default for BlocksManager {
fn default() -> Self {
Self::new()
}
}

impl Drop for BlocksManager {
fn drop(&mut self) {
let remove_data = INSTANCES.with_borrow_mut(|instances| {
*instances = instances.saturating_sub(1);
ark0f marked this conversation as resolved.
Show resolved Hide resolved
*instances == 0
});

if remove_data {
BLOCK_INFO_STORAGE.with_borrow_mut(|block_info| {
*block_info = None;
})
}
}
}

fn now() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_millis() as u64
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_data_nullified_on_drop() {
let first_instance = BlocksManager::new();
let second_instance = BlocksManager::new();

first_instance.next_block();
first_instance.next_block();

// Assert all instance use same data;
assert_eq!(second_instance.get().height, 2);

// Drop first instance and check whether data is removed.
drop(first_instance);
assert_eq!(second_instance.get().height, 2);

drop(second_instance);
INSTANCES.with_borrow(|count| assert_eq!(*count, 0));
BLOCK_INFO_STORAGE.with_borrow(|maybe_bi| assert!(maybe_bi.is_none()));
}
}
2 changes: 1 addition & 1 deletion gtest/src/gas_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub(crate) type PositiveImbalance = <GasTree as Tree>::PositiveImbalance;
pub(crate) type NegativeImbalance = <GasTree as Tree>::NegativeImbalance;
type GasTree = <AuxiliaryGasProvider as Provider>::GasTree;

/// Gas tree manager which uses operates under the hood over
/// Gas tree manager which operates under the hood over
/// [`gear_common::AuxiliaryGasProvider`].
///
/// Manager is needed mainly to adapt arguments of the gas tree methods to the
Expand Down
1 change: 1 addition & 0 deletions gtest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ mod system;
pub use crate::log::{CoreLog, Log, RunResult};
pub use codec;
pub use error::{Result, TestError};
pub use mailbox::MailboxInterface;
pub use program::{
calculate_program_id, gbuild::ensure_gbuild, Gas, Program, ProgramBuilder, ProgramIdWrapper,
WasmProgram,
Expand Down
29 changes: 16 additions & 13 deletions gtest/src/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::program::{Gas, ProgramIdWrapper};
use codec::{Codec, Encode};
use gear_core::{
ids::{MessageId, ProgramId},
message::{Payload, StoredMessage},
message::{Payload, StoredMessage, UserStoredMessage},
};
use gear_core_errors::{ErrorReplyReason, ReplyCode, SimpleExecutionError, SuccessReplyReason};
use std::{collections::BTreeMap, convert::TryInto, fmt::Debug};
Expand Down Expand Up @@ -151,11 +151,11 @@ impl<T: Codec + Debug> DecodedCoreLog<T> {
/// ```
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
pub struct Log {
source: Option<ProgramId>,
destination: Option<ProgramId>,
payload: Option<Payload>,
reply_code: Option<ReplyCode>,
reply_to: Option<MessageId>,
pub(crate) source: Option<ProgramId>,
pub(crate) destination: Option<ProgramId>,
pub(crate) payload: Option<Payload>,
pub(crate) reply_code: Option<ReplyCode>,
pub(crate) reply_to: Option<MessageId>,
}

impl<ID, T> From<(ID, T)> for Log
Expand Down Expand Up @@ -283,22 +283,25 @@ impl Log {
}
}

impl PartialEq<StoredMessage> for Log {
fn eq(&self, other: &StoredMessage) -> bool {
if matches!(other.reply_details(), Some(reply) if Some(reply.to_reply_code()) != self.reply_code)
{
return false;
}
impl PartialEq<UserStoredMessage> for Log {
fn eq(&self, other: &UserStoredMessage) -> bool {
// Any log field is set.
let has_any = self.source.is_some() || self.destination.is_some() || self.payload.is_some();

// If any of log field doesn't match, then there's no equality.
if matches!(self.source, Some(source) if source != other.source()) {
return false;
}

if matches!(self.destination, Some(dest) if dest != other.destination()) {
return false;
}

if matches!(&self.payload, Some(payload) if payload.inner() != other.payload_bytes()) {
return false;
}
true

has_any
}
}

Expand Down
Loading
Loading