;
19 |
20 | #[async_trait]
21 | pub trait FileSystem {
22 | async fn create_dir(&self, path: P) -> FileSystemResult<()>
23 | where
24 | P: AsRef + Send;
25 |
26 | async fn create_dir_all(&self, path: P) -> FileSystemResult<()>
27 | where
28 | P: AsRef + Send;
29 |
30 | async fn read(&self, path: P) -> FileSystemResult>
31 | where
32 | P: AsRef + Send;
33 |
34 | async fn read_to_string(&self, path: P) -> FileSystemResult
35 | where
36 | P: AsRef + Send;
37 |
38 | async fn write(&self, path: P, contents: C) -> FileSystemResult<()>
39 | where
40 | P: AsRef + Send,
41 | C: AsRef<[u8]> + Send;
42 |
43 | async fn append(&self, path: P, contents: C) -> FileSystemResult<()>
44 | where
45 | P: AsRef + Send,
46 | C: AsRef<[u8]> + Send;
47 |
48 | async fn copy(&self, from: P1, to: P2) -> FileSystemResult<()>
49 | where
50 | P1: AsRef + Send,
51 | P2: AsRef + Send;
52 |
53 | async fn set_mode(&self, path: P, perm: u32) -> FileSystemResult<()>
54 | where
55 | P: AsRef + Send;
56 |
57 | async fn exists(&self, path: P) -> bool
58 | where
59 | P: AsRef + Send;
60 | }
61 |
--------------------------------------------------------------------------------
/crates/support/src/lib.rs:
--------------------------------------------------------------------------------
1 | pub mod constants;
2 | pub mod fs;
3 | pub mod net;
4 | pub mod replacer;
5 |
--------------------------------------------------------------------------------
/crates/support/src/net.rs:
--------------------------------------------------------------------------------
1 | use std::{io::Cursor, str::FromStr, time::Duration};
2 |
3 | use reqwest::{Method, Request, StatusCode, Url};
4 | use tracing::trace;
5 |
6 | use crate::constants::THIS_IS_A_BUG;
7 |
8 | type Result = std::result::Result>;
9 |
10 | pub async fn download_file(url: String, dest: String) -> Result<()> {
11 | let response = reqwest::get(url).await?;
12 | let mut file = std::fs::File::create(dest)?;
13 | let mut content = Cursor::new(response.bytes().await?);
14 | std::io::copy(&mut content, &mut file)?;
15 | Ok(())
16 | }
17 |
18 | pub async fn wait_ws_ready(url: &str) -> Result<()> {
19 | let mut parsed = Url::from_str(url)?;
20 | parsed
21 | .set_scheme("http")
22 | .map_err(|_| anyhow::anyhow!("Can not set the scheme, {}", THIS_IS_A_BUG))?;
23 |
24 | let http_client = reqwest::Client::new();
25 | loop {
26 | let req = Request::new(Method::OPTIONS, parsed.clone());
27 | let res = http_client.execute(req).await;
28 | match res {
29 | Ok(res) => {
30 | if res.status() == StatusCode::OK {
31 | // ready to go!
32 | break;
33 | }
34 |
35 | trace!("http_client status: {}, continuing...", res.status());
36 | },
37 | Err(e) => {
38 | if !skip_err_while_waiting(&e) {
39 | return Err(e.into());
40 | }
41 |
42 | trace!("http_client err: {}, continuing... ", e.to_string());
43 | },
44 | }
45 |
46 | tokio::time::sleep(Duration::from_secs(1)).await;
47 | }
48 |
49 | Ok(())
50 | }
51 |
52 | pub fn skip_err_while_waiting(e: &reqwest::Error) -> bool {
53 | // if the error is connecting/request could be the case that the node
54 | // is not listening yet, so we keep waiting
55 | // Skipped errs like:
56 | // 'tcp connect error: Connection refused (os error 61)'
57 | // 'operation was canceled: connection closed before message completed'
58 | // 'connection error: Connection reset by peer (os error 54)'
59 | e.is_connect() || e.is_request()
60 | }
61 |
--------------------------------------------------------------------------------
/crates/support/src/replacer.rs:
--------------------------------------------------------------------------------
1 | use std::collections::HashMap;
2 |
3 | use lazy_static::lazy_static;
4 | use regex::{Captures, Regex};
5 | use tracing::{trace, warn};
6 |
7 | use crate::constants::{SHOULD_COMPILE, THIS_IS_A_BUG};
8 |
9 | lazy_static! {
10 | static ref RE: Regex = Regex::new(r#"\{\{([a-zA-Z0-9_]*)\}\}"#)
11 | .unwrap_or_else(|_| panic!("{}, {}", SHOULD_COMPILE, THIS_IS_A_BUG));
12 | static ref TOKEN_PLACEHOLDER: Regex = Regex::new(r#"\{\{ZOMBIE:(.*?):(.*?)\}\}"#)
13 | .unwrap_or_else(|_| panic!("{}, {}", SHOULD_COMPILE, THIS_IS_A_BUG));
14 | static ref PLACEHOLDER_COMPAT: HashMap<&'static str, &'static str> = {
15 | let mut m = HashMap::new();
16 | m.insert("multiAddress", "multiaddr");
17 | m.insert("wsUri", "ws_uri");
18 | m.insert("prometheusUri", "prometheus_uri");
19 |
20 | m
21 | };
22 | }
23 |
24 | /// Return true if the text contains any TOKEN_PLACEHOLDER
25 | pub fn has_tokens(text: &str) -> bool {
26 | TOKEN_PLACEHOLDER.is_match(text)
27 | }
28 |
29 | pub fn apply_replacements(text: &str, replacements: &HashMap<&str, &str>) -> String {
30 | let augmented_text = RE.replace_all(text, |caps: &Captures| {
31 | if let Some(replacements_value) = replacements.get(&caps[1]) {
32 | replacements_value.to_string()
33 | } else {
34 | caps[0].to_string()
35 | }
36 | });
37 |
38 | augmented_text.to_string()
39 | }
40 |
41 | pub fn apply_env_replacements(text: &str) -> String {
42 | let augmented_text = RE.replace_all(text, |caps: &Captures| {
43 | if let Ok(replacements_value) = std::env::var(&caps[1]) {
44 | replacements_value
45 | } else {
46 | caps[0].to_string()
47 | }
48 | });
49 |
50 | augmented_text.to_string()
51 | }
52 |
53 | pub fn apply_running_network_replacements(text: &str, network: &serde_json::Value) -> String {
54 | let augmented_text = TOKEN_PLACEHOLDER.replace_all(text, |caps: &Captures| {
55 | trace!("appling replacements for caps: {caps:#?}");
56 | if let Some(node) = network.get(&caps[1]) {
57 | trace!("caps1 {} - node: {node}", &caps[1]);
58 | let field = *PLACEHOLDER_COMPAT.get(&caps[2]).unwrap_or(&&caps[2]);
59 | if let Some(val) = node.get(field) {
60 | trace!("caps2 {} - node: {node}", field);
61 | val.as_str().unwrap_or("Invalid string").to_string()
62 | } else {
63 | warn!(
64 | "⚠️ The node with name {} doesn't have the value {} in context",
65 | &caps[1], &caps[2]
66 | );
67 | caps[0].to_string()
68 | }
69 | } else {
70 | warn!("⚠️ No node with name {} in context", &caps[1]);
71 | caps[0].to_string()
72 | }
73 | });
74 |
75 | augmented_text.to_string()
76 | }
77 | #[cfg(test)]
78 | mod tests {
79 | use serde_json::json;
80 |
81 | use super::*;
82 |
83 | #[test]
84 | fn replace_should_works() {
85 | let text = "some {{namespace}}";
86 | let mut replacements = HashMap::new();
87 | replacements.insert("namespace", "demo-123");
88 | let res = apply_replacements(text, &replacements);
89 | assert_eq!("some demo-123".to_string(), res);
90 | }
91 |
92 | #[test]
93 | fn replace_env_should_works() {
94 | let text = "some {{namespace}}";
95 | std::env::set_var("namespace", "demo-123");
96 | // let mut replacements = HashMap::new();
97 | // replacements.insert("namespace", "demo-123");
98 | let res = apply_env_replacements(text);
99 | assert_eq!("some demo-123".to_string(), res);
100 | }
101 |
102 | #[test]
103 | fn replace_multiple_should_works() {
104 | let text = r#"some {{namespace}}
105 | other is {{other}}"#;
106 | let augmented_text = r#"some demo-123
107 | other is other-123"#;
108 |
109 | let mut replacements = HashMap::new();
110 | replacements.insert("namespace", "demo-123");
111 | replacements.insert("other", "other-123");
112 | let res = apply_replacements(text, &replacements);
113 | assert_eq!(augmented_text, res);
114 | }
115 |
116 | #[test]
117 | fn replace_multiple_with_missing_should_works() {
118 | let text = r#"some {{namespace}}
119 | other is {{other}}"#;
120 | let augmented_text = r#"some demo-123
121 | other is {{other}}"#;
122 |
123 | let mut replacements = HashMap::new();
124 | replacements.insert("namespace", "demo-123");
125 |
126 | let res = apply_replacements(text, &replacements);
127 | assert_eq!(augmented_text, res);
128 | }
129 |
130 | #[test]
131 | fn replace_without_replacement_should_leave_text_unchanged() {
132 | let text = "some {{namespace}}";
133 | let mut replacements = HashMap::new();
134 | replacements.insert("other", "demo-123");
135 | let res = apply_replacements(text, &replacements);
136 | assert_eq!(text.to_string(), res);
137 | }
138 |
139 | #[test]
140 | fn replace_running_network_should_work() {
141 | let network = json!({
142 | "alice" : {
143 | "multiaddr": "some/demo/127.0.0.1"
144 | }
145 | });
146 |
147 | let res = apply_running_network_replacements("{{ZOMBIE:alice:multiaddr}}", &network);
148 | assert_eq!(res.as_str(), "some/demo/127.0.0.1");
149 | }
150 |
151 | #[test]
152 | fn replace_running_network_with_compat_should_work() {
153 | let network = json!({
154 | "alice" : {
155 | "multiaddr": "some/demo/127.0.0.1"
156 | }
157 | });
158 |
159 | let res = apply_running_network_replacements("{{ZOMBIE:alice:multiAddress}}", &network);
160 | assert_eq!(res.as_str(), "some/demo/127.0.0.1");
161 | }
162 |
163 | #[test]
164 | fn replace_running_network_with_missing_field_should_not_replace_nothing() {
165 | let network = json!({
166 | "alice" : {
167 | "multiaddr": "some/demo/127.0.0.1"
168 | }
169 | });
170 |
171 | let res = apply_running_network_replacements("{{ZOMBIE:alice:someField}}", &network);
172 | assert_eq!(res.as_str(), "{{ZOMBIE:alice:someField}}");
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/crates/test-runner/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | /Cargo.lock
3 |
--------------------------------------------------------------------------------
/crates/test-runner/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "test-runner"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 |
--------------------------------------------------------------------------------
/crates/test-runner/src/lib.rs:
--------------------------------------------------------------------------------
1 | pub fn add(left: usize, right: usize) -> usize {
2 | left + right
3 | }
4 |
5 | #[cfg(test)]
6 | mod tests {
7 | use super::*;
8 |
9 | #[test]
10 | fn it_works() {
11 | let result = add(2, 2);
12 | assert_eq!(result, 4);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/rustfmt.toml:
--------------------------------------------------------------------------------
1 | # https://rust-lang.github.io/rustfmt/?version=v1.7.0
2 |
3 | # general
4 | indent_style = "Block"
5 |
6 | # rewriting
7 | condense_wildcard_suffixes = true
8 | match_block_trailing_comma = true
9 | use_field_init_shorthand = true
10 | use_try_shorthand = true
11 |
12 | # normalization
13 | normalize_comments = true
14 | normalize_doc_attributes = true
15 |
16 | # reordering
17 | reorder_impl_items = true
18 | reorder_imports = true
19 | reorder_modules = true
20 | imports_granularity = "Crate"
21 | group_imports = "StdExternalCrate"
22 |
23 | # additional formating
24 | format_code_in_doc_comments = true
25 | format_macro_matchers = true
26 | format_macro_bodies = true
--------------------------------------------------------------------------------