meta_module_tests/
meta-module-tests.rs1use std::future::Future;
2
3use anyhow::{Result, bail};
4use clap::Parser;
5use devimint::federation::Client;
6use devimint::util::poll_simple;
7use devimint::version_constants::VERSION_0_5_0_ALPHA;
8use devimint::{cmd, util};
9use fedimint_core::PeerId;
10use serde_json::json;
11use tracing::{info, warn};
12
13#[derive(Parser, Debug)]
14pub enum TestCli {
15 Sanity,
16}
17
18#[tokio::main]
19async fn main() -> anyhow::Result<()> {
20 let opts = TestCli::parse();
21
22 match opts {
23 TestCli::Sanity => sanity_tests().await,
24 }
25}
26
27async fn sanity_tests() -> anyhow::Result<()> {
28 devimint::run_devfed_test()
29 .call(|dev_fed, _process_mgr| async move {
30 let fedimint_cli_version = util::FedimintCli::version_or_default().await;
31
32 let client = dev_fed
33 .fed()
34 .await?
35 .new_joined_client("meta-module-client")
36 .await?;
37
38 async fn get_consensus(client: &Client) -> anyhow::Result<serde_json::Value> {
39 cmd!(client, "module", "meta", "get").out_json().await
40 }
41
42 async fn get_submissions(
43 client: &Client,
44 peer_id: PeerId,
45 ) -> anyhow::Result<serde_json::Value> {
46 cmd!(
47 client,
48 "--our-id",
49 &peer_id.to_string(),
50 "--password",
51 "notset",
52 "module",
53 "meta",
54 "get-submissions"
55 )
56 .out_json()
57 .await
58 }
59
60 async fn submit(
61 client: &Client,
62 peer_id: PeerId,
63 value: &serde_json::Value,
64 ) -> anyhow::Result<serde_json::Value> {
65 info!(%peer_id, ?value, "Peer submitting value");
66
67 cmd!(
68 client,
69 "--our-id",
70 &peer_id.to_string(),
71 "--password",
72 "notset",
73 "module",
74 "meta",
75 "submit",
76 &value.to_string(),
77 )
78 .out_json()
79 .await
80 }
81
82 pub async fn poll_value<Fut>(
83 name: &str,
84 f: impl Fn() -> Fut,
85 expected_value: serde_json::Value,
86 ) -> Result<serde_json::Value>
87 where
88 Fut: Future<Output = Result<serde_json::Value, anyhow::Error>>,
89 {
90 poll_simple(name, || async {
91 let value = f().await?;
92 if value == expected_value {
93 Ok(value)
94 } else {
95 bail!("Incorrect value: {}, expected: {}", value, expected_value);
96 }
97 })
98 .await
99 }
100
101 async fn get_meta_fields(client: &Client) -> anyhow::Result<serde_json::Value> {
102 cmd!(client, "dev", "meta-fields",).out_json().await
103 }
104
105 assert_eq!(get_consensus(&client).await?, serde_json::Value::Null);
107 assert_eq!(
108 get_submissions(&client, PeerId::from(1)).await?,
109 json! {
110 {}
111 }
112 );
113
114 let submission_value = json! {
115 { "foo": "bar" }
116 };
117 let minority_submission_value = json! {
118 { "bar": "baz" }
119 };
120
121 submit(&client, PeerId::from(1), &submission_value).await?;
123
124 info!("Checking submission");
125 poll_value(
126 "submission visible on same peer",
127 || async { get_submissions(&client, PeerId::from(1)).await },
128 json! {
129 { "1": submission_value }
130 },
131 )
132 .await?;
133 poll_value(
134 "submission visible on a different peer",
135 || async { get_submissions(&client, PeerId::from(3)).await },
136 json! {
137 { "1": submission_value }
138 },
139 )
140 .await?;
141
142 submit(&client, PeerId::from(0), &minority_submission_value).await?;
144 submit(&client, PeerId::from(2), &submission_value).await?;
145 assert_eq!(
146 submit(&client, PeerId::from(3), &submission_value).await?,
147 serde_json::Value::Bool(true)
148 );
149
150 info!(expected = %submission_value, "Checking consensus");
151 if let Err(e) = poll_value(
152 "consensus set",
153 || async { get_consensus(&client).await },
154 json! {
155 {
156 "revision": 0,
157 "value":submission_value
158 }
159 },
160 )
161 .await
162 {
163 let submissions = get_submissions(&client, PeerId::from(3)).await?;
164 warn!(%submissions, "Getting expected consensus value failed");
165 return Err(e);
166 }
167
168 poll_value(
170 "minor submission visible",
171 || async { get_submissions(&client, PeerId::from(0)).await },
172 json! {
173 { "0": minority_submission_value}
174 },
175 )
176 .await?;
177
178 submit(&client, PeerId::from(0), &submission_value).await?;
181 poll_value(
182 "submission cleared",
183 || async { get_submissions(&client, PeerId::from(1)).await },
184 json! { {} },
185 )
186 .await?;
187
188 if fedimint_cli_version >= *VERSION_0_5_0_ALPHA {
191 let meta_fields = get_meta_fields(&client).await?;
192 assert_eq!(
193 meta_fields,
194 json! {
195 {
196 "revision": 0,
197 "values": submission_value,
198 }
199 }
200 );
201 }
202
203 Ok(())
204 })
205 .await
206}