Skip to main content

pop_chains/try_runtime/
mod.rs

1use crate::{Error, errors::handle_command_error};
2use duct::cmd;
3pub use frame_try_runtime::{TryStateSelect, UpgradeCheckSelect};
4use std::{fmt::Display, path::PathBuf, str::from_utf8};
5
6/// Provides functionality for sourcing binaries of the `try-runtime-cli`.
7pub mod binary;
8/// Provides functionality for parsing command-line arguments.
9pub mod parse;
10/// Shared parameters for the `try-runtime-cli` commands.
11pub mod shared_parameters;
12/// Types related to the source of runtime state.
13pub mod state;
14
15/// Commands that can be executed by the `try-runtime-cli`.
16pub enum TryRuntimeCliCommand {
17	/// Command to test runtime upgrades.
18	OnRuntimeUpgrade,
19	/// Command to test block execution.
20	ExecuteBlock,
21	/// Command to create a snapshot.
22	CreateSnapshot,
23	/// Command to mine a series of blocks after executing a runtime upgrade.
24	FastForward,
25}
26
27impl Display for TryRuntimeCliCommand {
28	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29		let s = match self {
30			TryRuntimeCliCommand::OnRuntimeUpgrade => "on-runtime-upgrade",
31			TryRuntimeCliCommand::ExecuteBlock => "execute-block",
32			TryRuntimeCliCommand::CreateSnapshot => "create-snapshot",
33			TryRuntimeCliCommand::FastForward => "fast-forward",
34		};
35		write!(f, "{}", s)
36	}
37}
38
39/// Get the details of upgrade options for testing runtime upgrades.
40///
41/// # Arguments
42/// * `upgrade_check_select` - The selected upgrade check option.
43pub fn upgrade_checks_details(upgrade_check_select: &UpgradeCheckSelect) -> (String, String) {
44	match upgrade_check_select {
45		UpgradeCheckSelect::None => ("none".to_string(), "Run no checks".to_string()),
46		UpgradeCheckSelect::All => (
47			"all".to_string(),
48			"Run the `try_state`, `pre_upgrade` and `post_upgrade` checks".to_string(),
49		),
50		UpgradeCheckSelect::TryState =>
51			("try-state".to_string(), "Run the `try_state` checks".to_string()),
52		UpgradeCheckSelect::PreAndPost => (
53			"pre-and-post".to_string(),
54			"Run the `pre_upgrade` and `post_upgrade` checks".to_string(),
55		),
56	}
57}
58
59/// Get the label of try state options.
60///
61/// # Arguments
62/// * `try_state_select` - The selected try state option.
63pub fn try_state_label(try_state_select: &TryStateSelect) -> String {
64	match try_state_select {
65		TryStateSelect::None => "None".to_string(),
66		TryStateSelect::All => "All".to_string(),
67		TryStateSelect::RoundRobin(..) => "Round Robin".to_string(),
68		TryStateSelect::Only(..) => "Only Pallets".to_string(),
69	}
70}
71
72/// Get the details of try state options for testing runtime upgrades.
73///
74/// # Arguments
75/// * `try_state_select` - The selected try state option.
76pub fn try_state_details(try_state_select: &TryStateSelect) -> (String, String) {
77	(
78		try_state_label(try_state_select),
79		match try_state_select {
80			TryStateSelect::None => "Run no tests".to_string(),
81			TryStateSelect::All => "Run all the state tests".to_string(),
82			TryStateSelect::RoundRobin(..) =>
83				"Run a fixed number of state tests in a round robin manner.".to_string(),
84			TryStateSelect::Only(..) =>
85				"Run only pallets who's name matches the given list.".to_string(),
86		},
87	)
88}
89
90/// Parse the `try_state` to string.
91///
92/// # Arguments
93/// * `try_state` - The selected try state option.
94pub fn parse_try_state_string(try_state: &TryStateSelect) -> Result<String, Error> {
95	Ok(match try_state {
96		TryStateSelect::All => "all".to_string(),
97		TryStateSelect::None => "none".to_string(),
98		TryStateSelect::RoundRobin(rounds) => format!("rr-{}", rounds),
99		TryStateSelect::Only(pallets) => {
100			let mut result = vec![];
101			for pallet in pallets.iter() {
102				result.push(from_utf8(pallet).map_err(|_| {
103					Error::ParamParsingError("Invalid pallet string in `try_state`".to_string())
104				})?);
105			}
106			result.join(",")
107		},
108	})
109}
110
111/// Run `try-runtime-cli` binary.
112///
113/// # Arguments
114/// * `binary_path` - Path to the binary.
115/// * `command` - Command to run.
116/// * `shared_params` - Shared parameters of the `try-runtime` command.
117/// * `args` - Arguments passed to the subcommand.
118/// * `excluded_args` - Arguments to exclude.
119pub fn run_try_runtime(
120	binary_path: &PathBuf,
121	command: TryRuntimeCliCommand,
122	shared_params: Vec<String>,
123	args: Vec<String>,
124	excluded_args: &[&str],
125) -> Result<(), Error> {
126	let mut cmd_args = shared_params
127		.into_iter()
128		.filter(|arg| !excluded_args.iter().any(|a| arg.starts_with(a)))
129		.collect::<Vec<String>>();
130	cmd_args.extend(vec![command.to_string()]);
131	cmd_args.extend(
132		args.into_iter()
133			.filter(|arg| !excluded_args.iter().any(|a| arg.starts_with(a)))
134			.collect::<Vec<String>>(),
135	);
136	let output = cmd(binary_path, cmd_args)
137		.env("RUST_LOG", "info")
138		.stderr_capture()
139		.unchecked()
140		.run()?;
141	// Check if the command failed.
142	handle_command_error(&output, Error::TryRuntimeError)?;
143	if output.status.success() {
144		eprintln!("{}", String::from_utf8_lossy(&output.stderr));
145	}
146	Ok(())
147}
148
149#[cfg(test)]
150mod tests {
151	use super::*;
152
153	#[test]
154	fn parse_try_state_string_works() {
155		assert_eq!(parse_try_state_string(&TryStateSelect::All).unwrap(), "all");
156		assert_eq!(parse_try_state_string(&TryStateSelect::None).unwrap(), "none");
157		assert_eq!(parse_try_state_string(&TryStateSelect::RoundRobin(5)).unwrap(), "rr-5");
158		assert_eq!(
159			parse_try_state_string(&TryStateSelect::Only(vec![
160				b"System".to_vec(),
161				b"Proxy".to_vec()
162			]))
163			.unwrap(),
164			"System,Proxy"
165		);
166	}
167
168	#[test]
169	fn try_state_label_works() {
170		for (select, label) in [
171			(TryStateSelect::All, "All"),
172			(TryStateSelect::None, "None"),
173			(TryStateSelect::RoundRobin(5), "Round Robin"),
174			(TryStateSelect::Only(vec![]), "Only Pallets"),
175		] {
176			assert_eq!(try_state_label(&select), label);
177		}
178	}
179
180	#[test]
181	fn try_state_details_works() {
182		for (select, description) in [
183			(TryStateSelect::None, "Run no tests"),
184			(TryStateSelect::All, "Run all the state tests"),
185			(
186				TryStateSelect::RoundRobin(0),
187				"Run a fixed number of state tests in a round robin manner.",
188			),
189			(TryStateSelect::Only(vec![]), "Run only pallets who's name matches the given list."),
190		] {
191			assert_eq!(
192				try_state_details(&select),
193				(try_state_label(&select), description.to_string())
194			);
195		}
196	}
197}