From cd69f209b71c554f06d3061169ad00c5f1c170b2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?D=C3=B3nal=20Murray?= <donal.murray@parity.io>
Date: Thu, 12 Sep 2024 17:48:04 +0100
Subject: [PATCH] Add emulated tests for the Coretime Interface calls to ensure
 sufficient weights (#2704)

Add emulated test cases for the coretime chain.

This tests the calls sent across the `CoretimeInterface` and ensures the
weights are sufficient.
---
 Cargo.lock                                    |  14 +-
 .../coretime/coretime-rococo/Cargo.toml       |   2 +-
 .../coretime/coretime-westend/Cargo.toml      |   2 +-
 .../tests/coretime/coretime-rococo/Cargo.toml |   5 +-
 .../tests/coretime/coretime-rococo/src/lib.rs |   4 +-
 .../src/tests/coretime_interface.rs           | 235 ++++++++++++++++++
 .../coretime/coretime-rococo/src/tests/mod.rs |   1 +
 .../coretime/coretime-westend/Cargo.toml      |   5 +-
 .../coretime/coretime-westend/src/lib.rs      |   4 +-
 .../src/tests/coretime_interface.rs           | 223 +++++++++++++++++
 .../coretime-westend/src/tests/mod.rs         |   1 +
 11 files changed, 484 insertions(+), 12 deletions(-)
 create mode 100644 cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/coretime_interface.rs
 create mode 100644 cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/coretime_interface.rs

diff --git a/Cargo.lock b/Cargo.lock
index d30acc0f5b2..e5b12a60da2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3299,7 +3299,7 @@ dependencies = [
 
 [[package]]
 name = "coretime-rococo-emulated-chain"
-version = "0.0.0"
+version = "0.1.0"
 dependencies = [
  "coretime-rococo-runtime",
  "cumulus-primitives-core",
@@ -3312,14 +3312,17 @@ dependencies = [
 
 [[package]]
 name = "coretime-rococo-integration-tests"
-version = "0.1.0"
+version = "0.0.0"
 dependencies = [
+ "cumulus-pallet-parachain-system",
  "emulated-integration-tests-common",
  "frame-support",
  "pallet-balances",
+ "pallet-broker",
  "pallet-identity",
  "pallet-message-queue",
  "polkadot-runtime-common",
+ "polkadot-runtime-parachains",
  "rococo-runtime-constants",
  "rococo-system-emulated-network",
  "sp-runtime",
@@ -3396,7 +3399,7 @@ dependencies = [
 
 [[package]]
 name = "coretime-westend-emulated-chain"
-version = "0.0.0"
+version = "0.1.0"
 dependencies = [
  "coretime-westend-runtime",
  "cumulus-primitives-core",
@@ -3409,14 +3412,17 @@ dependencies = [
 
 [[package]]
 name = "coretime-westend-integration-tests"
-version = "0.1.0"
+version = "0.0.0"
 dependencies = [
+ "cumulus-pallet-parachain-system",
  "emulated-integration-tests-common",
  "frame-support",
  "pallet-balances",
+ "pallet-broker",
  "pallet-identity",
  "pallet-message-queue",
  "polkadot-runtime-common",
+ "polkadot-runtime-parachains",
  "sp-runtime",
  "staging-xcm",
  "staging-xcm-executor",
diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/Cargo.toml
index 6af3f270a90..94d43c5eee2 100644
--- a/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/Cargo.toml
+++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-rococo/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "coretime-rococo-emulated-chain"
-version = "0.0.0"
+version = "0.1.0"
 authors.workspace = true
 edition.workspace = true
 license = "Apache-2.0"
diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/Cargo.toml
index 895a984eccb..2640c27d016 100644
--- a/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/Cargo.toml
+++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/coretime/coretime-westend/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "coretime-westend-emulated-chain"
-version = "0.0.0"
+version = "0.1.0"
 authors.workspace = true
 edition.workspace = true
 license = "Apache-2.0"
diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/Cargo.toml
index 259be790c3e..28d9da0993f 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/Cargo.toml
+++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "coretime-rococo-integration-tests"
-version = "0.1.0"
+version = "0.0.0"
 authors.workspace = true
 edition.workspace = true
 license = "Apache-2.0"
@@ -12,16 +12,19 @@ publish = false
 # Substrate
 frame-support = { workspace = true }
 pallet-balances = { workspace = true }
+pallet-broker = { workspace = true, default-features = true }
 pallet-message-queue = { workspace = true }
 pallet-identity = { workspace = true }
 sp-runtime = { workspace = true }
 
 # Polkadot
 polkadot-runtime-common = { workspace = true, default-features = true }
+polkadot-runtime-parachains = { workspace = true, default-features = true }
 rococo-runtime-constants = { workspace = true, default-features = true }
 xcm = { workspace = true }
 xcm-executor = { workspace = true }
 
 # Cumulus
+cumulus-pallet-parachain-system = { workspace = true, default-features = true }
 emulated-integration-tests-common = { workspace = true }
 rococo-system-emulated-network = { workspace = true }
diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs
index ad3c4fd58da..055bd50d829 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs
@@ -24,7 +24,7 @@ mod imports {
 
 	// Cumulus
 	pub use emulated_integration_tests_common::xcm_emulator::{
-		assert_expected_events, bx, TestExt,
+		assert_expected_events, bx, Chain, Parachain, TestExt,
 	};
 	pub use rococo_system_emulated_network::{
 		coretime_rococo_emulated_chain::{
@@ -32,7 +32,7 @@ mod imports {
 			CoretimeRococoParaPallet as CoretimeRococoPallet,
 		},
 		CoretimeRococoPara as CoretimeRococo, CoretimeRococoParaReceiver as CoretimeRococoReceiver,
-		CoretimeRococoParaSender as CoretimeRococoSender,
+		CoretimeRococoParaSender as CoretimeRococoSender, RococoRelay as Rococo,
 	};
 }
 
diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/coretime_interface.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/coretime_interface.rs
new file mode 100644
index 00000000000..584bce8f1df
--- /dev/null
+++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/coretime_interface.rs
@@ -0,0 +1,235 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use crate::imports::*;
+use frame_support::traits::OnInitialize;
+use pallet_broker::{ConfigRecord, Configuration, CoreAssignment, CoreMask, ScheduleItem};
+use rococo_runtime_constants::system_parachain::coretime::TIMESLICE_PERIOD;
+use sp_runtime::Perbill;
+
+#[test]
+fn transact_hardcoded_weights_are_sane() {
+	// There are three transacts with hardcoded weights sent from the Coretime Chain to the Relay
+	// Chain across the CoretimeInterface which are triggered at various points in the sales cycle.
+	// - Request core count - triggered directly by `start_sales` or `request_core_count`
+	//   extrinsics.
+	// - Request revenue info - triggered when each timeslice is committed.
+	// - Assign core - triggered when an entry is encountered in the workplan for the next
+	//   timeslice.
+
+	// RuntimeEvent aliases to avoid warning from usage of qualified paths in assertions due to
+	// <https://github.com/rust-lang/rust/issues/86935>
+	type CoretimeEvent = <CoretimeRococo as Chain>::RuntimeEvent;
+	type RelayEvent = <Rococo as Chain>::RuntimeEvent;
+
+	// Reserve a workload, configure broker and start sales.
+	CoretimeRococo::execute_with(|| {
+		// Hooks don't run in emulated tests - workaround as we need `on_initialize` to tick things
+		// along and have no concept of time passing otherwise.
+		<CoretimeRococo as CoretimeRococoPallet>::Broker::on_initialize(
+			<CoretimeRococo as Chain>::System::block_number(),
+		);
+
+		let coretime_root_origin = <CoretimeRococo as Chain>::RuntimeOrigin::root();
+
+		// Create and populate schedule with the worst case assignment on this core.
+		let mut schedule = Vec::new();
+		for i in 0..27 {
+			schedule.push(ScheduleItem {
+				mask: CoreMask::void().set(i),
+				assignment: CoreAssignment::Task(2000 + i),
+			})
+		}
+
+		assert_ok!(<CoretimeRococo as CoretimeRococoPallet>::Broker::reserve(
+			coretime_root_origin.clone(),
+			schedule.try_into().expect("Vector is within bounds."),
+		));
+
+		// Configure broker and start sales.
+		let config = ConfigRecord {
+			advance_notice: 1,
+			interlude_length: 1,
+			leadin_length: 2,
+			region_length: 1,
+			ideal_bulk_proportion: Perbill::from_percent(40),
+			limit_cores_offered: None,
+			renewal_bump: Perbill::from_percent(2),
+			contribution_timeout: 1,
+		};
+		assert_ok!(<CoretimeRococo as CoretimeRococoPallet>::Broker::configure(
+			coretime_root_origin.clone(),
+			config
+		));
+		assert_ok!(<CoretimeRococo as CoretimeRococoPallet>::Broker::start_sales(
+			coretime_root_origin,
+			100,
+			0
+		));
+		assert_eq!(
+			pallet_broker::Status::<<CoretimeRococo as Chain>::Runtime>::get()
+				.unwrap()
+				.core_count,
+			1
+		);
+
+		assert_expected_events!(
+			CoretimeRococo,
+			vec![
+				CoretimeEvent::Broker(
+					pallet_broker::Event::ReservationMade { .. }
+				) => {},
+				CoretimeEvent::Broker(
+					pallet_broker::Event::CoreCountRequested { core_count: 1 }
+				) => {},
+				CoretimeEvent::ParachainSystem(
+					cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }
+				) => {},
+			]
+		);
+	});
+
+	// Check that the request_core_count message was processed successfully. This will fail if the
+	// weights are misconfigured.
+	Rococo::execute_with(|| {
+		Rococo::assert_ump_queue_processed(true, Some(CoretimeRococo::para_id()), None);
+
+		assert_expected_events!(
+			Rococo,
+			vec![
+				RelayEvent::MessageQueue(
+					pallet_message_queue::Event::Processed { success: true, .. }
+				) => {},
+			]
+		);
+	});
+
+	// Keep track of the relay chain block number so we can fast forward while still checking the
+	// right block.
+	let mut block_number_cursor = Rococo::ext_wrapper(<Rococo as Chain>::System::block_number);
+
+	let config = CoretimeRococo::ext_wrapper(|| {
+		Configuration::<<CoretimeRococo as Chain>::Runtime>::get()
+			.expect("Pallet was configured earlier.")
+	});
+
+	// Now run up to the block before the sale is rotated.
+	while block_number_cursor < TIMESLICE_PERIOD - config.advance_notice - 1 {
+		CoretimeRococo::execute_with(|| {
+			// Hooks don't run in emulated tests - workaround.
+			<CoretimeRococo as CoretimeRococoPallet>::Broker::on_initialize(
+				<CoretimeRococo as Chain>::System::block_number(),
+			);
+		});
+
+		Rococo::ext_wrapper(|| {
+			block_number_cursor = <Rococo as Chain>::System::block_number();
+		});
+	}
+
+	// In this block we trigger assign core.
+	CoretimeRococo::execute_with(|| {
+		// Hooks don't run in emulated tests - workaround.
+		<CoretimeRococo as CoretimeRococoPallet>::Broker::on_initialize(
+			<CoretimeRococo as Chain>::System::block_number(),
+		);
+
+		assert_expected_events!(
+			CoretimeRococo,
+			vec![
+				CoretimeEvent::Broker(
+					pallet_broker::Event::SaleInitialized { .. }
+				) => {},
+				CoretimeEvent::Broker(
+					pallet_broker::Event::CoreAssigned { .. }
+				) => {},
+				CoretimeEvent::ParachainSystem(
+					cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }
+				) => {},
+			]
+		);
+	});
+
+	// Check that the assign_core message was processed successfully.
+	// This will fail if the weights are misconfigured.
+	Rococo::execute_with(|| {
+		Rococo::assert_ump_queue_processed(true, Some(CoretimeRococo::para_id()), None);
+
+		assert_expected_events!(
+			Rococo,
+			vec![
+				RelayEvent::MessageQueue(
+					pallet_message_queue::Event::Processed { success: true, .. }
+				) => {},
+				RelayEvent::Coretime(
+					polkadot_runtime_parachains::coretime::Event::CoreAssigned { .. }
+				) => {},
+			]
+		);
+	});
+
+	// In this block we trigger request revenue.
+	CoretimeRococo::execute_with(|| {
+		// Hooks don't run in emulated tests - workaround.
+		<CoretimeRococo as CoretimeRococoPallet>::Broker::on_initialize(
+			<CoretimeRococo as Chain>::System::block_number(),
+		);
+
+		assert_expected_events!(
+			CoretimeRococo,
+			vec![
+				CoretimeEvent::ParachainSystem(
+					cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }
+				) => {},
+			]
+		);
+	});
+
+	// Check that the request_revenue_info_at message was processed successfully.
+	// This will fail if the weights are misconfigured.
+	Rococo::execute_with(|| {
+		Rococo::assert_ump_queue_processed(true, Some(CoretimeRococo::para_id()), None);
+
+		assert_expected_events!(
+			Rococo,
+			vec![
+				RelayEvent::MessageQueue(
+					pallet_message_queue::Event::Processed { success: true, .. }
+				) => {},
+			]
+		);
+	});
+
+	// Here we receive and process the notify_revenue XCM with zero revenue.
+	CoretimeRococo::execute_with(|| {
+		// Hooks don't run in emulated tests - workaround.
+		<CoretimeRococo as CoretimeRococoPallet>::Broker::on_initialize(
+			<CoretimeRococo as Chain>::System::block_number(),
+		);
+
+		assert_expected_events!(
+			CoretimeRococo,
+			vec![
+				CoretimeEvent::MessageQueue(
+					pallet_message_queue::Event::Processed { success: true, .. }
+				) => {},
+				// Zero revenue in first timeslice so history is immediately dropped.
+				CoretimeEvent::Broker(
+					pallet_broker::Event::HistoryDropped { when: 0, revenue: 0 }
+				) => {},
+			]
+		);
+	});
+}
diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/mod.rs
index 0e78351bce0..bb0387a4b35 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/mod.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/mod.rs
@@ -14,3 +14,4 @@
 // limitations under the License.
 
 mod claim_assets;
+mod coretime_interface;
diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/Cargo.toml
index a8fa905d2e5..d57e7926b0e 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/Cargo.toml
+++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "coretime-westend-integration-tests"
-version = "0.1.0"
+version = "0.0.0"
 authors.workspace = true
 edition.workspace = true
 license = "Apache-2.0"
@@ -12,16 +12,19 @@ publish = false
 # Substrate
 frame-support = { workspace = true }
 pallet-balances = { workspace = true }
+pallet-broker = { workspace = true, default-features = true }
 pallet-message-queue = { workspace = true }
 pallet-identity = { workspace = true }
 sp-runtime = { workspace = true }
 
 # Polkadot
 polkadot-runtime-common = { workspace = true, default-features = true }
+polkadot-runtime-parachains = { workspace = true, default-features = true }
 westend-runtime-constants = { workspace = true, default-features = true }
 xcm = { workspace = true }
 xcm-executor = { workspace = true }
 
 # Cumulus
+cumulus-pallet-parachain-system = { workspace = true, default-features = true }
 emulated-integration-tests-common = { workspace = true }
 westend-system-emulated-network = { workspace = true }
diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs
index 838ca6eeafb..ac844e0f328 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/lib.rs
@@ -24,7 +24,7 @@ mod imports {
 
 	// Cumulus
 	pub use emulated_integration_tests_common::xcm_emulator::{
-		assert_expected_events, bx, TestExt,
+		assert_expected_events, bx, Chain, Parachain, TestExt,
 	};
 	pub use westend_system_emulated_network::{
 		coretime_westend_emulated_chain::{
@@ -33,7 +33,7 @@ mod imports {
 		},
 		CoretimeWestendPara as CoretimeWestend,
 		CoretimeWestendParaReceiver as CoretimeWestendReceiver,
-		CoretimeWestendParaSender as CoretimeWestendSender,
+		CoretimeWestendParaSender as CoretimeWestendSender, WestendRelay as Westend,
 	};
 }
 
diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/coretime_interface.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/coretime_interface.rs
new file mode 100644
index 00000000000..f61bc4285a0
--- /dev/null
+++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/coretime_interface.rs
@@ -0,0 +1,223 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use crate::imports::*;
+use frame_support::traits::OnInitialize;
+use pallet_broker::{ConfigRecord, Configuration, CoreAssignment, CoreMask, ScheduleItem};
+use sp_runtime::Perbill;
+use westend_runtime_constants::system_parachain::coretime::TIMESLICE_PERIOD;
+
+#[test]
+fn transact_hardcoded_weights_are_sane() {
+	// There are three transacts with hardcoded weights sent from the Coretime Chain to the Relay
+	// Chain across the CoretimeInterface which are triggered at various points in the sales cycle.
+	// - Request core count - triggered directly by `start_sales` or `request_core_count`
+	//   extrinsics.
+	// - Request revenue info - triggered when each timeslice is committed.
+	// - Assign core - triggered when an entry is encountered in the workplan for the next
+	//   timeslice.
+
+	// RuntimeEvent aliases to avoid warning from usage of qualified paths in assertions due to
+	// <https://github.com/rust-lang/rust/issues/86935>
+	type CoretimeEvent = <CoretimeWestend as Chain>::RuntimeEvent;
+	type RelayEvent = <Westend as Chain>::RuntimeEvent;
+
+	// Reserve a workload, configure broker and start sales.
+	CoretimeWestend::execute_with(|| {
+		// Hooks don't run in emulated tests - workaround as we need `on_initialize` to tick things
+		// along and have no concept of time passing otherwise.
+		<CoretimeWestend as CoretimeWestendPallet>::Broker::on_initialize(
+			<CoretimeWestend as Chain>::System::block_number(),
+		);
+
+		let coretime_root_origin = <CoretimeWestend as Chain>::RuntimeOrigin::root();
+
+		// Create and populate schedule with the worst case assignment on this core.
+		let mut schedule = Vec::new();
+		for i in 0..27 {
+			schedule.push(ScheduleItem {
+				mask: CoreMask::void().set(i),
+				assignment: CoreAssignment::Task(2000 + i),
+			})
+		}
+
+		assert_ok!(<CoretimeWestend as CoretimeWestendPallet>::Broker::reserve(
+			coretime_root_origin.clone(),
+			schedule.try_into().expect("Vector is within bounds."),
+		));
+
+		// Configure broker and start sales.
+		let config = ConfigRecord {
+			advance_notice: 1,
+			interlude_length: 1,
+			leadin_length: 2,
+			region_length: 1,
+			ideal_bulk_proportion: Perbill::from_percent(40),
+			limit_cores_offered: None,
+			renewal_bump: Perbill::from_percent(2),
+			contribution_timeout: 1,
+		};
+		assert_ok!(<CoretimeWestend as CoretimeWestendPallet>::Broker::configure(
+			coretime_root_origin.clone(),
+			config
+		));
+		assert_ok!(<CoretimeWestend as CoretimeWestendPallet>::Broker::start_sales(
+			coretime_root_origin,
+			100,
+			0
+		));
+		assert_eq!(
+			pallet_broker::Status::<<CoretimeWestend as Chain>::Runtime>::get()
+				.unwrap()
+				.core_count,
+			1
+		);
+
+		assert_expected_events!(
+			CoretimeWestend,
+			vec![
+				CoretimeEvent::Broker(
+					pallet_broker::Event::ReservationMade { .. }
+				) => {},
+				CoretimeEvent::Broker(
+					pallet_broker::Event::CoreCountRequested { core_count: 1 }
+				) => {},
+				CoretimeEvent::ParachainSystem(
+					cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }
+				) => {},
+			]
+		);
+	});
+
+	// Check that the request_core_count message was processed successfully. This will fail if the
+	// weights are misconfigured.
+	Westend::execute_with(|| {
+		Westend::assert_ump_queue_processed(true, Some(CoretimeWestend::para_id()), None);
+
+		assert_expected_events!(
+			Westend,
+			vec![
+				RelayEvent::MessageQueue(
+					pallet_message_queue::Event::Processed { success: true, .. }
+				) => {},
+			]
+		);
+	});
+
+	// Keep track of the relay chain block number so we can fast forward while still checking the
+	// right block.
+	let mut block_number_cursor = Westend::ext_wrapper(<Westend as Chain>::System::block_number);
+
+	let config = CoretimeWestend::ext_wrapper(|| {
+		Configuration::<<CoretimeWestend as Chain>::Runtime>::get()
+			.expect("Pallet was configured earlier.")
+	});
+
+	// Now run up to the block before the sale is rotated.
+	while block_number_cursor < TIMESLICE_PERIOD - config.advance_notice - 1 {
+		CoretimeWestend::execute_with(|| {
+			// Hooks don't run in emulated tests - workaround.
+			<CoretimeWestend as CoretimeWestendPallet>::Broker::on_initialize(
+				<CoretimeWestend as Chain>::System::block_number(),
+			);
+		});
+
+		Westend::ext_wrapper(|| {
+			block_number_cursor = <Westend as Chain>::System::block_number();
+		});
+	}
+
+	// In this block we trigger assign core.
+	CoretimeWestend::execute_with(|| {
+		// Hooks don't run in emulated tests - workaround.
+		<CoretimeWestend as CoretimeWestendPallet>::Broker::on_initialize(
+			<CoretimeWestend as Chain>::System::block_number(),
+		);
+
+		assert_expected_events!(
+			CoretimeWestend,
+			vec![
+				CoretimeEvent::Broker(
+					pallet_broker::Event::SaleInitialized { .. }
+				) => {},
+				CoretimeEvent::Broker(
+					pallet_broker::Event::CoreAssigned { .. }
+				) => {},
+				CoretimeEvent::ParachainSystem(
+					cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }
+				) => {},
+			]
+		);
+	});
+
+	// In this block we trigger request revenue.
+	CoretimeWestend::execute_with(|| {
+		// Hooks don't run in emulated tests - workaround.
+		<CoretimeWestend as CoretimeWestendPallet>::Broker::on_initialize(
+			<CoretimeWestend as Chain>::System::block_number(),
+		);
+
+		assert_expected_events!(
+			CoretimeWestend,
+			vec![
+				CoretimeEvent::ParachainSystem(
+					cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. }
+				) => {},
+			]
+		);
+	});
+
+	// Check that the assign_core and request_revenue_info_at messages were processed successfully.
+	// This will fail if the weights are misconfigured.
+	Westend::execute_with(|| {
+		Westend::assert_ump_queue_processed(true, Some(CoretimeWestend::para_id()), None);
+
+		assert_expected_events!(
+			Westend,
+			vec![
+				RelayEvent::MessageQueue(
+					pallet_message_queue::Event::Processed { success: true, .. }
+				) => {},
+				RelayEvent::MessageQueue(
+					pallet_message_queue::Event::Processed { success: true, .. }
+				) => {},
+				RelayEvent::Coretime(
+					polkadot_runtime_parachains::coretime::Event::CoreAssigned { .. }
+				) => {},
+			]
+		);
+	});
+
+	// Here we receive and process the notify_revenue XCM with zero revenue.
+	CoretimeWestend::execute_with(|| {
+		// Hooks don't run in emulated tests - workaround.
+		<CoretimeWestend as CoretimeWestendPallet>::Broker::on_initialize(
+			<CoretimeWestend as Chain>::System::block_number(),
+		);
+
+		assert_expected_events!(
+			CoretimeWestend,
+			vec![
+				CoretimeEvent::MessageQueue(
+					pallet_message_queue::Event::Processed { success: true, .. }
+				) => {},
+				// Zero revenue in first timeslice so history is immediately dropped.
+				CoretimeEvent::Broker(
+					pallet_broker::Event::HistoryDropped { when: 0, revenue: 0 }
+				) => {},
+			]
+		);
+	});
+}
diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/mod.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/mod.rs
index 0e78351bce0..bb0387a4b35 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/mod.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/mod.rs
@@ -14,3 +14,4 @@
 // limitations under the License.
 
 mod claim_assets;
+mod coretime_interface;
-- 
GitLab