Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify event assertion with predicate-based check #7734

Open
wants to merge 22 commits into
base: master
Choose a base branch
from

Conversation

raymondkfcheung
Copy link
Contributor

@raymondkfcheung raymondkfcheung commented Feb 26, 2025

A follow-up PR to simplify event assertions by introducing contains_event, allowing event checks without needing exact field matches. This reduces redundancy and makes tests more flexible.

Partially addresses #6119 by providing an alternative way to assert events.

Reference: PR #7594 - Discussion

@raymondkfcheung raymondkfcheung requested review from a team as code owners February 26, 2025 16:45
@raymondkfcheung raymondkfcheung self-assigned this Feb 26, 2025
@raymondkfcheung
Copy link
Contributor Author

/cmd prdoc --audience runtime_dev --bump patch

@raymondkfcheung raymondkfcheung added T6-XCM This PR/Issue is related to XCM. T10-tests This PR/Issue is related to tests. labels Feb 26, 2025
@paritytech-workflow-stopper
Copy link

All GitHub workflows were cancelled due to failure one of the required jobs.
Failed workflow url: https://github.com/paritytech/polkadot-sdk/actions/runs/13549250284
Failed job name: fmt

@raymondkfcheung
Copy link
Contributor Author

/cmd fmt

/// Similar to `System::assert_has_event`, but allows checking for an event without needing to
/// specify the exact details of its inner fields.
#[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
#[track_caller]
Copy link
Contributor

@bkontur bkontur Feb 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've never used this, but from what I’m reading, #[track_caller] is used for functions that can panic or assert, allowing you to see the line where they were called rather than the line where the panic or assertion occurred.
So, this contains_event returns bool, so I think it shouldn't fail.

Suggested change
#[track_caller]

If we use this all the time as assert!(System::contains_event(, maybe we could just change existing:

-  pub fn assert_has_event(event: T::RuntimeEvent)`
+  pub fn assert_has_event(predicate: F)`

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually if we look above, we already have assert_has_event. So this can just be used here already and we don't need contains_event.

Copy link
Contributor Author

@raymondkfcheung raymondkfcheung Feb 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree that we already have a similar function, assert_has_event(). Refactoring it to accept a predicate could be an option. The goal here is to simplify event assertions and provide an alternative way to check for events. Here's a comparison of assert_has_event() vs contains_event():

relay_chain::System::assert_has_event(relay_chain::RuntimeEvent::XcmPallet(
    pallet_xcm::Event::Attempted {
        outcome: Outcome::Complete { used: Weight::from_parts(1_000, 1_000) },
    },
));
		
assert!(relay_chain::System::contains_event(|event| {
    matches!(
        event,
        relay_chain::RuntimeEvent::XcmPallet(pallet_xcm::Event::Attempted { .. })
    )
}));

My original intent was to keep this as a lightweight PR. Refactoring assert_has_event() would require more extensive changes. If that's the preferred approach, I’ll skip adding contains_event() to frame and instead refactor it as a local helper within the XCM scope.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bkchr Removed contains_event() from frame, please check.

/// Similar to `System::assert_has_event`, but allows checking for an event without needing to
/// specify the exact details of its inner fields.
#[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
#[track_caller]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually if we look above, we already have assert_has_event. So this can just be used here already and we don't need contains_event.

@paritytech-review-bot paritytech-review-bot bot requested a review from a team February 27, 2025 09:48
@@ -26,6 +26,20 @@ fn buy_execution<C>(fees: impl Into<Asset>) -> Instruction<C> {
BuyExecution { fees: fees.into(), weight_limit: Unlimited }
}

// Helper function for checking if an XCM event matching the given predicate exists.
fn contains_event<F>(predicate: F) -> bool
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I would rename this function since it's not clear who should contain the event.

Also could we make it a macro ? I think it would be easier to use. At least for the use cases that I see in this PR. Something like assert_system_event!(event).

Copy link
Contributor Author

@raymondkfcheung raymondkfcheung Feb 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, no, I mean something like:

macro_rules! assert_system_event {
	( $expected_event:pat ) => {
		relay_chain::System::events().iter().any(|e| matches!(e.event, $expected_event))
	};
}

And then we can just do

assert_system_event!(relay_chain::RuntimeEvent::XcmPallet(pallet_xcm::Event::Attempted { .. }))

Or maybe we should provide relay_chain::System also as a parameter, but anyway, something like that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, will do.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, my code is incomplete. You also have to check that relay_chain::System::events().iter().any(|e| matches!(e.event, $expected_event)) actually returns true

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of assert_system_event, I changed the logic a bit to system_contains_event, which returns a bool. This allows tests to check for both the presence and absence of events. It also works for both parachain and relay chain events.

Copy link
Contributor

@serban300 serban300 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good ! I just left one more comment, but it's mostly a nit.

Comment on lines 38 to 39
$module::System::events().iter().any(|e| {
matches!(e.event, $module::RuntimeEvent::$variant($($pattern)*))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RuntimeEvent is hardcoded and it's the same for all runtimes. But I think System is not. The runtimes can use any name when adding the system pallet:

construct_runtime! {
	pub enum Runtime
	{
		System: frame_system,
        ...
     }
}

So if we need to use this method in more tests in the future, we might need to add a parameter to the macro for providing the name of the system pallet. But here it works like this.

Also I would rename module to runtime

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed. Will change later if we need more parameters.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T6-XCM This PR/Issue is related to XCM. T10-tests This PR/Issue is related to tests.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants