#![cfg(test)]
use crate::{core_mask::*, mock::*, *};
use pezframe_support::{
assert_noop, assert_ok,
traits::nonfungible::{Inspect as NftInspect, Mutate, Transfer},
BoundedVec,
};
use pezframe_system::RawOrigin::Root;
use pezsp_runtime::{
traits::{BadOrigin, Get},
Perbill, TokenError,
};
use pretty_assertions::assert_eq;
use CoreAssignment::*;
use CoretimeTraceItem::*;
use Finality::*;
#[test]
fn basic_initialize_works() {
TestExt::new().execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
assert_eq!(CoretimeTrace::get(), vec![]);
assert_eq!(Broker::current_timeslice(), 0);
});
}
#[test]
fn drop_region_works() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_ok!(Broker::do_assign(region, Some(1), 1001, Provisional));
advance_to(11);
assert_noop!(Broker::do_drop_region(region), Error::<Test>::StillValid);
advance_to(12);
let just_1001 = vec![(Task(1001), 57600)];
let just_pool = vec![(Pool, 57600)];
assert_eq!(
CoretimeTrace::get(),
vec![
(6, AssignCore { core: 0, begin: 8, assignment: just_1001, end_hint: None }),
(12, AssignCore { core: 0, begin: 14, assignment: just_pool, end_hint: None }),
]
);
assert_eq!(Regions::<Test>::iter().count(), 1);
assert_ok!(Broker::do_drop_region(region));
assert_eq!(Regions::<Test>::iter().count(), 0);
assert_noop!(Broker::do_drop_region(region), Error::<Test>::UnknownRegion);
});
}
#[test]
fn drop_renewal_works() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_ok!(Broker::do_assign(region, Some(1), 1001, Final));
advance_to(11);
let e = Error::<Test>::StillValid;
assert_noop!(Broker::do_drop_renewal(region.core, region.begin + 3), e);
advance_to(12);
assert_eq!(PotentialRenewals::<Test>::iter().count(), 1);
assert_ok!(Broker::do_drop_renewal(region.core, region.begin + 3));
assert_eq!(PotentialRenewals::<Test>::iter().count(), 0);
let e = Error::<Test>::UnknownRenewal;
assert_noop!(Broker::do_drop_renewal(region.core, region.begin + 3), e);
});
}
#[test]
fn drop_contribution_works() {
TestExt::new().contribution_timeout(3).endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_ok!(Broker::do_pool(region, Some(1), 1, Final));
assert_eq!(InstaPoolContribution::<Test>::iter().count(), 1);
advance_to(19);
assert_noop!(Broker::do_drop_contribution(region), Error::<Test>::StillValid);
advance_to(20);
assert_ok!(Broker::do_drop_contribution(region));
assert_eq!(InstaPoolContribution::<Test>::iter().count(), 0);
assert_noop!(Broker::do_drop_contribution(region), Error::<Test>::UnknownContribution);
});
}
#[test]
fn drop_history_works() {
TestExt::new()
.contribution_timeout(4)
.endow(1, 1000)
.endow(2, 50)
.execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let mut region = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_ok!(Broker::do_pool(region, Some(1), 1, Final));
assert_ok!(Broker::do_purchase_credit(2, 50, 2));
advance_to(6);
assert_eq!(InstaPoolHistory::<Test>::iter().count(), 3);
advance_to(7);
assert_eq!(InstaPoolHistory::<Test>::iter().count(), 2);
advance_to(8);
assert_eq!(InstaPoolHistory::<Test>::iter().count(), 3);
assert_ok!(TestCoretimeProvider::spend_instantaneous(2, 10));
advance_to(10);
assert_eq!(InstaPoolHistory::<Test>::iter().count(), 3);
assert_ok!(TestCoretimeProvider::spend_instantaneous(2, 10));
advance_to(12);
assert_eq!(InstaPoolHistory::<Test>::iter().count(), 4);
assert_ok!(TestCoretimeProvider::spend_instantaneous(2, 10));
advance_to(14);
assert_eq!(InstaPoolHistory::<Test>::iter().count(), 5);
advance_to(16);
assert_eq!(InstaPoolHistory::<Test>::iter().count(), 6);
advance_to(17);
assert_noop!(Broker::do_drop_history(u32::MAX), Error::<Test>::StillValid);
assert_noop!(Broker::do_drop_history(region.begin), Error::<Test>::StillValid);
advance_to(18);
assert_eq!(InstaPoolHistory::<Test>::iter().count(), 6);
assert_ok!(Broker::do_drop_history(region.begin));
assert_eq!(InstaPoolHistory::<Test>::iter().count(), 5);
assert_noop!(Broker::do_drop_history(region.begin), Error::<Test>::NoHistory);
advance_to(19);
region.begin += 1;
assert_noop!(Broker::do_drop_history(region.begin), Error::<Test>::StillValid);
advance_to(20);
assert_ok!(Broker::do_drop_history(region.begin));
assert_eq!(InstaPoolHistory::<Test>::iter().count(), 4);
assert_noop!(Broker::do_drop_history(region.begin), Error::<Test>::NoHistory);
advance_to(21);
region.begin += 1;
assert_noop!(Broker::do_drop_history(region.begin), Error::<Test>::StillValid);
advance_to(22);
assert_ok!(Broker::do_drop_history(region.begin));
assert_eq!(InstaPoolHistory::<Test>::iter().count(), 3);
assert_noop!(Broker::do_drop_history(region.begin), Error::<Test>::NoHistory);
});
}
#[test]
fn request_core_count_works() {
TestExt::new().execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 0));
assert_ok!(Broker::request_core_count(RuntimeOrigin::root(), 1));
advance_to(12);
let assignment = vec![(Pool, 57600)];
assert_eq!(
CoretimeTrace::get(),
vec![(12, AssignCore { core: 0, begin: 14, assignment, end_hint: None })],
);
});
}
#[test]
fn transfer_works() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_ok!(<Broker as Transfer<_>>::transfer(®ion.into(), &2));
assert_eq!(<Broker as NftInspect<_>>::owner(®ion.into()), Some(2));
assert_noop!(Broker::do_assign(region, Some(1), 1001, Final), Error::<Test>::NotOwner);
assert_ok!(Broker::do_assign(region, Some(2), 1002, Final));
});
}
#[test]
fn mutate_operations_work() {
TestExt::new().endow(1, 1000).execute_with(|| {
let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() };
assert_noop!(
<Broker as Mutate<_>>::mint_into(®ion_id.into(), &2),
Error::<Test>::UnknownRegion
);
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region_id = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_noop!(
<Broker as Mutate<_>>::mint_into(®ion_id.into(), &2),
Error::<Test>::NotAllowed
);
assert_noop!(
<Broker as Mutate<_>>::burn(®ion_id.into(), Some(&2)),
Error::<Test>::NotOwner
);
assert_ok!(<Broker as Mutate<_>>::burn(®ion_id.into(), Some(&1)));
assert_eq!(Regions::<Test>::get(region_id).unwrap().owner, None);
assert_ok!(<Broker as Mutate<_>>::mint_into(®ion_id.into(), &2));
assert_eq!(Regions::<Test>::get(region_id).unwrap().owner, Some(2));
assert_noop!(
<Broker as Mutate<_>>::set_attribute(®ion_id.into(), &[], &[]),
TokenError::Unsupported
);
assert_noop!(
<Broker as Mutate<_>>::set_typed_attribute::<u8, u8>(®ion_id.into(), &0, &0),
TokenError::Unsupported
);
});
}
#[test]
fn mutate_operations_work_with_partitioned_region() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
let (region1, _region2) = Broker::do_partition(region, None, 2).unwrap();
let record_1 = Regions::<Test>::get(region1).unwrap();
assert_ok!(<Broker as Mutate<_>>::burn(®ion1.into(), Some(&1)));
assert_eq!(Regions::<Test>::get(region1).unwrap().owner, None);
assert_ok!(<Broker as Mutate<_>>::mint_into(®ion1.into(), &1));
assert_eq!(Regions::<Test>::get(region1).unwrap(), record_1);
});
}
#[test]
fn mutate_operations_work_with_interlaced_region() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
let (region1, _region2) =
Broker::do_interlace(region, None, CoreMask::from_chunk(0, 40)).unwrap();
let record_1 = Regions::<Test>::get(region1).unwrap();
assert_ok!(<Broker as Mutate<_>>::burn(®ion1.into(), Some(&1)));
assert_eq!(Regions::<Test>::get(region1).unwrap().owner, None);
assert_ok!(<Broker as Mutate<_>>::mint_into(®ion1.into(), &1));
assert_eq!(Regions::<Test>::get(region1).unwrap(), record_1);
});
}
#[test]
fn permanent_is_not_reassignable() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_ok!(Broker::do_assign(region, Some(1), 1001, Final));
assert_noop!(Broker::do_assign(region, Some(1), 1002, Final), Error::<Test>::UnknownRegion);
assert_noop!(Broker::do_pool(region, Some(1), 1002, Final), Error::<Test>::UnknownRegion);
assert_noop!(Broker::do_partition(region, Some(1), 1), Error::<Test>::UnknownRegion);
assert_noop!(
Broker::do_interlace(region, Some(1), CoreMask::from_chunk(0, 40)),
Error::<Test>::UnknownRegion
);
});
}
#[test]
fn provisional_is_reassignable() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_ok!(Broker::do_assign(region, Some(1), 1001, Provisional));
let (region1, region) = Broker::do_partition(region, Some(1), 1).unwrap();
let (region2, region3) =
Broker::do_interlace(region, Some(1), CoreMask::from_chunk(0, 40)).unwrap();
assert_ok!(Broker::do_pool(region1, Some(1), 1, Provisional));
assert_ok!(Broker::do_assign(region2, Some(1), 1002, Provisional));
assert_ok!(Broker::do_assign(region3, Some(1), 1003, Provisional));
advance_to(8);
assert_eq!(
CoretimeTrace::get(),
vec![
(
6,
AssignCore {
core: 0,
begin: 8,
assignment: vec![(Pool, 57600),],
end_hint: None
}
),
(
8,
AssignCore {
core: 0,
begin: 10,
assignment: vec![(Task(1002), 28800), (Task(1003), 28800),],
end_hint: None
}
),
]
);
});
}
#[test]
fn nft_metadata_works() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_eq!(attribute::<Timeslice>(region, b"begin"), 4);
assert_eq!(attribute::<Timeslice>(region, b"length"), 3);
assert_eq!(attribute::<Timeslice>(region, b"end"), 7);
assert_eq!(attribute::<Option<u64>>(region, b"owner"), Some(1));
assert_eq!(attribute::<CoreMask>(region, b"part"), 0xfffff_fffff_fffff_fffff.into());
assert_eq!(attribute::<CoreIndex>(region, b"core"), 0);
assert_eq!(attribute::<Option<u64>>(region, b"paid"), Some(100));
assert_ok!(Broker::do_transfer(region, None, 42));
let (_, region) = Broker::do_partition(region, None, 2).unwrap();
let (region, _) =
Broker::do_interlace(region, None, 0x00000_fffff_fffff_00000.into()).unwrap();
assert_eq!(attribute::<Timeslice>(region, b"begin"), 6);
assert_eq!(attribute::<Timeslice>(region, b"length"), 1);
assert_eq!(attribute::<Timeslice>(region, b"end"), 7);
assert_eq!(attribute::<Option<u64>>(region, b"owner"), Some(42));
assert_eq!(attribute::<CoreMask>(region, b"part"), 0x00000_fffff_fffff_00000.into());
assert_eq!(attribute::<CoreIndex>(region, b"core"), 0);
assert_eq!(attribute::<Option<u64>>(region, b"paid"), None);
});
}
#[test]
fn migration_works() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_set_lease(1000, 8));
assert_ok!(Broker::do_start_sales(100, 1));
assert_noop!(Broker::do_renew(1, 0), Error::<Test>::NotAllowed);
advance_to(12);
assert_ok!(Broker::do_renew(1, 0));
assert_eq!(balance(1), 900);
advance_to(18);
let just_pool = || vec![(Pool, 57600)];
let just_1000 = || vec![(Task(1000), 57600)];
assert_eq!(
CoretimeTrace::get(),
vec![
(6, AssignCore { core: 0, begin: 8, assignment: just_1000(), end_hint: None }),
(6, AssignCore { core: 1, begin: 8, assignment: just_pool(), end_hint: None }),
(12, AssignCore { core: 0, begin: 14, assignment: just_1000(), end_hint: None }),
(12, AssignCore { core: 1, begin: 14, assignment: just_pool(), end_hint: None }),
(18, AssignCore { core: 0, begin: 20, assignment: just_1000(), end_hint: None }),
(18, AssignCore { core: 1, begin: 20, assignment: just_pool(), end_hint: None }),
]
);
});
}
#[test]
fn renewal_works() {
let b = 100_000;
TestExt::new().endow(1, b).execute_with(move || {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_eq!(balance(1), 99_900);
assert_ok!(Broker::do_assign(region, None, 1001, Final));
advance_to(6);
assert_noop!(Broker::do_purchase(1, u64::max_value()), Error::<Test>::TooEarly);
let core = Broker::do_renew(1, region.core).unwrap();
assert_eq!(balance(1), 99_800);
advance_to(8);
assert_noop!(Broker::do_purchase(1, u64::max_value()), Error::<Test>::SoldOut);
advance_to(12);
assert_ok!(Broker::do_renew(1, core));
assert_eq!(balance(1), 99_690);
});
}
#[test]
fn renewals_affect_price() {
pezsp_tracing::try_init_simple();
let b = 100_000;
let config = ConfigRecord {
advance_notice: 2,
interlude_length: 10,
leadin_length: 20,
ideal_bulk_proportion: Perbill::from_percent(100),
limit_cores_offered: None,
region_length: 20,
renewal_bump: Perbill::from_percent(10),
contribution_timeout: 5,
};
TestExt::new_with_config(config).endow(1, b).execute_with(|| {
let price = 910;
assert_ok!(Broker::do_start_sales(10, 1));
advance_to(11);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
let b = b - price;
assert_eq!(balance(1), b);
assert_ok!(Broker::do_assign(region, None, 1001, Final));
advance_to(40);
assert_noop!(Broker::do_purchase(1, u64::max_value()), Error::<Test>::TooEarly);
let core = Broker::do_renew(1, region.core).unwrap();
let b = b - price;
assert_eq!(balance(1), b);
advance_to(51);
assert_noop!(Broker::do_purchase(1, u64::max_value()), Error::<Test>::SoldOut);
advance_to(81);
assert_ok!(Broker::do_renew(1, core));
let price = price + Perbill::from_percent(10) * price;
let b = b - price;
assert_eq!(balance(1), b);
advance_to(159);
Broker::do_renew(1, region.core).unwrap();
let price = price + Perbill::from_percent(10) * price;
let b = b - price;
assert_eq!(balance(1), b);
advance_to(161);
Broker::do_renew(1, region.core).unwrap();
let price = 100;
let b = b - price;
assert_eq!(balance(1), b);
advance_to(201);
Broker::do_renew(1, region.core).unwrap();
let price = 110;
let b = b - price;
assert_eq!(balance(1), b);
});
}
#[test]
fn renewal_price_adjusts_to_lower_market_end() {
pezsp_tracing::try_init_simple();
let b = 100_000_000;
let region_length_blocks = 40;
let config = ConfigRecord {
advance_notice: 2,
interlude_length: 10,
leadin_length: 20,
ideal_bulk_proportion: Perbill::from_percent(100),
limit_cores_offered: None,
region_length: 20,
renewal_bump: Perbill::from_percent(10),
contribution_timeout: 5,
};
TestExt::new_with_config(config.clone())
.endow(1, b)
.endow(2, b)
.execute_with(|| {
let price = 910;
assert_ok!(Broker::do_start_sales(10, 2));
advance_to(11);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
let b = b - price;
assert_eq!(balance(1), b);
assert_ok!(Broker::do_assign(region, None, 1001, Final));
advance_to(region_length_blocks);
assert_noop!(Broker::do_purchase(1, u64::max_value()), Error::<Test>::TooEarly);
let core = Broker::do_renew(1, region.core).unwrap();
let b = b - price;
assert_eq!(balance(1), b);
advance_to(region_length_blocks + config.interlude_length + 1);
Broker::do_purchase(2, u64::max_value()).unwrap();
advance_to(2 * region_length_blocks);
assert_ok!(Broker::do_renew(1, core));
let price = price + Perbill::from_percent(10) * price;
let b = b - price;
assert_eq!(balance(1), b);
advance_to(2 * region_length_blocks + config.interlude_length + 1);
Broker::do_purchase(2, u64::max_value()).unwrap();
advance_to(3 * region_length_blocks);
assert_ok!(Broker::do_renew(1, core));
let price = price + Perbill::from_percent(10) * price;
let b = b - price;
assert_eq!(balance(1), b);
let end_price = SaleInfo::<Test>::get().unwrap().end_price;
advance_to(4 * region_length_blocks);
assert_ok!(Broker::do_renew(1, core));
let price = end_price;
let b = b - price;
assert_eq!(balance(1), b);
});
}
#[test]
fn instapool_payouts_work() {
TestExt::new().endow(1, 1000).execute_with(|| {
let item = ScheduleItem { assignment: Pool, mask: CoreMask::complete() };
assert_ok!(Broker::do_reserve(Schedule::truncate_from(vec![item])));
assert_ok!(Broker::do_start_sales(100, 2));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_eq!(revenue(), 100);
assert_ok!(Broker::do_pool(region, None, 2, Final));
assert_ok!(Broker::do_purchase_credit(1, 20, 1));
assert_eq!(pot(), 0);
assert_eq!(revenue(), 100);
advance_to(8);
assert_ok!(TestCoretimeProvider::spend_instantaneous(1, 10));
advance_to(11);
assert_eq!(pot(), 4);
assert_eq!(revenue(), 106);
assert_noop!(Broker::do_claim_revenue(region, 0), Error::<Test>::NoClaimTimeslices);
assert_ok!(Broker::do_claim_revenue(region, 100));
assert_eq!(pot(), 0);
assert_eq!(revenue(), 106);
assert_eq!(balance(2), 4);
});
}
#[test]
fn instapool_partial_core_payouts_work() {
TestExt::new().endow(1, 1000).execute_with(|| {
let item = ScheduleItem { assignment: Pool, mask: CoreMask::complete() };
assert_ok!(Broker::do_reserve(Schedule::truncate_from(vec![item])));
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
let (region1, region2) =
Broker::do_interlace(region, None, CoreMask::from_chunk(0, 20)).unwrap();
assert_ok!(Broker::do_pool(region1, None, 2, Final));
assert_ok!(Broker::do_pool(region2, None, 3, Final));
assert_ok!(Broker::do_purchase_credit(1, 40, 1));
assert_eq!(pot(), 0);
assert_eq!(revenue(), 100);
advance_to(8);
assert_ok!(TestCoretimeProvider::spend_instantaneous(1, 40));
advance_to(11);
assert_eq!(pot(), 20);
assert_ok!(Broker::do_claim_revenue(region1, 100));
assert_ok!(Broker::do_claim_revenue(region2, 100));
assert_eq!(balance(2), 5);
assert_eq!(balance(3), 15);
assert_eq!(pot(), 0);
assert_eq!(revenue(), 120);
});
}
#[test]
fn instapool_core_payouts_work_with_partitioned_region() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_eq!(revenue(), 100);
let (region1, region2) = Broker::do_partition(region, None, 2).unwrap();
assert_ok!(Broker::do_pool(region1, None, 2, Final));
assert_ok!(Broker::do_pool(region2, None, 3, Final));
assert_ok!(Broker::do_purchase_credit(1, 20, 1));
assert_eq!(pot(), 0);
assert_eq!(revenue(), 100);
advance_to(8);
assert_ok!(TestCoretimeProvider::spend_instantaneous(1, 10));
advance_to(11);
assert_eq!(pot(), 10);
assert_eq!(revenue(), 100);
assert_ok!(Broker::do_claim_revenue(region1, 100));
assert_eq!(pot(), 0);
assert_eq!(balance(2), 10);
advance_to(12);
assert_ok!(TestCoretimeProvider::spend_instantaneous(1, 10));
advance_to(15);
assert_eq!(pot(), 10);
assert_ok!(Broker::do_claim_revenue(region2, 100));
assert_eq!(pot(), 0);
assert_eq!(balance(2), 10);
assert_eq!(balance(3), 10);
});
}
#[test]
fn instapool_payouts_cannot_be_duplicated_through_partition() {
TestExt::new().endow(1, 1000).execute_with(|| {
let item = ScheduleItem { assignment: Pool, mask: CoreMask::complete() };
assert_ok!(Broker::do_reserve(Schedule::truncate_from(vec![item])));
assert_ok!(Broker::do_start_sales(100, 3));
advance_to(2);
let region_id = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_eq!(revenue(), 100);
let region = Regions::<Test>::get(®ion_id).unwrap();
assert_eq!(
InstaPoolIo::<Test>::get(region_id.begin),
PoolIoRecord { private: 0, system: 80 }
);
assert_eq!(InstaPoolIo::<Test>::get(region.end), PoolIoRecord { private: 0, system: -80 });
assert_ok!(Broker::do_pool(region_id, None, 2, Provisional));
assert_eq!(
InstaPoolContribution::<Test>::get(region_id),
Some(ContributionRecord { length: 3, payee: 2 })
);
assert_eq!(
InstaPoolIo::<Test>::get(region_id.begin),
PoolIoRecord { private: 80, system: 80 }
);
assert_eq!(
InstaPoolIo::<Test>::get(region.end),
PoolIoRecord { private: -80, system: -80 }
);
assert_ok!(Broker::do_partition(region_id, None, 1));
assert_eq!(InstaPoolContribution::<Test>::get(region_id), None);
assert_eq!(
InstaPoolIo::<Test>::get(region_id.begin),
PoolIoRecord { private: 0, system: 80 }
);
assert_eq!(InstaPoolIo::<Test>::get(region.end), PoolIoRecord { private: 0, system: -80 });
assert_ok!(Broker::do_purchase_credit(1, 20, 1));
assert_eq!(pot(), 0);
assert_eq!(revenue(), 100);
advance_to(8);
assert_ok!(TestCoretimeProvider::spend_instantaneous(1, 10));
advance_to(11);
assert_eq!(pot(), 0);
assert_eq!(revenue(), 110);
assert_noop!(Broker::do_claim_revenue(region_id, 100), Error::<Test>::UnknownContribution);
assert_eq!(pot(), 0);
assert_eq!(revenue(), 110);
assert_eq!(balance(2), 0);
});
}
#[test]
fn insta_pool_history_works() {
TestExt::new().endow(1, 1000).execute_with(|| {
type Io = InstaPoolIo<Test>;
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region_id = Broker::do_purchase(1, u64::max_value()).unwrap();
let region = Regions::<Test>::get(®ion_id).unwrap();
assert_eq!(Io::get(region_id.begin), PoolIoRecord { private: 0, system: 0 });
assert_eq!(Io::get(region.end), PoolIoRecord { private: 0, system: 0 });
assert_eq!(region_id.begin, 4);
assert_ok!(Broker::do_pool(region_id, None, 2, Provisional));
assert_eq!(Io::get(region_id.begin), PoolIoRecord { private: 80, system: 0 });
assert_eq!(Io::get(region.end), PoolIoRecord { private: -80, system: 0 });
let timeslice_period: u64 = <Test as Config>::TimeslicePeriod::get();
let expected_private_history = vec![0, 0, 0, 80, 80, 80, 0];
let actual_private_history: Vec<_> = (1..8)
.map(|timeslice| {
advance_to(timeslice as u64 * timeslice_period);
InstaPoolHistory::<Test>::get(timeslice).unwrap().private_contributions
})
.collect();
assert_eq!(actual_private_history, expected_private_history);
System::assert_has_event(
Event::HistoryInitialized { when: 1, private_pool_size: 0, system_pool_size: 0 }.into(),
);
System::assert_has_event(
Event::HistoryInitialized { when: 2, private_pool_size: 0, system_pool_size: 0 }.into(),
);
System::assert_has_event(
Event::HistoryInitialized { when: 3, private_pool_size: 0, system_pool_size: 0 }.into(),
);
System::assert_has_event(
Event::HistoryInitialized { when: 4, private_pool_size: 80, system_pool_size: 0 }
.into(),
);
System::assert_has_event(
Event::HistoryInitialized { when: 5, private_pool_size: 80, system_pool_size: 0 }
.into(),
);
System::assert_has_event(
Event::HistoryInitialized { when: 6, private_pool_size: 80, system_pool_size: 0 }
.into(),
);
System::assert_has_event(
Event::HistoryInitialized { when: 7, private_pool_size: 0, system_pool_size: 80 }
.into(),
);
});
}
#[test]
fn force_unpool_works() {
TestExt::new().endow(1, 1000).execute_with(|| {
type Io = InstaPoolIo<Test>;
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
System::assert_has_event(
Event::HistoryInitialized { when: 1, private_pool_size: 0, system_pool_size: 0 }.into(),
);
let region_id = Broker::do_purchase(1, u64::max_value()).unwrap();
let region = Regions::<Test>::get(®ion_id).unwrap();
assert_eq!(Io::get(region_id.begin), PoolIoRecord { private: 0, system: 0 });
assert_eq!(Io::get(region.end), PoolIoRecord { private: 0, system: 0 });
assert_ok!(Broker::do_pool(region_id, None, 2, Provisional));
assert_eq!(Io::get(region_id.begin), PoolIoRecord { private: 80, system: 0 });
assert_eq!(Io::get(region.end), PoolIoRecord { private: -80, system: 0 });
let status = Status::<Test>::get().unwrap();
Broker::force_unpool_region(region_id, ®ion, &status);
System::assert_last_event(
Event::<Test>::RegionUnpooled { region_id, when: region_id.begin }.into(),
);
assert_eq!(Io::get(Broker::current_timeslice()), PoolIoRecord { private: 0, system: 0 });
assert_eq!(Io::get(region_id.begin), PoolIoRecord { private: 0, system: 0 });
InstaPoolHistory::<Test>::get(Broker::current_timeslice())
.map(|record| record.private_contributions);
assert_ok!(Broker::do_pool(region_id, None, 2, Provisional));
assert_eq!(Io::get(region_id.begin), PoolIoRecord { private: 80, system: 0 });
let timeslice_period: u64 = <Test as Config>::TimeslicePeriod::get();
advance_to(3 * timeslice_period);
let current_timeslice = Broker::current_timeslice();
System::assert_has_event(
Event::HistoryInitialized { when: 2, private_pool_size: 0, system_pool_size: 0 }.into(),
);
System::assert_has_event(
Event::HistoryInitialized { when: 3, private_pool_size: 0, system_pool_size: 0 }.into(),
);
System::assert_has_event(
Event::HistoryInitialized { when: 4, private_pool_size: 80, system_pool_size: 0 }
.into(),
);
assert_eq!(Io::get(region.end), PoolIoRecord { private: -80, system: 0 });
assert_eq!(Io::get(current_timeslice), PoolIoRecord { private: 0, system: 0 });
let status = Status::<Test>::get().unwrap();
Broker::force_unpool_region(region_id, ®ion, &status);
System::assert_last_event(
Event::<Test>::RegionUnpooled { region_id, when: current_timeslice + 2 }.into(),
);
assert_eq!(Io::get(region.end), PoolIoRecord { private: 0, system: 0 });
assert_eq!(Io::get(current_timeslice + 2), PoolIoRecord { private: -80, system: 0 });
advance_sale_period();
System::assert_has_event(
Event::HistoryInitialized { when: 5, private_pool_size: 0, system_pool_size: 0 }.into(),
);
System::assert_has_event(
Event::HistoryInitialized { when: 6, private_pool_size: 0, system_pool_size: 0 }.into(),
);
System::assert_has_event(
Event::HistoryInitialized { when: 7, private_pool_size: 0, system_pool_size: 80 }
.into(),
);
});
}
#[test]
fn instapool_payouts_cannot_be_duplicated_through_interlacing() {
TestExt::new().endow(1, 1000).execute_with(|| {
let item = ScheduleItem { assignment: Pool, mask: CoreMask::complete() };
assert_ok!(Broker::do_reserve(Schedule::truncate_from(vec![item])));
assert_ok!(Broker::do_start_sales(100, 2));
advance_to(2);
let region_id = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_eq!(revenue(), 100);
let region = Regions::<Test>::get(®ion_id).unwrap();
assert_eq!(
InstaPoolIo::<Test>::get(region_id.begin),
PoolIoRecord { private: 0, system: 80 }
);
assert_eq!(InstaPoolIo::<Test>::get(region.end), PoolIoRecord { private: 0, system: -80 });
assert_ok!(Broker::do_pool(region_id, None, 2, Provisional));
assert_eq!(
InstaPoolContribution::<Test>::get(region_id),
Some(ContributionRecord { length: 3, payee: 2 })
);
assert_eq!(
InstaPoolIo::<Test>::get(region_id.begin),
PoolIoRecord { private: 80, system: 80 }
);
assert_eq!(
InstaPoolIo::<Test>::get(region.end),
PoolIoRecord { private: -80, system: -80 }
);
assert_ok!(Broker::do_interlace(region_id, None, 0xfffff_fffff_00000_00000.into()));
assert_eq!(InstaPoolContribution::<Test>::get(region_id), None);
assert_eq!(
InstaPoolIo::<Test>::get(region_id.begin),
PoolIoRecord { private: 0, system: 80 }
);
assert_eq!(InstaPoolIo::<Test>::get(region.end), PoolIoRecord { private: 0, system: -80 });
assert_ok!(Broker::do_purchase_credit(1, 20, 1));
assert_eq!(pot(), 0);
assert_eq!(revenue(), 100);
advance_to(8);
assert_ok!(TestCoretimeProvider::spend_instantaneous(1, 10));
advance_to(11);
assert_eq!(pot(), 0);
assert_eq!(revenue(), 110);
assert_noop!(Broker::do_claim_revenue(region_id, 100), Error::<Test>::UnknownContribution);
assert_eq!(pot(), 0);
assert_eq!(revenue(), 110);
assert_eq!(balance(2), 0);
});
}
#[test]
fn instapool_payouts_cannot_be_duplicated_through_reassignment() {
TestExt::new().endow(1, 1000).execute_with(|| {
let item = ScheduleItem { assignment: Pool, mask: CoreMask::complete() };
assert_ok!(Broker::do_reserve(Schedule::truncate_from(vec![item])));
assert_ok!(Broker::do_start_sales(100, 2));
advance_to(2);
let region_id = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_eq!(revenue(), 100);
let region = Regions::<Test>::get(®ion_id).unwrap();
assert_eq!(
InstaPoolIo::<Test>::get(region_id.begin),
PoolIoRecord { private: 0, system: 80 }
);
assert_eq!(InstaPoolIo::<Test>::get(region.end), PoolIoRecord { private: 0, system: -80 });
assert_ok!(Broker::do_pool(region_id, None, 2, Provisional));
assert_eq!(
InstaPoolContribution::<Test>::get(region_id),
Some(ContributionRecord { length: 3, payee: 2 })
);
assert_eq!(
InstaPoolIo::<Test>::get(region_id.begin),
PoolIoRecord { private: 80, system: 80 }
);
assert_eq!(
InstaPoolIo::<Test>::get(region.end),
PoolIoRecord { private: -80, system: -80 }
);
assert_ok!(Broker::do_assign(region_id, None, 2000, Finality::Final));
assert_eq!(InstaPoolContribution::<Test>::get(region_id), None);
assert_eq!(
InstaPoolIo::<Test>::get(region_id.begin),
PoolIoRecord { private: 0, system: 80 }
);
assert_eq!(InstaPoolIo::<Test>::get(region.end), PoolIoRecord { private: 0, system: -80 });
assert_ok!(Broker::do_purchase_credit(1, 20, 1));
assert_eq!(pot(), 0);
assert_eq!(revenue(), 100);
advance_to(8);
assert_ok!(TestCoretimeProvider::spend_instantaneous(1, 10));
advance_to(11);
assert_eq!(pot(), 0);
assert_eq!(revenue(), 110);
assert_noop!(Broker::do_claim_revenue(region_id, 100), Error::<Test>::UnknownContribution);
assert_eq!(pot(), 0);
assert_eq!(revenue(), 110);
assert_eq!(balance(2), 0);
});
}
#[test]
fn initialize_with_system_paras_works() {
TestExt::new().execute_with(|| {
let item = ScheduleItem { assignment: Task(1u32), mask: CoreMask::complete() };
assert_ok!(Broker::do_reserve(Schedule::truncate_from(vec![item])));
let items = vec![
ScheduleItem { assignment: Task(2u32), mask: 0xfffff_fffff_00000_00000.into() },
ScheduleItem { assignment: Task(3u32), mask: 0x00000_00000_fffff_00000.into() },
ScheduleItem { assignment: Task(4u32), mask: 0x00000_00000_00000_fffff.into() },
];
assert_ok!(Broker::do_reserve(Schedule::truncate_from(items)));
assert_ok!(Broker::do_start_sales(100, 0));
advance_to(10);
assert_eq!(
CoretimeTrace::get(),
vec![
(
6,
AssignCore {
core: 0,
begin: 8,
assignment: vec![(Task(1), 57600),],
end_hint: None
}
),
(
6,
AssignCore {
core: 1,
begin: 8,
assignment: vec![(Task(2), 28800), (Task(3), 14400), (Task(4), 14400),],
end_hint: None
}
),
]
);
});
}
#[test]
fn initialize_with_leased_slots_works() {
TestExt::new().execute_with(|| {
assert_ok!(Broker::do_set_lease(1000, 6));
assert_ok!(Broker::do_set_lease(1001, 7));
assert_ok!(Broker::do_start_sales(100, 0));
advance_to(18);
let end_hint = None;
assert_eq!(
CoretimeTrace::get(),
vec![
(
6,
AssignCore {
core: 0,
begin: 8,
assignment: vec![(Task(1000), 57600),],
end_hint
}
),
(
6,
AssignCore {
core: 1,
begin: 8,
assignment: vec![(Task(1001), 57600),],
end_hint
}
),
(
12,
AssignCore {
core: 0,
begin: 14,
assignment: vec![(Task(1001), 57600),],
end_hint
}
),
(12, AssignCore { core: 1, begin: 14, assignment: vec![(Pool, 57600),], end_hint }),
(18, AssignCore { core: 0, begin: 20, assignment: vec![(Pool, 57600),], end_hint }),
(18, AssignCore { core: 1, begin: 20, assignment: vec![(Pool, 57600),], end_hint }),
]
);
});
}
#[test]
fn purchase_works() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_ok!(Broker::do_assign(region, None, 1000, Final));
advance_to(6);
assert_eq!(
CoretimeTrace::get(),
vec![(
6,
AssignCore {
core: 0,
begin: 8,
assignment: vec![(Task(1000), 57600),],
end_hint: None
}
),]
);
});
}
#[test]
fn purchase_credit_works() {
TestExt::new().endow(1, 50).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let credits = CoretimeCredit::get();
assert_eq!(credits.get(&1), None);
assert_noop!(Broker::do_purchase_credit(1, 10, 1), Error::<Test>::CreditPurchaseTooSmall);
assert_noop!(Broker::do_purchase_credit(1, 100, 1), TokenError::FundsUnavailable);
assert_ok!(Broker::do_purchase_credit(1, 50, 1));
let credits = CoretimeCredit::get();
assert_eq!(credits.get(&1), Some(&50));
});
}
#[test]
fn partition_works() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
let (region1, region) = Broker::do_partition(region, None, 1).unwrap();
let (region2, region3) = Broker::do_partition(region, None, 1).unwrap();
assert_ok!(Broker::do_assign(region1, None, 1001, Final));
assert_ok!(Broker::do_assign(region2, None, 1002, Final));
assert_ok!(Broker::do_assign(region3, None, 1003, Final));
advance_to(10);
assert_eq!(
CoretimeTrace::get(),
vec![
(
6,
AssignCore {
core: 0,
begin: 8,
assignment: vec![(Task(1001), 57600),],
end_hint: None
}
),
(
8,
AssignCore {
core: 0,
begin: 10,
assignment: vec![(Task(1002), 57600),],
end_hint: None
}
),
(
10,
AssignCore {
core: 0,
begin: 12,
assignment: vec![(Task(1003), 57600),],
end_hint: None
}
),
]
);
});
}
#[test]
fn interlace_works() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
let (region1, region) =
Broker::do_interlace(region, None, CoreMask::from_chunk(0, 30)).unwrap();
let (region2, region3) =
Broker::do_interlace(region, None, CoreMask::from_chunk(30, 60)).unwrap();
assert_ok!(Broker::do_assign(region1, None, 1001, Final));
assert_ok!(Broker::do_assign(region2, None, 1002, Final));
assert_ok!(Broker::do_assign(region3, None, 1003, Final));
advance_to(10);
assert_eq!(
CoretimeTrace::get(),
vec![(
6,
AssignCore {
core: 0,
begin: 8,
assignment: vec![(Task(1001), 21600), (Task(1002), 21600), (Task(1003), 14400),],
end_hint: None
}
),]
);
});
}
#[test]
fn cant_assign_unowned_region() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
let (region1, region2) =
Broker::do_interlace(region, Some(1), CoreMask::from_chunk(0, 30)).unwrap();
assert_ok!(Broker::do_transfer(region2, Some(1), 2));
assert_noop!(Broker::do_assign(region, Some(1), 1001, Final), Error::<Test>::UnknownRegion);
assert_ok!(Broker::do_assign(region1, Some(1), 1001, Final));
assert_ok!(Broker::do_assign(region2, Some(2), 1002, Final));
advance_to(10);
assert_eq!(
CoretimeTrace::get(),
vec![(
6,
AssignCore {
core: 0,
begin: 8,
assignment: vec![(Task(1001), 21600), (Task(1002), 36000)],
end_hint: None
}
),]
);
});
}
#[test]
fn interlace_then_partition_works() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
let (region1, region2) =
Broker::do_interlace(region, None, CoreMask::from_chunk(0, 20)).unwrap();
let (region1, region3) = Broker::do_partition(region1, None, 1).unwrap();
let (region2, region4) = Broker::do_partition(region2, None, 2).unwrap();
assert_ok!(Broker::do_assign(region1, None, 1001, Final));
assert_ok!(Broker::do_assign(region2, None, 1002, Final));
assert_ok!(Broker::do_assign(region3, None, 1003, Final));
assert_ok!(Broker::do_assign(region4, None, 1004, Final));
advance_to(10);
assert_eq!(
CoretimeTrace::get(),
vec![
(
6,
AssignCore {
core: 0,
begin: 8,
assignment: vec![(Task(1001), 14400), (Task(1002), 43200),],
end_hint: None
}
),
(
8,
AssignCore {
core: 0,
begin: 10,
assignment: vec![(Task(1002), 43200), (Task(1003), 14400),],
end_hint: None
}
),
(
10,
AssignCore {
core: 0,
begin: 12,
assignment: vec![(Task(1003), 14400), (Task(1004), 43200),],
end_hint: None
}
),
]
);
});
}
#[test]
fn partition_then_interlace_works() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
let (region1, region2) = Broker::do_partition(region, None, 1).unwrap();
let (region1, region3) =
Broker::do_interlace(region1, None, CoreMask::from_chunk(0, 20)).unwrap();
let (region2, region4) =
Broker::do_interlace(region2, None, CoreMask::from_chunk(0, 30)).unwrap();
assert_ok!(Broker::do_assign(region1, None, 1001, Final));
assert_ok!(Broker::do_assign(region2, None, 1002, Final));
assert_ok!(Broker::do_assign(region3, None, 1003, Final));
assert_ok!(Broker::do_assign(region4, None, 1004, Final));
advance_to(10);
assert_eq!(
CoretimeTrace::get(),
vec![
(
6,
AssignCore {
core: 0,
begin: 8,
assignment: vec![(Task(1001), 14400), (Task(1003), 43200),],
end_hint: None
}
),
(
8,
AssignCore {
core: 0,
begin: 10,
assignment: vec![(Task(1002), 21600), (Task(1004), 36000),],
end_hint: None
}
),
]
);
});
}
#[test]
fn partitioning_after_assignment_works() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_ok!(Broker::do_assign(region, None, 1001, Provisional));
let (_region, region1) = Broker::do_partition(region, None, 2).unwrap();
assert_ok!(Broker::do_assign(region1, None, 1002, Provisional));
advance_to(10);
assert_eq!(
CoretimeTrace::get(),
vec![
(
6,
AssignCore {
core: 0,
begin: 8,
assignment: vec![(Task(1001), 57600),],
end_hint: None
}
),
(
10,
AssignCore {
core: 0,
begin: 12,
assignment: vec![(Task(1002), 57600),],
end_hint: None
}
),
]
);
});
}
#[test]
fn interlacing_after_assignment_works() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_ok!(Broker::do_assign(region, None, 1001, Provisional));
let (region1, _region) =
Broker::do_interlace(region, None, CoreMask::from_chunk(0, 40)).unwrap();
assert_ok!(Broker::do_assign(region1, None, 1002, Provisional));
advance_to(10);
assert_eq!(
CoretimeTrace::get(),
vec![(
6,
AssignCore {
core: 0,
begin: 8,
assignment: vec![(Idle, 28800), (Task(1002), 28800)],
end_hint: None
}
),]
);
});
}
#[test]
fn reservations_are_limited() {
TestExt::new().execute_with(|| {
let schedule = Schedule::truncate_from(vec![ScheduleItem {
assignment: Pool,
mask: CoreMask::complete(),
}]);
let max_cores: u32 = <Test as Config>::MaxReservedCores::get();
Reservations::<Test>::put(
BoundedVec::try_from(vec![schedule.clone(); max_cores as usize]).unwrap(),
);
assert_noop!(Broker::do_reserve(schedule), Error::<Test>::TooManyReservations);
});
}
#[test]
fn cannot_unreserve_unknown() {
TestExt::new().execute_with(|| {
let schedule = Schedule::truncate_from(vec![ScheduleItem {
assignment: Pool,
mask: CoreMask::complete(),
}]);
Reservations::<Test>::put(BoundedVec::try_from(vec![schedule.clone(); 1usize]).unwrap());
assert_noop!(Broker::do_unreserve(2), Error::<Test>::UnknownReservation);
});
}
#[test]
fn cannot_set_expired_lease() {
TestExt::new().execute_with(|| {
advance_to(2);
let current_timeslice = Broker::current_timeslice();
assert_noop!(
Broker::do_set_lease(1000, current_timeslice.saturating_sub(1)),
Error::<Test>::AlreadyExpired
);
});
}
#[test]
fn short_leases_are_cleaned() {
TestExt::new().region_length(3).execute_with(|| {
assert_ok!(Broker::do_start_sales(200, 1));
advance_to(2);
assert_noop!(
Broker::do_set_lease(1000, Broker::current_timeslice()),
Error::<Test>::AlreadyExpired
);
assert_eq!(Leases::<Test>::get().len(), 0);
assert_ok!(Broker::do_set_lease(1000, Broker::current_timeslice().saturating_add(1)));
assert_eq!(Leases::<Test>::get().len(), 1);
let config = Configuration::<Test>::get().unwrap();
let timeslice_period: u64 = <Test as Config>::TimeslicePeriod::get();
advance_to(timeslice_period.saturating_mul(config.region_length.into()));
assert_eq!(Leases::<Test>::get().len(), 0);
});
}
#[test]
fn leases_can_be_renewed() {
let initial_balance = 100_000;
TestExt::new().endow(1, initial_balance).execute_with(|| {
assert_ok!(Broker::do_set_lease(2001, 9));
assert_eq!(Leases::<Test>::get().len(), 1);
assert_ok!(Broker::do_start_sales(100, 0));
advance_sale_period();
assert_eq!(
PotentialRenewals::<Test>::get(PotentialRenewalId { core: 0, when: 10 }),
Some(PotentialRenewalRecord {
price: 1000,
completion: CompletionStatus::Complete(
vec![ScheduleItem { mask: CoreMask::complete(), assignment: Task(2001) }]
.try_into()
.unwrap()
)
})
);
assert_eq!(Leases::<Test>::get().len(), 0);
advance_sale_period();
assert_ok!(Broker::do_renew(1, 0));
assert_eq!(balance(1), initial_balance - 1000);
advance_sale_period();
advance_sale_period();
assert_eq!(
CoretimeTrace::get(),
vec![
(
6,
AssignCore {
core: 0,
begin: 8,
assignment: vec![(CoreAssignment::Task(2001), 57600)],
end_hint: None,
},
),
(
12,
AssignCore {
core: 0,
begin: 14,
assignment: vec![(CoreAssignment::Task(2001), 57600)],
end_hint: None,
},
),
(
18,
AssignCore {
core: 0,
begin: 20,
assignment: vec![(CoreAssignment::Task(2001), 57600)],
end_hint: None,
},
),
(
24,
AssignCore {
core: 0,
begin: 26,
assignment: vec![(CoreAssignment::Pool, 57600)],
end_hint: None,
},
),
]
);
});
}
#[test]
fn short_leases_cannot_be_renewed() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_set_lease(2001, 3));
assert_eq!(Leases::<Test>::get().len(), 1);
assert_ok!(Broker::do_start_sales(100, 0));
assert_eq!(Leases::<Test>::get().len(), 0);
assert_eq!(PotentialRenewals::<Test>::get(PotentialRenewalId { core: 0, when: 10 }), None);
assert_eq!(Leases::<Test>::get().len(), 0);
advance_to(13);
assert_noop!(Broker::do_renew(1, 0), Error::<Test>::NotAllowed);
assert_eq!(
CoretimeTrace::get(),
vec![
(
6,
AssignCore {
core: 0,
begin: 8,
assignment: vec![(CoreAssignment::Task(2001), 57600)],
end_hint: None,
},
),
(
12,
AssignCore {
core: 0,
begin: 14,
assignment: vec![(CoreAssignment::Pool, 57600)],
end_hint: None,
},
),
]
);
});
}
#[test]
fn leases_are_limited() {
TestExt::new().execute_with(|| {
let max_leases: u32 = <Test as Config>::MaxLeasedCores::get();
Leases::<Test>::put(
BoundedVec::try_from(vec![
LeaseRecordItem { task: 1u32, until: 10u32 };
max_leases as usize
])
.unwrap(),
);
assert_noop!(Broker::do_set_lease(1000, 10), Error::<Test>::TooManyLeases);
});
}
#[test]
fn remove_lease_works() {
TestExt::new().execute_with(|| {
Leases::<Test>::put(
BoundedVec::try_from(vec![LeaseRecordItem { task: 1u32, until: 10u32 }]).unwrap(),
);
assert_noop!(Broker::do_remove_lease(2), Error::<Test>::LeaseNotFound);
assert_ok!(Broker::do_remove_lease(1));
assert_noop!(Broker::do_remove_lease(1), Error::<Test>::LeaseNotFound);
});
}
#[test]
fn purchase_requires_valid_status_and_sale_info() {
TestExt::new().execute_with(|| {
assert_noop!(Broker::do_purchase(1, 100), Error::<Test>::Uninitialized);
let status = StatusRecord {
core_count: 2,
private_pool_size: 0,
system_pool_size: 0,
last_committed_timeslice: 0,
last_timeslice: 1,
};
Status::<Test>::put(&status);
assert_noop!(Broker::do_purchase(1, 100), Error::<Test>::NoSales);
let mut dummy_sale = SaleInfoRecord {
sale_start: 0,
leadin_length: 0,
end_price: 200,
sellout_price: None,
region_begin: 0,
region_end: 3,
first_core: 3,
ideal_cores_sold: 0,
cores_offered: 1,
cores_sold: 2,
};
SaleInfo::<Test>::put(&dummy_sale);
assert_noop!(Broker::do_purchase(1, 100), Error::<Test>::Unavailable);
dummy_sale.first_core = 1;
SaleInfo::<Test>::put(&dummy_sale);
assert_noop!(Broker::do_purchase(1, 100), Error::<Test>::SoldOut);
assert_ok!(Broker::do_start_sales(200, 1));
assert_noop!(Broker::do_purchase(1, 100), Error::<Test>::TooEarly);
advance_to(2);
assert_noop!(Broker::do_purchase(1, 100), Error::<Test>::Overpriced);
});
}
#[test]
fn renewal_requires_valid_status_and_sale_info() {
TestExt::new().execute_with(|| {
assert_noop!(Broker::do_renew(1, 1), Error::<Test>::Uninitialized);
let status = StatusRecord {
core_count: 2,
private_pool_size: 0,
system_pool_size: 0,
last_committed_timeslice: 0,
last_timeslice: 1,
};
Status::<Test>::put(&status);
assert_noop!(Broker::do_renew(1, 1), Error::<Test>::NoSales);
let mut dummy_sale = SaleInfoRecord {
sale_start: 0,
leadin_length: 0,
end_price: 200,
sellout_price: None,
region_begin: 0,
region_end: 3,
first_core: 3,
ideal_cores_sold: 0,
cores_offered: 1,
cores_sold: 2,
};
SaleInfo::<Test>::put(&dummy_sale);
assert_noop!(Broker::do_renew(1, 1), Error::<Test>::Unavailable);
dummy_sale.first_core = 1;
SaleInfo::<Test>::put(&dummy_sale);
assert_noop!(Broker::do_renew(1, 1), Error::<Test>::SoldOut);
assert_ok!(Broker::do_start_sales(200, 1));
assert_noop!(Broker::do_renew(1, 1), Error::<Test>::NotAllowed);
let record = PotentialRenewalRecord {
price: 100,
completion: CompletionStatus::Partial(CoreMask::from_chunk(0, 20)),
};
PotentialRenewals::<Test>::insert(PotentialRenewalId { core: 1, when: 4 }, &record);
assert_noop!(Broker::do_renew(1, 1), Error::<Test>::IncompleteAssignment);
});
}
#[test]
fn cannot_transfer_or_partition_or_interlace_unknown() {
TestExt::new().execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() };
assert_noop!(Broker::do_transfer(region_id, None, 2), Error::<Test>::UnknownRegion);
assert_noop!(Broker::do_partition(region_id, None, 2), Error::<Test>::UnknownRegion);
assert_noop!(
Broker::do_interlace(region_id, None, CoreMask::from_chunk(0, 20)),
Error::<Test>::UnknownRegion
);
});
}
#[test]
fn check_ownership_for_transfer_or_partition_or_interlace() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_noop!(Broker::do_transfer(region, Some(2), 2), Error::<Test>::NotOwner);
assert_noop!(Broker::do_partition(region, Some(2), 2), Error::<Test>::NotOwner);
assert_noop!(
Broker::do_interlace(region, Some(2), CoreMask::from_chunk(0, 20)),
Error::<Test>::NotOwner
);
});
}
#[test]
fn cannot_partition_invalid_offset() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_noop!(Broker::do_partition(region, None, 0), Error::<Test>::PivotTooEarly);
assert_noop!(Broker::do_partition(region, None, 5), Error::<Test>::PivotTooLate);
});
}
#[test]
fn cannot_interlace_invalid_pivot() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region = Broker::do_purchase(1, u64::max_value()).unwrap();
let (region1, _) = Broker::do_interlace(region, None, CoreMask::from_chunk(0, 20)).unwrap();
assert_noop!(
Broker::do_interlace(region1, None, CoreMask::from_chunk(20, 40)),
Error::<Test>::ExteriorPivot
);
assert_noop!(
Broker::do_interlace(region1, None, CoreMask::void()),
Error::<Test>::VoidPivot
);
assert_noop!(
Broker::do_interlace(region1, None, CoreMask::from_chunk(0, 20)),
Error::<Test>::CompletePivot
);
});
}
#[test]
fn assign_should_drop_invalid_region() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let mut region = Broker::do_purchase(1, u64::max_value()).unwrap();
advance_to(10);
assert_ok!(Broker::do_assign(region, Some(1), 1001, Provisional));
region.begin = 7;
System::assert_last_event(Event::RegionDropped { region_id: region, duration: 3 }.into());
});
}
#[test]
fn pool_should_drop_invalid_region() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let mut region = Broker::do_purchase(1, u64::max_value()).unwrap();
advance_to(10);
assert_ok!(Broker::do_pool(region, Some(1), 1001, Provisional));
region.begin = 7;
System::assert_last_event(Event::RegionDropped { region_id: region, duration: 3 }.into());
});
}
#[test]
fn config_works() {
TestExt::new().execute_with(|| {
let mut cfg = new_config();
assert_ok!(Broker::configure(Root.into(), cfg.clone()));
cfg.leadin_length = 0;
assert_noop!(Broker::configure(Root.into(), cfg), Error::<Test>::InvalidConfig);
});
}
#[test]
fn renewal_works_leases_ended_before_start_sales() {
TestExt::new().endow(1, 100_000).execute_with(|| {
let config = Configuration::<Test>::get().unwrap();
assert_ok!(Broker::do_set_lease(1, 1));
advance_to(5);
assert_ok!(Broker::do_set_lease(
2,
Broker::latest_timeslice_ready_to_commit(&config) + config.region_length * 3
));
assert_ok!(Broker::do_start_sales(100, 0));
assert_noop!(Broker::do_renew(1, 1), Error::<Test>::Unavailable);
assert_noop!(Broker::do_renew(1, 0), Error::<Test>::Unavailable);
assert!(Leases::<Test>::get().iter().any(|l| l.task == 2));
advance_sale_period();
let new_core = Broker::do_renew(1, 0).unwrap();
assert_noop!(Broker::do_renew(1, 1), Error::<Test>::SoldOut);
assert_eq!(balance(1), 99000);
advance_sale_period();
let new_core = Broker::do_renew(1, new_core).unwrap();
assert_noop!(Broker::do_renew(1, 0), Error::<Test>::SoldOut);
assert_eq!(balance(1), 98900);
assert!(Leases::<Test>::get().is_empty());
advance_sale_period();
assert_eq!(0, Broker::do_renew(1, new_core).unwrap());
assert_eq!(1, Broker::do_renew(1, 0).unwrap());
assert_eq!(balance(1), 98790);
advance_sale_period();
assert_eq!(
CoretimeTrace::get(),
vec![
(
10,
AssignCore {
core: 0,
begin: 12,
assignment: vec![(Task(1), 57600)],
end_hint: None
}
),
(
10,
AssignCore {
core: 1,
begin: 12,
assignment: vec![(Task(2), 57600)],
end_hint: None
}
),
(
16,
AssignCore {
core: 0,
begin: 18,
assignment: vec![(Task(2), 57600)],
end_hint: None
}
),
(
16,
AssignCore {
core: 1,
begin: 18,
assignment: vec![(Task(1), 57600)],
end_hint: None
}
),
(
22,
AssignCore {
core: 0,
begin: 24,
assignment: vec![(Task(2), 57600)],
end_hint: None,
},
),
(
22,
AssignCore {
core: 1,
begin: 24,
assignment: vec![(Task(1), 57600)],
end_hint: None,
},
),
(
28,
AssignCore {
core: 0,
begin: 30,
assignment: vec![(Task(1), 57600)],
end_hint: None,
},
),
(
28,
AssignCore {
core: 1,
begin: 30,
assignment: vec![(Task(2), 57600)],
end_hint: None,
},
),
]
);
});
}
#[test]
fn enable_auto_renew_works() {
TestExt::new().endow(1, 1000).limit_cores_offered(Some(10)).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 5));
advance_to(2);
let region_id = Broker::do_purchase(1, u64::max_value()).unwrap();
let record = Regions::<Test>::get(region_id).unwrap();
assert_ok!(Broker::do_assign(region_id, Some(1), 1001, Provisional));
assert_noop!(
Broker::do_enable_auto_renew(1001, region_id.core, 1001, Some(7)),
Error::<Test>::NotAllowed
);
assert_ok!(Broker::do_assign(region_id, Some(1), 1001, Final));
assert!(PotentialRenewals::<Test>::get(PotentialRenewalId {
core: region_id.core,
when: record.end
})
.is_some());
assert_noop!(
Broker::enable_auto_renew(RuntimeOrigin::signed(1), region_id.core, 1001, Some(7)),
Error::<Test>::NoPermission
);
assert_ok!(Broker::do_enable_auto_renew(1001, region_id.core, 1001, Some(7)));
assert_eq!(
AutoRenewals::<Test>::get().to_vec(),
vec![AutoRenewalRecord { core: 0, task: 1001, next_renewal: 7 }]
);
System::assert_has_event(
Event::<Test>::AutoRenewalEnabled { core: region_id.core, task: 1001 }.into(),
);
let region_2 = Broker::do_purchase(1, u64::max_value()).unwrap();
let region_3 = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_ok!(Broker::do_assign(region_2, Some(1), 1002, Final));
assert_ok!(Broker::do_assign(region_3, Some(1), 1003, Final));
assert_ok!(Broker::do_enable_auto_renew(1003, region_3.core, 1003, Some(7)));
assert_ok!(Broker::do_enable_auto_renew(1002, region_2.core, 1002, Some(7)));
assert_eq!(
AutoRenewals::<Test>::get().to_vec(),
vec![
AutoRenewalRecord { core: 0, task: 1001, next_renewal: 7 },
AutoRenewalRecord { core: 1, task: 1002, next_renewal: 7 },
AutoRenewalRecord { core: 2, task: 1003, next_renewal: 7 },
]
);
let region_4 = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_ok!(Broker::do_assign(region_4, Some(1), 1004, Final));
assert_noop!(
Broker::do_enable_auto_renew(1004, region_4.core, 1004, Some(7)),
Error::<Test>::TooManyAutoRenewals
);
});
}
#[test]
fn enable_auto_renewal_works_for_legacy_leases() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let record = PotentialRenewalRecord {
price: 100,
completion: CompletionStatus::Complete(
vec![ScheduleItem { mask: CoreMask::complete(), assignment: Task(1001) }]
.try_into()
.unwrap(),
),
};
PotentialRenewals::<Test>::insert(PotentialRenewalId { core: 0, when: 10 }, &record);
endow(1001, 1000);
assert_noop!(Broker::do_enable_auto_renew(1001, 0, 1001, None), Error::<Test>::NotAllowed);
assert_ok!(Broker::do_enable_auto_renew(1001, 0, 1001, Some(10)));
assert_eq!(
AutoRenewals::<Test>::get().to_vec(),
vec![AutoRenewalRecord { core: 0, task: 1001, next_renewal: 10 },]
);
System::assert_has_event(Event::<Test>::AutoRenewalEnabled { core: 0, task: 1001 }.into());
advance_to(7);
assert_eq!(balance(1001), 1000);
advance_to(13);
assert_eq!(balance(1001), 900);
System::assert_has_event(
Event::<Test>::Renewed {
who: 1001, old_core: 0,
core: 0,
price: 100,
begin: 10,
duration: 3,
workload: Schedule::truncate_from(vec![ScheduleItem {
assignment: Task(1001),
mask: CoreMask::complete(),
}]),
}
.into(),
);
});
}
#[test]
fn enable_auto_renew_renews() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region_id = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_ok!(Broker::do_assign(region_id, Some(1), 1001, Final));
advance_to(6);
assert_noop!(
Broker::do_enable_auto_renew(1001, region_id.core, 1001, None),
TokenError::FundsUnavailable
);
endow(1001, 1000);
assert_ok!(Broker::do_enable_auto_renew(1001, region_id.core, 1001, None));
assert_eq!(
AutoRenewals::<Test>::get().to_vec(),
vec![AutoRenewalRecord { core: 0, task: 1001, next_renewal: 10 }]
);
assert!(PotentialRenewals::<Test>::get(PotentialRenewalId {
core: region_id.core,
when: 10
})
.is_some());
System::assert_has_event(
Event::<Test>::AutoRenewalEnabled { core: region_id.core, task: 1001 }.into(),
);
});
}
#[test]
fn auto_renewal_works() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 3));
advance_to(2);
let region_1 = Broker::do_purchase(1, u64::max_value()).unwrap();
let region_2 = Broker::do_purchase(1, u64::max_value()).unwrap();
let region_3 = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_ok!(Broker::do_assign(region_1, Some(1), 1001, Final));
assert_ok!(Broker::do_assign(region_2, Some(1), 1002, Final));
assert_ok!(Broker::do_assign(region_3, Some(1), 1003, Final));
assert_ok!(Broker::do_enable_auto_renew(1001, region_1.core, 1001, Some(7)));
assert_ok!(Broker::do_enable_auto_renew(1002, region_2.core, 1002, Some(7)));
assert_ok!(Broker::do_enable_auto_renew(1003, region_3.core, 1003, Some(7)));
assert_eq!(
AutoRenewals::<Test>::get().to_vec(),
vec![
AutoRenewalRecord { core: 0, task: 1001, next_renewal: 7 },
AutoRenewalRecord { core: 1, task: 1002, next_renewal: 7 },
AutoRenewalRecord { core: 2, task: 1003, next_renewal: 7 },
]
);
endow(1001, 1000);
endow(1003, 1000);
advance_to(7);
System::assert_has_event(
Event::<Test>::Renewed {
who: 1001, old_core: 0,
core: 0,
price: 100,
begin: 7,
duration: 3,
workload: Schedule::truncate_from(vec![ScheduleItem {
assignment: Task(1001),
mask: CoreMask::complete(),
}]),
}
.into(),
);
System::assert_has_event(
Event::<Test>::AutoRenewalFailed { core: 1, payer: Some(1002) }.into(),
);
System::assert_has_event(
Event::<Test>::Renewed {
who: 1003, old_core: 2,
core: 1, price: 100,
begin: 7,
duration: 3,
workload: Schedule::truncate_from(vec![ScheduleItem {
assignment: Task(1003),
mask: CoreMask::complete(),
}]),
}
.into(),
);
assert_eq!(
AutoRenewals::<Test>::get().to_vec(),
vec![
AutoRenewalRecord { core: 0, task: 1001, next_renewal: 10 },
AutoRenewalRecord { core: 1, task: 1003, next_renewal: 10 },
]
);
});
}
#[test]
fn disable_auto_renew_works() {
TestExt::new().endow(1, 1000).limit_cores_offered(Some(10)).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 3));
advance_to(2);
let region_id = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_ok!(Broker::do_assign(region_id, Some(1), 1001, Final));
assert_noop!(
Broker::do_disable_auto_renew(region_id.core, 1001),
Error::<Test>::AutoRenewalNotEnabled
);
assert_ok!(Broker::do_enable_auto_renew(1001, region_id.core, 1001, Some(7)));
assert_eq!(
AutoRenewals::<Test>::get().to_vec(),
vec![AutoRenewalRecord { core: 0, task: 1001, next_renewal: 7 }]
);
assert_noop!(
Broker::disable_auto_renew(RuntimeOrigin::signed(1), 0, 1001),
Error::<Test>::NoPermission
);
assert_ok!(Broker::do_disable_auto_renew(0, 1001));
assert_eq!(AutoRenewals::<Test>::get().to_vec(), vec![]);
System::assert_has_event(
Event::<Test>::AutoRenewalDisabled { core: region_id.core, task: 1001 }.into(),
);
});
}
#[test]
fn remove_assignment_works() {
TestExt::new().endow(1, 1000).execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 1));
advance_to(2);
let region_id = Broker::do_purchase(1, u64::max_value()).unwrap();
assert_ok!(Broker::do_assign(region_id, Some(1), 1001, Final));
let workplan_key = (region_id.begin, region_id.core);
assert_ne!(Workplan::<Test>::get(workplan_key), None);
assert_noop!(Broker::remove_assignment(RuntimeOrigin::signed(2), region_id), BadOrigin);
assert_ok!(Broker::remove_assignment(RuntimeOrigin::root(), region_id));
assert_eq!(Workplan::<Test>::get(workplan_key), None);
assert_noop!(
Broker::remove_assignment(RuntimeOrigin::root(), region_id),
Error::<Test>::AssignmentNotFound
);
});
}
#[test]
fn start_sales_sets_correct_core_count() {
TestExt::new().endow(1, 1000).execute_with(|| {
advance_to(1);
Broker::do_set_lease(1, 100).unwrap();
Broker::do_set_lease(2, 100).unwrap();
Broker::do_set_lease(3, 100).unwrap();
Broker::do_reserve(Schedule::truncate_from(vec![ScheduleItem {
assignment: Pool,
mask: CoreMask::complete(),
}]))
.unwrap();
Broker::do_start_sales(5, 5).unwrap();
System::assert_has_event(Event::<Test>::CoreCountRequested { core_count: 9 }.into());
})
}
#[test]
fn reserve_works() {
TestExt::new().execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 0));
advance_to(1);
let system_workload = Schedule::truncate_from(vec![ScheduleItem {
mask: CoreMask::complete(),
assignment: Task(1004),
}]);
let status = Status::<Test>::get().unwrap();
assert_ok!(Broker::request_core_count(RuntimeOrigin::root(), status.core_count + 1));
assert_ok!(Broker::reserve(RuntimeOrigin::root(), system_workload.clone()));
System::assert_last_event(
Event::ReservationMade { index: 0, workload: system_workload.clone() }.into(),
);
assert_eq!(Reservations::<Test>::get(), vec![system_workload.clone()]);
for i in 0..20 {
assert_eq!(Workplan::<Test>::get((i, 0)), None);
}
assert_eq!(CoretimeTrace::get(), vec![]);
advance_sale_period();
assert_eq!(Workplan::<Test>::get((7, 0)), Some(system_workload.clone()));
assert_eq!(CoretimeTrace::get(), vec![]);
advance_sale_period();
assert_eq!(
CoretimeTrace::get(),
vec![(
12,
AssignCore {
core: 0,
begin: 14,
assignment: vec![(Task(1004), 57600)],
end_hint: None
}
)]
);
System::assert_has_event(
Event::CoreAssigned {
core: 0,
when: 14,
assignment: vec![(CoreAssignment::Task(1004), 57600)],
}
.into(),
);
assert_eq!(Workplan::<Test>::get((10, 0)), Some(system_workload.clone()));
});
}
#[test]
fn can_reserve_workloads_quickly() {
TestExt::new().execute_with(|| {
assert_ok!(Broker::do_start_sales(100, 0));
advance_to(2);
let system_workload = Schedule::truncate_from(vec![ScheduleItem {
mask: CoreMask::complete(),
assignment: Task(1004),
}]);
let core_count = Status::<Test>::get().unwrap().core_count;
assert_ok!(Broker::request_core_count(RuntimeOrigin::root(), core_count + 1));
assert_ok!(Broker::reserve(RuntimeOrigin::root(), system_workload.clone()));
let core_index = core_count;
<TestCoretimeProvider as CoretimeInterface>::assign_core(
core_index,
2,
vec![(Task(1004), 57600)],
None,
);
Workplan::<Test>::insert((4, core_index), system_workload.clone());
System::assert_has_event(
Event::ReservationMade { index: 0, workload: system_workload.clone() }.into(),
);
System::assert_has_event(Event::CoreCountRequested { core_count: 1 }.into());
assert_eq!(Workplan::<Test>::get((4, 0)), Some(system_workload.clone()));
advance_sale_period();
assert_eq!(Workplan::<Test>::get((7, 0)), Some(system_workload.clone()));
advance_sale_period();
assert_eq!(
CoretimeTrace::get(),
vec![
(
2,
AssignCore {
core: 0,
begin: 2,
assignment: vec![(Task(1004), 57600)],
end_hint: None
}
),
(
6,
AssignCore {
core: 0,
begin: 8,
assignment: vec![(Task(1004), 57600)],
end_hint: None
}
),
(
12,
AssignCore {
core: 0,
begin: 14,
assignment: vec![(Task(1004), 57600)],
end_hint: None
}
)
]
);
System::assert_has_event(
Event::CoreAssigned {
core: 0,
when: 8,
assignment: vec![(CoreAssignment::Task(1004), 57600)],
}
.into(),
);
System::assert_has_event(
Event::CoreAssigned {
core: 0,
when: 14,
assignment: vec![(CoreAssignment::Task(1004), 57600)],
}
.into(),
);
System::assert_has_event(
Event::CoreAssigned {
core: 0,
when: 14,
assignment: vec![(CoreAssignment::Task(1004), 57600)],
}
.into(),
);
assert_eq!(Workplan::<Test>::get((10, 0)), Some(system_workload.clone()));
});
}
#[test]
fn force_reserve_works() {
TestExt::new().execute_with(|| {
let system_workload = Schedule::truncate_from(vec![ScheduleItem {
mask: CoreMask::complete(),
assignment: Task(1004),
}]);
assert_noop!(
Broker::force_reserve(RuntimeOrigin::root(), system_workload.clone(), 0),
Error::<Test>::NoSales
);
assert_ok!(Broker::do_start_sales(100, 0));
advance_to(1);
assert_ok!(Broker::do_request_core_count(1));
assert_ok!(Broker::force_reserve(RuntimeOrigin::root(), system_workload.clone(), 0));
System::assert_has_event(
Event::ReservationMade { index: 0, workload: system_workload.clone() }.into(),
);
System::assert_has_event(Event::CoreCountRequested { core_count: 1 }.into());
assert_eq!(Reservations::<Test>::get(), vec![system_workload.clone()]);
advance_to(3);
System::assert_has_event(
Event::CoreAssigned {
core: 0,
when: 4,
assignment: vec![(CoreAssignment::Task(1004), 57600)],
}
.into(),
);
assert_eq!(Workplan::<Test>::get((4, 0)), Some(system_workload.clone()));
advance_sale_period();
assert_eq!(Workplan::<Test>::get((7, 0)), Some(system_workload.clone()));
advance_sale_period();
assert_eq!(
CoretimeTrace::get(),
vec![
(
2,
AssignCore {
core: 0,
begin: 4,
assignment: vec![(Task(1004), 57600)],
end_hint: None
}
),
(
6,
AssignCore {
core: 0,
begin: 8,
assignment: vec![(Task(1004), 57600)],
end_hint: None
}
),
(
12,
AssignCore {
core: 0,
begin: 14,
assignment: vec![(Task(1004), 57600)],
end_hint: None
}
)
]
);
System::assert_has_event(
Event::CoreAssigned {
core: 0,
when: 8,
assignment: vec![(CoreAssignment::Task(1004), 57600)],
}
.into(),
);
System::assert_has_event(
Event::CoreAssigned {
core: 0,
when: 14,
assignment: vec![(CoreAssignment::Task(1004), 57600)],
}
.into(),
);
System::assert_has_event(
Event::CoreAssigned {
core: 0,
when: 14,
assignment: vec![(CoreAssignment::Task(1004), 57600)],
}
.into(),
);
assert_eq!(Workplan::<Test>::get((10, 0)), Some(system_workload.clone()));
});
}