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, OnInitialize},44};4546#[test]47fn basic_scheduling_works() {48 new_test_ext().execute_with(|| {49 let call =50 RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });51 assert!(!<Test as frame_system::Config>::BaseCallFilter::contains(&call));52 assert_ok!(Scheduler::do_schedule(53 DispatchTime::At(4),54 None,55 127,56 root(),57 <ScheduledCall<Test>>::new(call).unwrap(),58 ));59 run_to_block(3);60 assert!(logger::log().is_empty());61 run_to_block(4);62 assert_eq!(logger::log(), vec![(root(), 42u32)]);63 run_to_block(100);64 assert_eq!(logger::log(), vec![(root(), 42u32)]);65 });66}6768#[test]69fn schedule_after_works() {70 new_test_ext().execute_with(|| {71 run_to_block(2);72 let call =73 RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });74 assert!(!<Test as frame_system::Config>::BaseCallFilter::contains(&call));75 76 assert_ok!(Scheduler::do_schedule(77 DispatchTime::After(3),78 None,79 127,80 root(),81 <ScheduledCall<Test>>::new(call).unwrap(),82 ));83 run_to_block(5);84 assert!(logger::log().is_empty());85 run_to_block(6);86 assert_eq!(logger::log(), vec![(root(), 42u32)]);87 run_to_block(100);88 assert_eq!(logger::log(), vec![(root(), 42u32)]);89 });90}9192#[test]93fn schedule_after_zero_works() {94 new_test_ext().execute_with(|| {95 run_to_block(2);96 let call =97 RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });98 assert!(!<Test as frame_system::Config>::BaseCallFilter::contains(&call));99 assert_ok!(Scheduler::do_schedule(100 DispatchTime::After(0),101 None,102 127,103 root(),104 <ScheduledCall<Test>>::new(call).unwrap(),105 ));106 107 run_to_block(3);108 assert_eq!(logger::log(), vec![(root(), 42u32)]);109 run_to_block(100);110 assert_eq!(logger::log(), vec![(root(), 42u32)]);111 });112}113114#[test]115fn periodic_scheduling_works() {116 new_test_ext().execute_with(|| {117 118 assert_ok!(Scheduler::do_schedule(119 DispatchTime::At(4),120 Some((3, 3)),121 127,122 root(),123 <ScheduledCall<Test>>::new(RuntimeCall::Logger(logger::Call::log {124 i: 42,125 weight: Weight::from_ref_time(10)126 }))127 .unwrap()128 ));129 run_to_block(3);130 assert!(logger::log().is_empty());131 run_to_block(4);132 assert_eq!(logger::log(), vec![(root(), 42u32)]);133 run_to_block(6);134 assert_eq!(logger::log(), vec![(root(), 42u32)]);135 run_to_block(7);136 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]);137 run_to_block(9);138 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32)]);139 run_to_block(10);140 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]);141 run_to_block(100);142 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 42u32), (root(), 42u32)]);143 });144}145146#[test]147fn cancel_named_scheduling_works_with_normal_cancel() {148 new_test_ext().execute_with(|| {149 150 Scheduler::do_schedule_named(151 [1u8; 32],152 DispatchTime::At(4),153 None,154 127,155 root(),156 <ScheduledCall<Test>>::new(RuntimeCall::Logger(LoggerCall::log {157 i: 69,158 weight: Weight::from_ref_time(10),159 }))160 .unwrap(),161 )162 .unwrap();163 let i = Scheduler::do_schedule(164 DispatchTime::At(4),165 None,166 127,167 root(),168 <ScheduledCall<Test>>::new(RuntimeCall::Logger(LoggerCall::log {169 i: 42,170 weight: Weight::from_ref_time(10),171 }))172 .unwrap(),173 )174 .unwrap();175 run_to_block(3);176 assert!(logger::log().is_empty());177 assert_ok!(Scheduler::do_cancel_named(None, [1u8; 32]));178 assert_ok!(Scheduler::do_cancel(None, i));179 run_to_block(100);180 assert!(logger::log().is_empty());181 });182}183184#[test]185fn cancel_named_periodic_scheduling_works() {186 new_test_ext().execute_with(|| {187 188 Scheduler::do_schedule_named(189 [1u8; 32],190 DispatchTime::At(4),191 Some((3, 3)),192 127,193 root(),194 <ScheduledCall<Test>>::new(RuntimeCall::Logger(LoggerCall::log {195 i: 42,196 weight: Weight::from_ref_time(10),197 }))198 .unwrap(),199 )200 .unwrap();201 202 assert!(Scheduler::do_schedule_named(203 [1u8; 32],204 DispatchTime::At(4),205 None,206 127,207 root(),208 <ScheduledCall<Test>>::new(RuntimeCall::Logger(LoggerCall::log {209 i: 69,210 weight: Weight::from_ref_time(10)211 }))212 .unwrap(),213 )214 .is_err());215 216 Scheduler::do_schedule_named(217 [2u8; 32],218 DispatchTime::At(8),219 None,220 127,221 root(),222 <ScheduledCall<Test>>::new(RuntimeCall::Logger(LoggerCall::log {223 i: 69,224 weight: Weight::from_ref_time(10),225 }))226 .unwrap(),227 )228 .unwrap();229 run_to_block(3);230 assert!(logger::log().is_empty());231 run_to_block(4);232 assert_eq!(logger::log(), vec![(root(), 42u32)]);233 run_to_block(6);234 assert_ok!(Scheduler::do_cancel_named(None, [1u8; 32]));235 run_to_block(100);236 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]);237 });238}239240#[test]241fn scheduler_respects_weight_limits() {242 let max_weight: Weight = <Test as Config>::MaximumWeight::get();243 new_test_ext().execute_with(|| {244 let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 3 * 2 });245 assert_ok!(Scheduler::do_schedule(246 DispatchTime::At(4),247 None,248 127,249 root(),250 <ScheduledCall<Test>>::new(call).unwrap(),251 ));252 let call = RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 3 * 2 });253 assert_ok!(Scheduler::do_schedule(254 DispatchTime::At(4),255 None,256 127,257 root(),258 <ScheduledCall<Test>>::new(call).unwrap(),259 ));260 261 run_to_block(4);262 assert_eq!(logger::log(), vec![(root(), 42u32)]);263 run_to_block(5);264 assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]);265 });266}267268269#[test]270fn scheduler_does_not_delete_permanently_overweight_call() {271 let max_weight: Weight = <Test as Config>::MaximumWeight::get();272 new_test_ext().execute_with(|| {273 let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight });274 assert_ok!(Scheduler::do_schedule(275 DispatchTime::At(4),276 None,277 127,278 root(),279 <ScheduledCall<Test>>::new(call).unwrap(),280 ));281 282 run_to_block(100);283 assert_eq!(logger::log(), vec![]);284285 286 assert_eq!(287 System::events().last().unwrap().event,288 crate::Event::PermanentlyOverweight { task: (4, 0), id: None }.into(),289 );290 291 assert!(Agenda::<Test>::get(4)[0].is_some());292 });293}294295#[test]296fn scheduler_handles_periodic_failure() {297 let max_weight: Weight = <Test as Config>::MaximumWeight::get();298 let max_per_block = <Test as Config>::MaxScheduledPerBlock::get();299300 new_test_ext().execute_with(|| {301 let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: (max_weight / 3) * 2 });302 let call = <ScheduledCall<Test>>::new(call).unwrap();303304 assert_ok!(Scheduler::do_schedule(305 DispatchTime::At(4),306 Some((4, u32::MAX)),307 127,308 root(),309 call.clone(),310 ));311 312 run_to_block(20);313 assert_eq!(logger::log().len(), 5);314315 316 for _ in 0..max_per_block {317 assert_ok!(Scheduler::do_schedule(318 DispatchTime::At(28),319 None,320 120,321 root(),322 call.clone(),323 ));324 }325326 327 run_to_block(24);328 assert_eq!(logger::log().len(), 6);329330 assert_eq!(331 System::events().last().unwrap().event,332 crate::Event::PeriodicFailed { task: (24, 0), id: None }.into(),333 );334 });335}336337#[test]338fn scheduler_respects_priority_ordering() {339 let max_weight: Weight = <Test as Config>::MaximumWeight::get();340 new_test_ext().execute_with(|| {341 let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 3 });342 assert_ok!(Scheduler::do_schedule(343 DispatchTime::At(4),344 None,345 1,346 root(),347 <ScheduledCall<Test>>::new(call).unwrap(),348 ));349 let call = RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 3 });350 assert_ok!(Scheduler::do_schedule(351 DispatchTime::At(4),352 None,353 0,354 root(),355 <ScheduledCall<Test>>::new(call).unwrap(),356 ));357 run_to_block(4);358 assert_eq!(logger::log(), vec![(root(), 69u32), (root(), 42u32)]);359 });360}361362#[test]363fn scheduler_respects_priority_ordering_with_soft_deadlines() {364 new_test_ext().execute_with(|| {365 let max_weight: Weight = <Test as Config>::MaximumWeight::get();366 let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 5 * 2 });367 assert_ok!(Scheduler::do_schedule(368 DispatchTime::At(4),369 None,370 255,371 root(),372 <ScheduledCall<Test>>::new(call).unwrap(),373 ));374 let call = RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 5 * 2 });375 assert_ok!(Scheduler::do_schedule(376 DispatchTime::At(4),377 None,378 127,379 root(),380 <ScheduledCall<Test>>::new(call).unwrap(),381 ));382 let call = RuntimeCall::Logger(LoggerCall::log { i: 2600, weight: max_weight / 5 * 4 });383 assert_ok!(Scheduler::do_schedule(384 DispatchTime::At(4),385 None,386 126,387 root(),388 <ScheduledCall<Test>>::new(call).unwrap(),389 ));390391 392 run_to_block(4);393 assert_eq!(logger::log(), vec![(root(), 2600u32)]);394 395 run_to_block(5);396 assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]);397 });398}399400#[test]401fn on_initialize_weight_is_correct() {402 new_test_ext().execute_with(|| {403 let call_weight = Weight::from_ref_time(25);404405 406 let call = RuntimeCall::Logger(LoggerCall::log {407 i: 3,408 weight: call_weight + Weight::from_ref_time(1),409 });410 assert_ok!(Scheduler::do_schedule_named(411 [1u8; 32],412 DispatchTime::At(3),413 None,414 255,415 root(),416 <ScheduledCall<Test>>::new(call).unwrap(),417 ));418 let call = RuntimeCall::Logger(LoggerCall::log {419 i: 42,420 weight: call_weight + Weight::from_ref_time(2),421 });422 423 assert_ok!(Scheduler::do_schedule(424 DispatchTime::At(2),425 Some((1000, 3)),426 128,427 root(),428 <ScheduledCall<Test>>::new(call).unwrap(),429 ));430 let call = RuntimeCall::Logger(LoggerCall::log {431 i: 69,432 weight: call_weight + Weight::from_ref_time(3),433 });434 435 assert_ok!(Scheduler::do_schedule(436 DispatchTime::At(2),437 None,438 127,439 root(),440 <ScheduledCall<Test>>::new(call).unwrap(),441 ));442 443 let call = RuntimeCall::Logger(LoggerCall::log {444 i: 2600,445 weight: call_weight + Weight::from_ref_time(4),446 });447 assert_ok!(Scheduler::do_schedule_named(448 [2u8; 32],449 DispatchTime::At(1),450 Some((1000, 3)),451 126,452 root(),453 <ScheduledCall<Test>>::new(call).unwrap(),454 ));455456 457 assert_eq!(458 Scheduler::on_initialize(1),459 TestWeightInfo::service_agendas_base() +460 TestWeightInfo::service_agenda_base(1) +461 <TestWeightInfo as MarginalWeightInfo>::service_task(None, true, true) +462 TestWeightInfo::execute_dispatch_unsigned() +463 call_weight + Weight::from_ref_time(4)464 );465 assert_eq!(IncompleteSince::<Test>::get(), None);466 assert_eq!(logger::log(), vec![(root(), 2600u32)]);467468 469 assert_eq!(470 Scheduler::on_initialize(2),471 TestWeightInfo::service_agendas_base() +472 TestWeightInfo::service_agenda_base(2) +473 <TestWeightInfo as MarginalWeightInfo>::service_task(None, false, true) +474 TestWeightInfo::execute_dispatch_unsigned() +475 call_weight + Weight::from_ref_time(3) +476 <TestWeightInfo as MarginalWeightInfo>::service_task(None, false, false) +477 TestWeightInfo::execute_dispatch_unsigned() +478 call_weight + Weight::from_ref_time(2)479 );480 assert_eq!(IncompleteSince::<Test>::get(), None);481 assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]);482483 484 assert_eq!(485 Scheduler::on_initialize(3),486 TestWeightInfo::service_agendas_base() +487 TestWeightInfo::service_agenda_base(1) +488 <TestWeightInfo as MarginalWeightInfo>::service_task(None, true, false) +489 TestWeightInfo::execute_dispatch_unsigned() +490 call_weight + Weight::from_ref_time(1)491 );492 assert_eq!(IncompleteSince::<Test>::get(), None);493 assert_eq!(494 logger::log(),495 vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32), (root(), 3u32)]496 );497498 499 let actual_weight = Scheduler::on_initialize(4);500 assert_eq!(501 actual_weight,502 TestWeightInfo::service_agendas_base() + TestWeightInfo::service_agenda_base(0)503 );504 });505}506507#[test]508fn root_calls_works() {509 new_test_ext().execute_with(|| {510 let call = Box::new(RuntimeCall::Logger(LoggerCall::log {511 i: 69,512 weight: Weight::from_ref_time(10),513 }));514 let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log {515 i: 42,516 weight: Weight::from_ref_time(10),517 }));518 assert_ok!(519 Scheduler::schedule_named(RuntimeOrigin::root(), [1u8; 32], 4, None, Some(127), call,)520 );521 assert_ok!(Scheduler::schedule(RuntimeOrigin::root(), 4, None, Some(127), call2));522 run_to_block(3);523 524 assert_eq!(Agenda::<Test>::get(4).len(), 2);525 assert!(logger::log().is_empty());526 assert_ok!(Scheduler::cancel_named(RuntimeOrigin::root(), [1u8; 32]));527 assert_ok!(Scheduler::cancel(RuntimeOrigin::root(), 4, 1));528 529 run_to_block(100);530 assert!(logger::log().is_empty());531 });532}533534#[test]535fn fails_to_schedule_task_in_the_past() {536 new_test_ext().execute_with(|| {537 run_to_block(3);538539 let call1 = Box::new(RuntimeCall::Logger(LoggerCall::log {540 i: 69,541 weight: Weight::from_ref_time(10),542 }));543 let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log {544 i: 42,545 weight: Weight::from_ref_time(10),546 }));547 let call3 = Box::new(RuntimeCall::Logger(LoggerCall::log {548 i: 42,549 weight: Weight::from_ref_time(10),550 }));551552 assert_noop!(553 Scheduler::schedule_named(RuntimeOrigin::root(), [1u8; 32], 2, None, Some(127), call1),554 Error::<Test>::TargetBlockNumberInPast,555 );556557 assert_noop!(558 Scheduler::schedule(RuntimeOrigin::root(), 2, None, Some(127), call2),559 Error::<Test>::TargetBlockNumberInPast,560 );561562 assert_noop!(563 Scheduler::schedule(RuntimeOrigin::root(), 3, None, Some(127), call3),564 Error::<Test>::TargetBlockNumberInPast,565 );566 });567}568569#[test]570fn should_use_origin() {571 new_test_ext().execute_with(|| {572 let call = Box::new(RuntimeCall::Logger(LoggerCall::log {573 i: 69,574 weight: Weight::from_ref_time(10),575 }));576 let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log {577 i: 42,578 weight: Weight::from_ref_time(10),579 }));580 assert_ok!(Scheduler::schedule_named(581 system::RawOrigin::Signed(1).into(),582 [1u8; 32],583 4,584 None,585 None,586 call,587 ));588 assert_ok!(Scheduler::schedule(system::RawOrigin::Signed(1).into(), 4, None, None, call2,));589 run_to_block(3);590 591 assert_eq!(Agenda::<Test>::get(4).len(), 2);592 assert!(logger::log().is_empty());593 assert_ok!(Scheduler::cancel_named(system::RawOrigin::Signed(1).into(), [1u8; 32]));594 assert_ok!(Scheduler::cancel(system::RawOrigin::Signed(1).into(), 4, 1));595 596 run_to_block(100);597 assert!(logger::log().is_empty());598 });599}600601#[test]602fn should_check_origin() {603 new_test_ext().execute_with(|| {604 let call = Box::new(RuntimeCall::Logger(LoggerCall::log {605 i: 69,606 weight: Weight::from_ref_time(10),607 }));608 let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log {609 i: 42,610 weight: Weight::from_ref_time(10),611 }));612 assert_noop!(613 Scheduler::schedule_named(614 system::RawOrigin::Signed(2).into(),615 [1u8; 32],616 4,617 None,618 None,619 call620 ),621 BadOrigin622 );623 assert_noop!(624 Scheduler::schedule(system::RawOrigin::Signed(2).into(), 4, None, None, call2),625 BadOrigin626 );627 });628}629630#[test]631fn should_check_origin_for_cancel() {632 new_test_ext().execute_with(|| {633 let call = Box::new(RuntimeCall::Logger(LoggerCall::log_without_filter {634 i: 69,635 weight: Weight::from_ref_time(10),636 }));637 let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log_without_filter {638 i: 42,639 weight: Weight::from_ref_time(10),640 }));641 assert_ok!(Scheduler::schedule_named(642 system::RawOrigin::Signed(1).into(),643 [1u8; 32],644 4,645 None,646 None,647 call,648 ));649 assert_ok!(Scheduler::schedule(system::RawOrigin::Signed(1).into(), 4, None, None, call2,));650 run_to_block(3);651 652 assert_eq!(Agenda::<Test>::get(4).len(), 2);653 assert!(logger::log().is_empty());654 assert_noop!(655 Scheduler::cancel_named(system::RawOrigin::Signed(2).into(), [1u8; 32]),656 BadOrigin657 );658 assert_noop!(Scheduler::cancel(system::RawOrigin::Signed(2).into(), 4, 1), BadOrigin);659 assert_noop!(Scheduler::cancel_named(system::RawOrigin::Root.into(), [1u8; 32]), BadOrigin);660 assert_noop!(Scheduler::cancel(system::RawOrigin::Root.into(), 4, 1), BadOrigin);661 run_to_block(5);662 assert_eq!(663 logger::log(),664 vec![665 (system::RawOrigin::Signed(1).into(), 69u32),666 (system::RawOrigin::Signed(1).into(), 42u32)667 ]668 );669 });670}671672673674#[test]675fn schedule_does_not_resuse_addr() {676 new_test_ext().execute_with(|| {677 let call =678 RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });679680 681 let addr_1 = Scheduler::do_schedule(682 DispatchTime::At(4),683 None,684 127,685 root(),686 <ScheduledCall<Test>>::new(call.clone()).unwrap(),687 )688 .unwrap();689 690 assert_ok!(Scheduler::do_cancel(None, addr_1));691 let addr_2 = Scheduler::do_schedule(692 DispatchTime::At(4),693 None,694 127,695 root(),696 <ScheduledCall<Test>>::new(call).unwrap(),697 )698 .unwrap();699700 701 assert!(addr_1 != addr_2);702 });703}704705#[test]706fn schedule_agenda_overflows() {707 let max: u32 = <Test as Config>::MaxScheduledPerBlock::get();708709 new_test_ext().execute_with(|| {710 let call =711 RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });712 let call = <ScheduledCall<Test>>::new(call).unwrap();713714 715 for _ in 0..max {716 Scheduler::do_schedule(717 DispatchTime::At(4),718 None,719 127,720 root(),721 call.clone(),722 )723 .unwrap();724 }725726 727 assert_noop!(728 Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call,),729 <Error<Test>>::AgendaIsExhausted,730 );731732 run_to_block(4);733 734 assert_eq!(logger::log().len() as u32, max);735 });736}737738739#[test]740fn cancel_and_schedule_fills_holes() {741 let max: u32 = <Test as Config>::MaxScheduledPerBlock::get();742 assert!(max > 3, "This test only makes sense for MaxScheduledPerBlock > 3");743744 new_test_ext().execute_with(|| {745 let call =746 RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) });747 let call = <ScheduledCall<Test>>::new(call).unwrap();748 let mut addrs = Vec::<_>::default();749750 751 for _ in 0..max {752 addrs.push(753 Scheduler::do_schedule(754 DispatchTime::At(4),755 None,756 127,757 root(),758 call.clone(),759 )760 .unwrap(),761 );762 }763 764 for addr in addrs.into_iter().take(3) {765 Scheduler::do_cancel(None, addr).unwrap();766 }767 768 for i in 0..3 {769 let (_block, index) = Scheduler::do_schedule(770 DispatchTime::At(4),771 None,772 127,773 root(),774 call.clone(),775 )776 .unwrap();777 assert_eq!(i, index);778 }779780 run_to_block(4);781 782 assert_eq!(logger::log().len() as u32, max);783 });784}