-
Notifications
You must be signed in to change notification settings - Fork 8
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
Add extra tests / examples of lockable ranges #58
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -264,13 +264,24 @@ mod tests_plus { | |
} | ||
|
||
#[derive(Error, Debug, PartialEq)] | ||
pub enum PersonError { | ||
pub enum TestsError { | ||
#[error("{0}")] | ||
Std(#[from] StdError), | ||
#[error("{0}")] | ||
Lock(#[from] LockError), | ||
} | ||
|
||
#[cw_serde] | ||
#[derive(Default)] | ||
pub struct UserInfo { | ||
// User collateral | ||
pub collateral: Uint128, | ||
// Highest user lien | ||
pub max_lien: Uint128, | ||
// Total slashable amount for user | ||
pub total_slashable: Uint128, | ||
} | ||
|
||
#[test] | ||
fn modify_item_with_locks() { | ||
let mut store = MockStorage::new(); | ||
|
@@ -285,7 +296,7 @@ mod tests_plus { | |
PERSON | ||
.update(&mut store, |mut p| { | ||
p.write()?.age += 1; | ||
Ok::<_, PersonError>(p) | ||
Ok::<_, TestsError>(p) | ||
}) | ||
.unwrap(); | ||
|
||
|
@@ -294,7 +305,7 @@ mod tests_plus { | |
.update(&mut store, |mut p| { | ||
assert_eq!(p.read()?.age, 33); | ||
p.lock_read()?; | ||
Ok::<_, PersonError>(p) | ||
Ok::<_, TestsError>(p) | ||
}) | ||
.unwrap(); | ||
|
||
|
@@ -312,7 +323,7 @@ mod tests_plus { | |
.update(&mut store, |mut p| { | ||
p.write()?.age += 1; | ||
assert_eq!(p.read()?.age, 34); | ||
Ok::<_, PersonError>(p) | ||
Ok::<_, TestsError>(p) | ||
}) | ||
.unwrap(); | ||
} | ||
|
@@ -332,23 +343,23 @@ mod tests_plus { | |
AGES.update(&mut store, "John", |p| { | ||
let mut p = p.unwrap_or_default(); | ||
*p.write()? += Uint128::new(1); | ||
Ok::<_, PersonError>(p) | ||
Ok::<_, TestsError>(p) | ||
}) | ||
.unwrap(); | ||
|
||
// Update works on new values, setting to unlocked by default | ||
AGES.update(&mut store, "Wilber", |p| { | ||
let mut p = p.unwrap_or_default(); | ||
*p.write()? += Uint128::new(2); | ||
Ok::<_, PersonError>(p) | ||
Ok::<_, TestsError>(p) | ||
}) | ||
.unwrap(); | ||
|
||
// We can range over them well | ||
let total_age = AGES | ||
.range(&store, None, None, cosmwasm_std::Order::Ascending) | ||
.fold(Ok(Uint128::zero()), |sum, item| { | ||
Ok::<_, PersonError>(sum? + *item?.1.read()?) | ||
Ok::<_, TestsError>(sum? + *item?.1.read()?) | ||
}) | ||
.unwrap(); | ||
assert_eq!(total_age, Uint128::new(33 + 47 + 2)); | ||
|
@@ -369,16 +380,16 @@ mod tests_plus { | |
.update(&mut store, "John", |p| { | ||
let mut p = p.unwrap_or_default(); | ||
*p.write()? += Uint128::new(1); | ||
Ok::<_, PersonError>(p) | ||
Ok::<_, TestsError>(p) | ||
}) | ||
.unwrap_err(); | ||
assert_eq!(err, PersonError::Lock(LockError::ReadLocked)); | ||
assert_eq!(err, TestsError::Lock(LockError::ReadLocked)); | ||
|
||
// We can still range over all | ||
let total_age = AGES | ||
.range(&store, None, None, cosmwasm_std::Order::Ascending) | ||
.fold(Ok(Uint128::zero()), |sum, item| { | ||
Ok::<_, PersonError>(sum? + *item?.1.read()?) | ||
Ok::<_, TestsError>(sum? + *item?.1.read()?) | ||
}) | ||
.unwrap(); | ||
assert_eq!(total_age, Uint128::new(33 + 47 + 2)); | ||
|
@@ -398,15 +409,140 @@ mod tests_plus { | |
let err = AGES | ||
.range(&store, None, None, cosmwasm_std::Order::Ascending) | ||
.fold(Ok(Uint128::zero()), |sum, item| { | ||
Ok::<_, PersonError>(sum? + *item?.1.read()?) | ||
Ok::<_, TestsError>(sum? + *item?.1.read()?) | ||
}) | ||
.unwrap_err(); | ||
assert_eq!(err, PersonError::Lock(LockError::WriteLocked)); | ||
assert_eq!(err, TestsError::Lock(LockError::WriteLocked)); | ||
|
||
// We can get count (kind of edge case bug, but I don't think we can change this or it matters) | ||
let num_people = AGES | ||
.range(&store, None, None, cosmwasm_std::Order::Ascending) | ||
.count(); | ||
assert_eq!(num_people, 3); | ||
} | ||
|
||
#[test] | ||
fn map_methods_with_locked_struct() { | ||
let mut store = MockStorage::new(); | ||
const USERS: Map<&str, Lockable<UserInfo>> = Map::new("users"); | ||
|
||
// add a few people | ||
USERS | ||
.save( | ||
&mut store, | ||
"John", | ||
&Lockable::new(UserInfo { | ||
collateral: Default::default(), | ||
max_lien: Default::default(), | ||
total_slashable: Default::default(), | ||
}), | ||
) | ||
.unwrap(); | ||
USERS | ||
.save( | ||
&mut store, | ||
"Maria", | ||
&Lockable::new(UserInfo { | ||
collateral: Uint128::new(1), | ||
max_lien: Uint128::new(2), | ||
total_slashable: Uint128::new(3), | ||
}), | ||
) | ||
.unwrap(); | ||
|
||
// Update works on new values, setting to unlocked by default | ||
USERS | ||
.update(&mut store, "Wilber", |p| { | ||
let mut p = p.unwrap_or_default(); | ||
*p.write()? = UserInfo { | ||
collateral: Uint128::new(4), | ||
max_lien: Uint128::new(5), | ||
total_slashable: Uint128::new(6), | ||
}; | ||
Ok::<_, TestsError>(p) | ||
}) | ||
.unwrap(); | ||
|
||
// Read-lock John | ||
let mut j = USERS.load(&store, "John").unwrap(); | ||
j.lock_read().unwrap(); | ||
USERS.save(&mut store, "John", &j).unwrap(); | ||
|
||
// We can still range over all | ||
let total_collateral = USERS | ||
.range(&store, None, None, cosmwasm_std::Order::Ascending) | ||
.fold(Ok(Uint128::zero()), |sum, item| { | ||
Ok::<_, TestsError>(sum? + item?.1.read()?.collateral) | ||
}) | ||
.unwrap(); | ||
assert_eq!(total_collateral, Uint128::new(1 + 4)); | ||
|
||
// We can get count | ||
let num_users = USERS | ||
.range(&store, None, None, cosmwasm_std::Order::Ascending) | ||
.count(); | ||
assert_eq!(num_users, 3); | ||
|
||
// Write-lock Wilber | ||
let mut w = USERS.load(&store, "Wilber").unwrap(); | ||
w.lock_write().unwrap(); | ||
USERS.save(&mut store, "Wilber", &w).unwrap(); | ||
|
||
// We cannot range over all | ||
let err = USERS | ||
.range(&store, None, None, cosmwasm_std::Order::Ascending) | ||
.fold(Ok(Uint128::zero()), |sum, item| { | ||
Ok::<_, TestsError>(sum? + item?.1.read()?.max_lien) | ||
}) | ||
.unwrap_err(); | ||
assert_eq!(err, TestsError::Lock(LockError::WriteLocked)); | ||
|
||
// We cannot range and map over all values either | ||
let err = USERS | ||
.range(&store, None, None, cosmwasm_std::Order::Ascending) | ||
.map(|item| { | ||
let (_, user_lock) = item?; | ||
let user = user_lock.read()?; | ||
Ok(user.collateral) | ||
}) | ||
.collect::<Result<Vec<_>, TestsError>>() | ||
.unwrap_err(); | ||
assert_eq!(err, TestsError::Lock(LockError::WriteLocked)); | ||
|
||
// But we can re-map (perhaps not a good idea) the write-locked values | ||
let collaterals: Vec<_> = USERS | ||
.range(&store, None, None, cosmwasm_std::Order::Ascending) | ||
.map(|item| { | ||
item.map(|(_, user_lock)| { | ||
user_lock | ||
.read() | ||
.map(|user| Ok(user.collateral)) | ||
.unwrap_or(Ok(Uint128::zero())) // Re-map locked collateral | ||
})? // Surface errors | ||
}) | ||
.collect::<Result<_, TestsError>>() | ||
.unwrap(); | ||
assert_eq!(collaterals.len(), 3); | ||
|
||
// Or we can skip (perhaps not a good idea either) the write-locked values | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reflecting more on this, I think the best would be to return: enum MaybeAccount {
Account(Account),
Locked{ user: String },
} Or something Similar. (Not sure how you use the keys). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍🏼 Will implement this for reference / as an example. |
||
let collaterals: Vec<_> = USERS | ||
.range(&store, None, None, cosmwasm_std::Order::Ascending) | ||
.filter(|item| { | ||
item.as_ref() | ||
.map(|(_, user_lock)| user_lock.read().map(|_| true).unwrap_or(false)) // Filter locked values | ||
.unwrap_or(true) // Surface other errors | ||
}) | ||
.map(|item| { | ||
item.map(|(_, user_lock)| user_lock.read().map(|user| Ok(user.collateral))?)? | ||
}) | ||
.collect::<Result<_, TestsError>>() | ||
.unwrap(); | ||
assert_eq!(collaterals.len(), 2); | ||
|
||
// We can get count (kind of edge case bug, but I don't think we can change this or it matters) | ||
let num_users = USERS | ||
.range(&store, None, None, cosmwasm_std::Order::Ascending) | ||
.count(); | ||
assert_eq!(num_users, 3); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice to explain what is and is not possible here