12345678910111213141516171819202122232425262728293031323334353637use super::*;38use crate::mock::{39 logger, new_test_ext, root, run_to_block, LoggerCall, RuntimeCall, Scheduler, Test, *,40};41use frame_support::{42 assert_noop, assert_ok,43 traits::{Contains, GetStorageVersion, OnInitialize},44 Hashable,45};4647#[test]48fn basic_scheduling_works() {49 new_test_ext().execute_with(|| {50 let call =51 RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });52 assert!(!<Test as frame_system::Config>::BaseCallFilter::contains(&call));53 assert_ok!(Scheduler::do_schedule(54 DispatchTime::At(4),55 None,56 127,57 root(),58 <ScheduledCall<Test>>::new(call).unwrap(),59 ));60 run_to_block(3);61 assert!(logger::log().is_empty());62 run_to_block(4);63 assert_eq!(logger::log(), vec![(root(), 42u32)]);64 run_to_block(100);65 assert_eq!(logger::log(), vec![(root(), 42u32)]);66 });67}6869#[test]70fn schedule_after_works() {71 new_test_ext().execute_with(|| {72 run_to_block(2);73 let call =74 RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });75 assert!(!<Test as frame_system::Config>::BaseCallFilter::contains(&call));76 77 assert_ok!(Scheduler::do_schedule(78 DispatchTime::After(3),79 None,80 127,81 root(),82 <ScheduledCall<Test>>::new(call).unwrap(),83 ));84 run_to_block(5);85 assert!(logger::log().is_empty());86 run_to_block(6);87 assert_eq!(logger::log(), vec![(root(), 42u32)]);88 run_to_block(100);89 assert_eq!(logger::log(), vec![(root(), 42u32)]);90 });91}9293#[test]94fn schedule_after_zero_works() {95 new_test_ext().execute_with(|| {96 run_to_block(2);97 let call =98 RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });99 assert!(!<Test as frame_system::Config>::BaseCallFilter::contains(&call));100 assert_ok!(Scheduler::do_schedule(101 DispatchTime::After(0),102 None,103 127,104 root(),105 <ScheduledCall<Test>>::new(call).unwrap(),106 ));107 108 run_to_block(3);109 assert_eq!(logger::log(), vec![(root(), 42u32)]);110 run_to_block(100);111 assert_eq!(logger::log(), vec![(root(), 42u32)]);112 });113}114115#[test]116fn periodic_scheduling_works() {117 new_test_ext().execute_with(|| {118 119 assert_ok!(Scheduler::do_schedule(120 DispatchTime::At(4),121 Some((3, 3)),122 127,123 root(),124 <ScheduledCall<Test>>::new(RuntimeCall::Logger(logger::Call::log {125 i: 42,126 weight: Weight::from_ref_time(10)127 }))128 .unwrap()129 ));130 run_to_block(3);131 assert!(logger::log().is_empty());132 run_to_block(4);133 assert_eq!(logger::log(), vec![(root(), 42u32)]);134 run_to_block(6);135 assert_eq!(logger::log(), vec![(root(), 42u32)]);136 run_to_block(7);137 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]);138 run_to_block(9);139 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]);140 run_to_block(10);141 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]);142 run_to_block(100);143 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]);144 });145}146147#[test]148fn cancel_named_scheduling_works_with_normal_cancel() {149 new_test_ext().execute_with(|| {150 151 Scheduler::do_schedule_named(152 [1u8; 32],153 DispatchTime::At(4),154 None,155 127,156 root(),157 <ScheduledCall<Test>>::new(RuntimeCall::Logger(LoggerCall::log {158 i: 69,159 weight: Weight::from_ref_time(10),160 }))161 .unwrap(),162 )163 .unwrap();164 let i = Scheduler::do_schedule(165 DispatchTime::At(4),166 None,167 127,168 root(),169 <ScheduledCall<Test>>::new(RuntimeCall::Logger(LoggerCall::log {170 i: 42,171 weight: Weight::from_ref_time(10),172 }))173 .unwrap(),174 )175 .unwrap();176 run_to_block(3);177 assert!(logger::log().is_empty());178 assert_ok!(Scheduler::do_cancel_named(None, [1u8; 32]));179 assert_ok!(Scheduler::do_cancel(None, i));180 run_to_block(100);181 assert!(logger::log().is_empty());182 });183}184185#[test]186fn cancel_named_periodic_scheduling_works() {187 new_test_ext().execute_with(|| {188 189 Scheduler::do_schedule_named(190 [1u8; 32],191 DispatchTime::At(4),192 Some((3, 3)),193 127,194 root(),195 <ScheduledCall<Test>>::new(RuntimeCall::Logger(LoggerCall::log {196 i: 42,197 weight: Weight::from_ref_time(10),198 }))199 .unwrap(),200 )201 .unwrap();202 203 assert!(Scheduler::do_schedule_named(204 [1u8; 32],205 DispatchTime::At(4),206 None,207 127,208 root(),209 <ScheduledCall<Test>>::new(RuntimeCall::Logger(LoggerCall::log {210 i: 69,211 weight: Weight::from_ref_time(10)212 }))213 .unwrap(),214 )215 .is_err());216 217 Scheduler::do_schedule_named(218 [2u8; 32],219 DispatchTime::At(8),220 None,221 127,222 root(),223 <ScheduledCall<Test>>::new(RuntimeCall::Logger(LoggerCall::log {224 i: 69,225 weight: Weight::from_ref_time(10),226 }))227 .unwrap(),228 )229 .unwrap();230 run_to_block(3);231 assert!(logger::log().is_empty());232 run_to_block(4);233 assert_eq!(logger::log(), vec![(root(), 42u32)]);234 run_to_block(6);235 assert_ok!(Scheduler::do_cancel_named(None, [1u8; 32]));236 run_to_block(100);237 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]);238 });239}240241#[test]242fn scheduler_respects_weight_limits() {243 let max_weight: Weight = <Test as Config>::MaximumWeight::get();244 new_test_ext().execute_with(|| {245 let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 3 * 2 });246 assert_ok!(Scheduler::do_schedule(247 DispatchTime::At(4),248 None,249 127,250 root(),251 <ScheduledCall<Test>>::new(call).unwrap(),252 ));253 let call = RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 3 * 2 });254 assert_ok!(Scheduler::do_schedule(255 DispatchTime::At(4),256 None,257 127,258 root(),259 <ScheduledCall<Test>>::new(call).unwrap(),260 ));261 262 run_to_block(4);263 assert_eq!(logger::log(), vec![(root(), 42u32)]);264 run_to_block(5);265 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]);266 });267}268269270#[test]271fn scheduler_does_not_delete_permanently_overweight_call() {272 let max_weight: Weight = <Test as Config>::MaximumWeight::get();273 new_test_ext().execute_with(|| {274 let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight });275 assert_ok!(Scheduler::do_schedule(276 DispatchTime::At(4),277 None,278 127,279 root(),280 <ScheduledCall<Test>>::new(call).unwrap(),281 ));282 283 run_to_block(100);284 assert_eq!(logger::log(), vec![]);285286 287 assert_eq!(288 System::events().last().unwrap().event,289 crate::Event::PermanentlyOverweight { task: (4, 0), id: None }.into(),290 );291 292 assert!(Agenda::<Test>::get(4)[0].is_some());293 });294}295296#[test]297fn scheduler_handles_periodic_failure() {298 let max_weight: Weight = <Test as Config>::MaximumWeight::get();299 let max_per_block = <Test as Config>::MaxScheduledPerBlock::get();300301 new_test_ext().execute_with(|| {302 let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: (max_weight / 3) * 2 });303 let call = <ScheduledCall<Test>>::new(call).unwrap();304305 assert_ok!(Scheduler::do_schedule(306 DispatchTime::At(4),307 Some((4, u32::MAX)),308 127,309 root(),310 call.clone(),311 ));312 313 run_to_block(20);314 assert_eq!(logger::log().len(), 5);315316 317 for _ in 0..max_per_block {318 assert_ok!(Scheduler::do_schedule(319 DispatchTime::At(28),320 None,321 120,322 root(),323 call.clone(),324 ));325 }326327 328 run_to_block(24);329 assert_eq!(logger::log().len(), 6);330331 assert_eq!(332 System::events().last().unwrap().event,333 crate::Event::PeriodicFailed { task: (24, 0), id: None }.into(),334 );335 });336}337338#[test]339fn scheduler_respects_priority_ordering() {340 let max_weight: Weight = <Test as Config>::MaximumWeight::get();341 new_test_ext().execute_with(|| {342 let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 3 });343 assert_ok!(Scheduler::do_schedule(344 DispatchTime::At(4),345 None,346 1,347 root(),348 <ScheduledCall<Test>>::new(call).unwrap(),349 ));350 let call = RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 3 });351 assert_ok!(Scheduler::do_schedule(352 DispatchTime::At(4),353 None,354 0,355 root(),356 <ScheduledCall<Test>>::new(call).unwrap(),357 ));358 run_to_block(4);359 assert_eq!(logger::log(), vec![(root(), 69u32), (root(), 42u32)]);360 });361}362363#[test]364fn scheduler_respects_priority_ordering_with_soft_deadlines() {365 new_test_ext().execute_with(|| {366 let max_weight: Weight = <Test as Config>::MaximumWeight::get();367 let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 5 * 2 });368 assert_ok!(Scheduler::do_schedule(369 DispatchTime::At(4),370 None,371 255,372 root(),373 <ScheduledCall<Test>>::new(call).unwrap(),374 ));375 let call = RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 5 * 2 });376 assert_ok!(Scheduler::do_schedule(377 DispatchTime::At(4),378 None,379 127,380 root(),381 <ScheduledCall<Test>>::new(call).unwrap(),382 ));383 let call = RuntimeCall::Logger(LoggerCall::log { i: 2600, weight: max_weight / 5 * 4 });384 assert_ok!(Scheduler::do_schedule(385 DispatchTime::At(4),386 None,387 126,388 root(),389 <ScheduledCall<Test>>::new(call).unwrap(),390 ));391392 393 run_to_block(4);394 assert_eq!(logger::log(), vec![(root(), 2600u32)]);395 396 run_to_block(5);397 assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]);398 });399}400401#[test]402fn on_initialize_weight_is_correct() {403 new_test_ext().execute_with(|| {404 let call_weight = Weight::from_ref_time(25);405406 407 let call = RuntimeCall::Logger(LoggerCall::log {408 i: 3,409 weight: call_weight + Weight::from_ref_time(1),410 });411 assert_ok!(Scheduler::do_schedule_named(412 [1u8; 32],413 DispatchTime::At(3),414 None,415 255,416 root(),417 <ScheduledCall<Test>>::new(call).unwrap(),418 ));419 let call = RuntimeCall::Logger(LoggerCall::log {420 i: 42,421 weight: call_weight + Weight::from_ref_time(2),422 });423 424 assert_ok!(Scheduler::do_schedule(425 DispatchTime::At(2),426 Some((1000, 3)),427 128,428 root(),429 <ScheduledCall<Test>>::new(call).unwrap(),430 ));431 let call = RuntimeCall::Logger(LoggerCall::log {432 i: 69,433 weight: call_weight + Weight::from_ref_time(3),434 });435 436 assert_ok!(Scheduler::do_schedule(437 DispatchTime::At(2),438 None,439 127,440 root(),441 <ScheduledCall<Test>>::new(call).unwrap(),442 ));443 444 let call = RuntimeCall::Logger(LoggerCall::log {445 i: 2600,446 weight: call_weight + Weight::from_ref_time(4),447 });448 assert_ok!(Scheduler::do_schedule_named(449 [2u8; 32],450 DispatchTime::At(1),451 Some((1000, 3)),452 126,453 root(),454 <ScheduledCall<Test>>::new(call).unwrap(),455 ));456457 458 assert_eq!(459 Scheduler::on_initialize(1),460 TestWeightInfo::service_agendas_base() +461 TestWeightInfo::service_agenda_base(1) +462 <TestWeightInfo as MarginalWeightInfo>::service_task(None, true, true) +463 TestWeightInfo::execute_dispatch_unsigned() +464 call_weight + Weight::from_ref_time(4)465 );466 assert_eq!(IncompleteSince::<Test>::get(), None);467 assert_eq!(logger::log(), vec![(root(), 2600u32)]);468469 470 assert_eq!(471 Scheduler::on_initialize(2),472 TestWeightInfo::service_agendas_base() +473 TestWeightInfo::service_agenda_base(2) +474 <TestWeightInfo as MarginalWeightInfo>::service_task(None, false, true) +475 TestWeightInfo::execute_dispatch_unsigned() +476 call_weight + Weight::from_ref_time(3) +477 <TestWeightInfo as MarginalWeightInfo>::service_task(None, false, false) +478 TestWeightInfo::execute_dispatch_unsigned() +479 call_weight + Weight::from_ref_time(2)480 );481 assert_eq!(IncompleteSince::<Test>::get(), None);482 assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]);483484 485 assert_eq!(486 Scheduler::on_initialize(3),487 TestWeightInfo::service_agendas_base() +488 TestWeightInfo::service_agenda_base(1) +489 <TestWeightInfo as MarginalWeightInfo>::service_task(None, true, false) +490 TestWeightInfo::execute_dispatch_unsigned() +491 call_weight + Weight::from_ref_time(1)492 );493 assert_eq!(IncompleteSince::<Test>::get(), None);494 assert_eq!(495 logger::log(),496 vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32), (root(), 3u32)]497 );498499 500 let actual_weight = Scheduler::on_initialize(4);501 assert_eq!(502 actual_weight,503 TestWeightInfo::service_agendas_base() + TestWeightInfo::service_agenda_base(0)504 );505 });506}507508#[test]509fn root_calls_works() {510 new_test_ext().execute_with(|| {511 let call = Box::new(RuntimeCall::Logger(LoggerCall::log {512 i: 69,513 weight: Weight::from_ref_time(10),514 }));515 let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log {516 i: 42,517 weight: Weight::from_ref_time(10),518 }));519 assert_ok!(520 Scheduler::schedule_named(RuntimeOrigin::root(), [1u8; 32], 4, None, Some(127), call,)521 );522 assert_ok!(Scheduler::schedule(RuntimeOrigin::root(), 4, None, Some(127), call2));523 run_to_block(3);524 525 assert_eq!(Agenda::<Test>::get(4).len(), 2);526 assert!(logger::log().is_empty());527 assert_ok!(Scheduler::cancel_named(RuntimeOrigin::root(), [1u8; 32]));528 assert_ok!(Scheduler::cancel(RuntimeOrigin::root(), 4, 1));529 530 run_to_block(100);531 assert!(logger::log().is_empty());532 });533}534535#[test]536fn fails_to_schedule_task_in_the_past() {537 new_test_ext().execute_with(|| {538 run_to_block(3);539540 let call1 = Box::new(RuntimeCall::Logger(LoggerCall::log {541 i: 69,542 weight: Weight::from_ref_time(10),543 }));544 let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log {545 i: 42,546 weight: Weight::from_ref_time(10),547 }));548 let call3 = Box::new(RuntimeCall::Logger(LoggerCall::log {549 i: 42,550 weight: Weight::from_ref_time(10),551 }));552553 assert_noop!(554 Scheduler::schedule_named(RuntimeOrigin::root(), [1u8; 32], 2, None, Some(127), call1),555 Error::<Test>::TargetBlockNumberInPast,556 );557558 assert_noop!(559 Scheduler::schedule(RuntimeOrigin::root(), 2, None, Some(127), call2),560 Error::<Test>::TargetBlockNumberInPast,561 );562563 assert_noop!(564 Scheduler::schedule(RuntimeOrigin::root(), 3, None, Some(127), call3),565 Error::<Test>::TargetBlockNumberInPast,566 );567 });568}569570#[test]571fn should_use_origin() {572 new_test_ext().execute_with(|| {573 let call = Box::new(RuntimeCall::Logger(LoggerCall::log {574 i: 69,575 weight: Weight::from_ref_time(10),576 }));577 let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log {578 i: 42,579 weight: Weight::from_ref_time(10),580 }));581 assert_ok!(Scheduler::schedule_named(582 system::RawOrigin::Signed(1).into(),583 [1u8; 32],584 4,585 None,586 None,587 call,588 ));589 assert_ok!(Scheduler::schedule(system::RawOrigin::Signed(1).into(), 4, None, None, call2,));590 run_to_block(3);591 592 assert_eq!(Agenda::<Test>::get(4).len(), 2);593 assert!(logger::log().is_empty());594 assert_ok!(Scheduler::cancel_named(system::RawOrigin::Signed(1).into(), [1u8; 32]));595 assert_ok!(Scheduler::cancel(system::RawOrigin::Signed(1).into(), 4, 1));596 597 run_to_block(100);598 assert!(logger::log().is_empty());599 });600}601602#[test]603fn should_check_origin() {604 new_test_ext().execute_with(|| {605 let call = Box::new(RuntimeCall::Logger(LoggerCall::log {606 i: 69,607 weight: Weight::from_ref_time(10),608 }));609 let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log {610 i: 42,611 weight: Weight::from_ref_time(10),612 }));613 assert_noop!(614 Scheduler::schedule_named(615 system::RawOrigin::Signed(2).into(),616 [1u8; 32],617 4,618 None,619 None,620 call621 ),622 BadOrigin623 );624 assert_noop!(625 Scheduler::schedule(system::RawOrigin::Signed(2).into(), 4, None, None, call2),626 BadOrigin627 );628 });629}630631#[test]632fn should_check_origin_for_cancel() {633 new_test_ext().execute_with(|| {634 let call = Box::new(RuntimeCall::Logger(LoggerCall::log_without_filter {635 i: 69,636 weight: Weight::from_ref_time(10),637 }));638 let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log_without_filter {639 i: 42,640 weight: Weight::from_ref_time(10),641 }));642 assert_ok!(Scheduler::schedule_named(643 system::RawOrigin::Signed(1).into(),644 [1u8; 32],645 4,646 None,647 None,648 call,649 ));650 assert_ok!(Scheduler::schedule(system::RawOrigin::Signed(1).into(), 4, None, None, call2,));651 run_to_block(3);652 653 assert_eq!(Agenda::<Test>::get(4).len(), 2);654 assert!(logger::log().is_empty());655 assert_noop!(656 Scheduler::cancel_named(system::RawOrigin::Signed(2).into(), [1u8; 32]),657 BadOrigin658 );659 assert_noop!(Scheduler::cancel(system::RawOrigin::Signed(2).into(), 4, 1), BadOrigin);660 assert_noop!(Scheduler::cancel_named(system::RawOrigin::Root.into(), [1u8; 32]), BadOrigin);661 assert_noop!(Scheduler::cancel(system::RawOrigin::Root.into(), 4, 1), BadOrigin);662 run_to_block(5);663 assert_eq!(664 logger::log(),665 vec![666 (system::RawOrigin::Signed(1).into(), 69u32),667 (system::RawOrigin::Signed(1).into(), 42u32)668 ]669 );670 });671}672673674675#[test]676fn schedule_does_not_resuse_addr() {677 new_test_ext().execute_with(|| {678 let call =679 RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });680681 682 let addr_1 = Scheduler::do_schedule(683 DispatchTime::At(4),684 None,685 127,686 root(),687 <ScheduledCall<Test>>::new(call.clone()).unwrap(),688 )689 .unwrap();690 691 assert_ok!(Scheduler::do_cancel(None, addr_1));692 let addr_2 = Scheduler::do_schedule(693 DispatchTime::At(4),694 None,695 127,696 root(),697 <ScheduledCall<Test>>::new(call).unwrap(),698 )699 .unwrap();700701 702 assert!(addr_1 != addr_2);703 });704}705706#[test]707fn schedule_agenda_overflows() {708 let max: u32 = <Test as Config>::MaxScheduledPerBlock::get();709710 new_test_ext().execute_with(|| {711 let call =712 RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });713 let call = <ScheduledCall<Test>>::new(call).unwrap();714715 716 for _ in 0..max {717 Scheduler::do_schedule(718 DispatchTime::At(4),719 None,720 127,721 root(),722 call.clone(),723 )724 .unwrap();725 }726727 728 assert_noop!(729 Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call,),730 <Error<Test>>::AgendaIsExhausted,731 );732733 run_to_block(4);734 735 assert_eq!(logger::log().len() as u32, max);736 });737}738739740#[test]741fn cancel_and_schedule_fills_holes() {742 let max: u32 = <Test as Config>::MaxScheduledPerBlock::get();743 assert!(max > 3, "This test only makes sense for MaxScheduledPerBlock > 3");744745 new_test_ext().execute_with(|| {746 let call =747 RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });748 let call = <ScheduledCall<Test>>::new(call).unwrap();749 let mut addrs = Vec::<_>::default();750751 752 for _ in 0..max {753 addrs.push(754 Scheduler::do_schedule(755 DispatchTime::At(4),756 None,757 127,758 root(),759 call.clone(),760 )761 .unwrap(),762 );763 }764 765 for addr in addrs.into_iter().take(3) {766 Scheduler::do_cancel(None, addr).unwrap();767 }768 769 for i in 0..3 {770 let (_block, index) = Scheduler::do_schedule(771 DispatchTime::At(4),772 None,773 127,774 root(),775 call.clone(),776 )777 .unwrap();778 assert_eq!(i, index);779 }780781 run_to_block(4);782 783 assert_eq!(logger::log().len() as u32, max);784 });785}