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