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