Path: blob/main/crates/bevy_dev_tools/src/ci_testing/mod.rs
9325 views
//! Utilities for testing in CI environments.12mod config;3mod systems;45use crate::EasyCameraMovementPlugin;6#[cfg(feature = "screenrecording")]7use crate::EasyScreenRecordPlugin;89pub use self::config::*;1011use bevy_app::prelude::*;12use bevy_ecs::prelude::*;13use bevy_render::view::screenshot::trigger_screenshots;14use bevy_time::TimeUpdateStrategy;15use core::time::Duration;1617/// A plugin that instruments continuous integration testing by automatically executing user-defined actions.18///19/// This plugin reads a [`ron`] file specified with the `CI_TESTING_CONFIG` environmental variable20/// (`ci_testing_config.ron` by default) and executes its specified actions. For a reference of the21/// allowed configuration, see [`CiTestingConfig`].22///23/// This plugin is included within `DefaultPlugins` and `MinimalPlugins`24/// when the `bevy_ci_testing` feature is enabled.25/// It is recommended to only used this plugin during testing (manual or26/// automatic), and disable it during regular development and for production builds.27#[derive(Default)]28pub struct CiTestingPlugin;2930impl Plugin for CiTestingPlugin {31fn build(&self, app: &mut App) {32let config = if !app.world().is_resource_added::<CiTestingConfig>() {33// Load configuration from file if not already setup34#[cfg(not(target_arch = "wasm32"))]35let config: CiTestingConfig = {36let filename = std::env::var("CI_TESTING_CONFIG")37.unwrap_or_else(|_| "ci_testing_config.ron".to_string());38std::fs::read_to_string(filename)39.map(|content| {40ron::from_str(&content)41.expect("error deserializing CI testing configuration file")42})43.unwrap_or_default()44};4546#[cfg(target_arch = "wasm32")]47let config: CiTestingConfig = {48let config = include_str!("../../../../ci_testing_config.ron");49ron::from_str(config).expect("error deserializing CI testing configuration file")50};5152config53} else {54app.world().resource::<CiTestingConfig>().clone()55};5657// Add the `EasyCameraMovementPlugin` to the app if it's not already added.58// To configure the movement speed, add the plugin first.59if !app.is_plugin_added::<EasyCameraMovementPlugin>() {60app.add_plugins(EasyCameraMovementPlugin::default());61}62// Add the `EasyScreenRecordPlugin` to the app if it's not already added and one of the event is starting screenrecording.63// To configure the recording quality, add the plugin first.64#[cfg(feature = "screenrecording")]65if !app.is_plugin_added::<EasyScreenRecordPlugin>()66&& config67.events68.iter()69.any(|e| matches!(e.1, CiTestingEvent::StartScreenRecording))70{71app.add_plugins(EasyScreenRecordPlugin::default());72}7374// Configure a fixed frame time if specified.75if let Some(fixed_frame_time) = config.setup.fixed_frame_time {76app.insert_resource(TimeUpdateStrategy::ManualDuration(Duration::from_secs_f32(77fixed_frame_time,78)));79}80app.add_message::<CiTestingCustomEvent>()81.insert_resource(config)82.add_systems(83Update,84systems::send_events85.before(trigger_screenshots)86.before(bevy_window::close_when_requested)87.in_set(EventSenderSystems)88.ambiguous_with_all(),89);9091// The offending system does not exist in the wasm32 target.92// As a result, we must conditionally order the two systems using a system set.93#[cfg(any(unix, windows))]94app.configure_sets(95Update,96EventSenderSystems.before(bevy_app::TerminalCtrlCHandlerPlugin::exit_on_flag),97);98}99}100101#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]102struct EventSenderSystems;103104105