polkadot_sdk_docs/guides/
your_first_node.rs1#![doc = docify::embed!("./src/guides/your_first_runtime.rs", build_runtime)]
46#![doc = docify::embed!("./src/guides/your_first_node.rs", csb)]
68#[cfg(test)]
100mod tests {
101 use assert_cmd::assert::OutputAssertExt;
102 use cmd_lib::*;
103 use rand::Rng;
104 use sc_chain_spec::{DEV_RUNTIME_PRESET, LOCAL_TESTNET_RUNTIME_PRESET};
105 use sp_genesis_builder::PresetId;
106 use std::{
107 io::{BufRead, BufReader},
108 path::PathBuf,
109 process::{ChildStderr, Command, Stdio},
110 time::Duration,
111 };
112
113 const PARA_RUNTIME: &'static str = "parachain-template-runtime";
114 const CHAIN_SPEC_BUILDER: &'static str = "chain-spec-builder";
115 const OMNI_NODE: &'static str = "polkadot-omni-node";
116
117 fn cargo() -> Command {
118 Command::new(std::env::var("CARGO").unwrap_or_else(|_| "cargo".to_string()))
119 }
120
121 fn get_target_directory() -> Option<PathBuf> {
122 let output = cargo().arg("metadata").arg("--format-version=1").output().ok()?;
123
124 if !output.status.success() {
125 return None;
126 }
127
128 let metadata: serde_json::Value = serde_json::from_slice(&output.stdout).ok()?;
129 let target_directory = metadata["target_directory"].as_str()?;
130
131 Some(PathBuf::from(target_directory))
132 }
133
134 fn find_release_binary(name: &str) -> Option<PathBuf> {
135 let target_dir = get_target_directory()?;
136 let release_path = target_dir.join("release").join(name);
137
138 if release_path.exists() {
139 Some(release_path)
140 } else {
141 None
142 }
143 }
144
145 fn find_wasm(runtime_name: &str) -> Option<PathBuf> {
146 let target_dir = get_target_directory()?;
147 let wasm_path = target_dir
148 .join("release")
149 .join("wbuild")
150 .join(runtime_name)
151 .join(format!("{}.wasm", runtime_name.replace('-', "_")));
152
153 if wasm_path.exists() {
154 Some(wasm_path)
155 } else {
156 None
157 }
158 }
159
160 fn maybe_build_runtimes() {
161 if find_wasm(&PARA_RUNTIME).is_none() {
162 println!("Building parachain-template-runtime...");
163 Command::new("cargo")
164 .arg("build")
165 .arg("--release")
166 .arg("-p")
167 .arg(PARA_RUNTIME)
168 .assert()
169 .success();
170 }
171
172 assert!(find_wasm(PARA_RUNTIME).is_some());
173 }
174
175 fn maybe_build_chain_spec_builder() {
176 if find_release_binary(CHAIN_SPEC_BUILDER).is_none() {
177 println!("Building chain-spec-builder...");
178 Command::new("cargo")
179 .arg("build")
180 .arg("--release")
181 .arg("-p")
182 .arg("staging-chain-spec-builder")
183 .assert()
184 .success();
185 }
186 assert!(find_release_binary(CHAIN_SPEC_BUILDER).is_some());
187 }
188
189 fn maybe_build_omni_node() {
190 if find_release_binary(OMNI_NODE).is_none() {
191 println!("Building polkadot-omni-node...");
192 Command::new("cargo")
193 .arg("build")
194 .arg("--release")
195 .arg("-p")
196 .arg("polkadot-omni-node")
197 .assert()
198 .success();
199 }
200 }
201
202 async fn imported_block_found(stderr: ChildStderr, block: u64, timeout: u64) -> bool {
203 tokio::time::timeout(Duration::from_secs(timeout), async {
204 let want = format!("Imported #{}", block);
205 let reader = BufReader::new(stderr);
206 let mut found_block = false;
207 for line in reader.lines() {
208 if line.unwrap().contains(&want) {
209 found_block = true;
210 break;
211 }
212 }
213 found_block
214 })
215 .await
216 .unwrap()
217 }
218
219 async fn test_runtime_preset(
220 runtime: &'static str,
221 block_time: u64,
222 maybe_preset: Option<PresetId>,
223 ) {
224 sp_tracing::try_init_simple();
225 maybe_build_runtimes();
226 maybe_build_chain_spec_builder();
227 maybe_build_omni_node();
228
229 let chain_spec_builder =
230 find_release_binary(&CHAIN_SPEC_BUILDER).expect("we built it above; qed");
231 let omni_node = find_release_binary(OMNI_NODE).expect("we built it above; qed");
232 let runtime_path = find_wasm(runtime).expect("we built it above; qed");
233
234 let random_seed: u32 = rand::thread_rng().gen();
235 let chain_spec_file = std::env::current_dir()
236 .unwrap()
237 .join(format!("{}_{}_{}.json", runtime, block_time, random_seed));
238
239 Command::new(chain_spec_builder)
240 .args(["-c", chain_spec_file.to_str().unwrap()])
241 .arg("create")
242 .args(["--relay-chain", "dontcare"])
243 .args(["-r", runtime_path.to_str().unwrap()])
244 .args(match maybe_preset {
245 Some(preset) => vec!["named-preset".to_string(), preset.to_string()],
246 None => vec!["default".to_string()],
247 })
248 .assert()
249 .success();
250
251 let mut child = Command::new(omni_node)
252 .arg("--tmp")
253 .args(["--chain", chain_spec_file.to_str().unwrap()])
254 .args(["--dev-block-time", block_time.to_string().as_str()])
255 .stderr(Stdio::piped())
256 .spawn()
257 .unwrap();
258
259 let stderr = child.stderr.take().unwrap();
261 let expected_blocks = (10_000 / block_time).saturating_div(2);
262 assert!(expected_blocks > 0, "test configuration is bad, should give it more time");
263 assert_eq!(imported_block_found(stderr, expected_blocks, 100).await, true);
264 std::fs::remove_file(chain_spec_file).unwrap();
265 child.kill().unwrap();
266 }
267
268 async fn omni_node_test_setup(chain_spec_path: PathBuf) {
270 maybe_build_omni_node();
271 let omni_node = find_release_binary(OMNI_NODE).unwrap();
272
273 let mut child = Command::new(omni_node)
274 .arg("--dev")
275 .args(["--chain", chain_spec_path.to_str().unwrap()])
276 .stderr(Stdio::piped())
277 .spawn()
278 .unwrap();
279
280 let stderr = child.stderr.take().unwrap();
281 assert_eq!(imported_block_found(stderr, 7, 100).await, true);
282 child.kill().unwrap();
283 }
284
285 #[tokio::test]
286 async fn works_with_different_block_times() {
287 test_runtime_preset(PARA_RUNTIME, 100, Some(DEV_RUNTIME_PRESET.into())).await;
288 test_runtime_preset(PARA_RUNTIME, 3000, Some(DEV_RUNTIME_PRESET.into())).await;
289
290 #[docify::export_content(csb)]
292 fn build_parachain_spec_works() {
293 let chain_spec_builder = find_release_binary(&CHAIN_SPEC_BUILDER).unwrap();
294 let runtime_path = find_wasm(PARA_RUNTIME).unwrap();
295 let output = "/tmp/demo-chain-spec.json";
296 let runtime_str = runtime_path.to_str().unwrap();
297 run_cmd!(
298 $chain_spec_builder -c $output create --relay-chain dontcare -r $runtime_str named-preset development
299 ).expect("Failed to run command");
300 std::fs::remove_file(output).unwrap();
301 }
302 build_parachain_spec_works();
303 }
304
305 #[tokio::test]
306 async fn parachain_runtime_works() {
307 for preset in [Some(DEV_RUNTIME_PRESET.into()), Some(LOCAL_TESTNET_RUNTIME_PRESET.into())] {
310 test_runtime_preset(PARA_RUNTIME, 1000, preset).await;
311 }
312 }
313
314 #[tokio::test]
315 async fn omni_node_dev_mode_works() {
316 let dev_chain_spec = std::env::current_dir()
318 .unwrap()
319 .parent()
320 .unwrap()
321 .parent()
322 .unwrap()
323 .join("templates")
324 .join("parachain")
325 .join("dev_chain_spec.json");
326 omni_node_test_setup(dev_chain_spec).await;
327 }
328
329 #[tokio::test]
330 async fn omni_node_dev_mode_works_without_getparachaininfo() {
334 let dev_chain_spec = std::env::current_dir()
335 .unwrap()
336 .join("src/guides/parachain_without_getparachaininfo.json");
337 omni_node_test_setup(dev_chain_spec).await;
338 }
339}