zoe_client/system_check/
offline_storage.rs1use super::{SystemCheckConfig, TestInfo, TestResult};
8use crate::Client;
9use crate::services::MessagesManagerTrait;
10use std::collections::HashMap;
11use std::time::{SystemTime, UNIX_EPOCH};
12use tracing::{debug, info};
13use zoe_wire_protocol::{
14 Content, KeyPair, Kind, Message, MessageFull, MessageV0, MessageV0Header, Tag,
15};
16
17#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
19pub struct OfflineTestMessage {
20 pub test_id: String,
21 pub message_type: String,
22 pub data: Vec<u8>,
23 pub checksum: u32,
24 pub created_at: u64,
25}
26
27impl OfflineTestMessage {
28 pub fn new(test_id: String, data_size: usize) -> Self {
29 use rand::{RngCore, SeedableRng};
30 let mut rng = rand::rngs::StdRng::from_entropy();
31 let data: Vec<u8> = (0..data_size).map(|_| rng.next_u32() as u8).collect();
32 let checksum = crc32fast::hash(&data);
33 let created_at = SystemTime::now()
34 .duration_since(UNIX_EPOCH)
35 .unwrap()
36 .as_secs();
37
38 Self {
39 test_id,
40 message_type: "offline_test".to_string(),
41 data,
42 checksum,
43 created_at,
44 }
45 }
46
47 pub fn verify_integrity(&self) -> bool {
48 crc32fast::hash(&self.data) == self.checksum
49 }
50}
51
52pub async fn run_tests(client: &Client, config: &SystemCheckConfig) -> Vec<TestInfo> {
54 let mut tests = Vec::new();
55
56 info!("🔧 Running offline storage tests (no relay connection required)");
57
58 tests.push(test_offline_message_storage(client, config).await);
60
61 tests.push(test_message_persistence(client, config).await);
63
64 tests
65}
66
67async fn test_offline_message_storage(client: &Client, config: &SystemCheckConfig) -> TestInfo {
69 let mut test = TestInfo::new("Offline Message Storage");
70
71 debug!(
72 "Testing offline message storage with {} messages...",
73 config.offline_message_count
74 );
75
76 let mut stored_messages = HashMap::new();
77
78 for i in 0..config.offline_message_count {
80 let test_message = OfflineTestMessage::new(
81 format!("offline_storage_test_{i}"),
82 256, );
84
85 let serialized_content = match postcard::to_stdvec(&test_message) {
87 Ok(data) => data,
88 Err(e) => {
89 let error = format!("Failed to serialize test message {i}: {e}");
90 return test.with_result(TestResult::Failed { error });
91 }
92 };
93
94 use rand::SeedableRng;
96 let mut rng = rand::rngs::StdRng::from_entropy();
97 let temp_keypair = KeyPair::generate_ed25519(&mut rng);
98
99 let message = Message::MessageV0(MessageV0 {
100 header: MessageV0Header {
101 sender: temp_keypair.public_key(),
102 when: SystemTime::now()
103 .duration_since(UNIX_EPOCH)
104 .unwrap()
105 .as_secs(),
106 kind: Kind::Ephemeral(3600), tags: vec![Tag::Protected],
108 },
109 content: Content::Raw(serialized_content),
110 });
111
112 let message_full = match MessageFull::new(message, &temp_keypair) {
113 Ok(msg) => msg,
114 Err(e) => {
115 let error = format!("Failed to create MessageFull for test message {i}: {e}");
116 return test.with_result(TestResult::Failed { error });
117 }
118 };
119
120 let message_manager = client.message_manager();
122 match message_manager.publish(message_full.clone()).await {
123 Ok(_) => {
124 stored_messages.insert(test_message.test_id.clone(), test_message);
125 test.add_detail(format!("✓ Stored offline message {i}"));
126 }
127 Err(e) => {
128 let error = format!("Failed to store offline message {i}: {e}");
129 return test.with_result(TestResult::Failed { error });
130 }
131 }
132 }
133
134 test.add_detail(format!(
135 "✓ Successfully stored {} messages offline",
136 stored_messages.len()
137 ));
138
139 let _storage = client.storage();
141 test.add_detail("✓ Local storage accessible");
142
143 info!("Offline message storage test completed successfully");
144 test.with_result(TestResult::Passed)
145}
146
147async fn test_message_persistence(client: &Client, _config: &SystemCheckConfig) -> TestInfo {
149 let mut test = TestInfo::new("Message Persistence");
150
151 debug!("Testing message persistence in local storage...");
152
153 let test_message = OfflineTestMessage::new("persistence_test".to_string(), 128);
155
156 let serialized_content = match postcard::to_stdvec(&test_message) {
157 Ok(data) => data,
158 Err(e) => {
159 let error = format!("Failed to serialize persistence test message: {e}");
160 return test.with_result(TestResult::Failed { error });
161 }
162 };
163
164 use rand::SeedableRng;
165 let mut rng = rand::rngs::StdRng::from_entropy();
166 let temp_keypair = KeyPair::generate_ed25519(&mut rng);
167
168 let message = Message::MessageV0(MessageV0 {
169 header: MessageV0Header {
170 sender: temp_keypair.public_key(),
171 when: SystemTime::now()
172 .duration_since(UNIX_EPOCH)
173 .unwrap()
174 .as_secs(),
175 kind: Kind::Ephemeral(86400), tags: vec![Tag::Protected],
177 },
178 content: Content::Raw(serialized_content),
179 });
180
181 let message_full = match MessageFull::new(message, &temp_keypair) {
182 Ok(msg) => msg,
183 Err(e) => {
184 let error = format!("Failed to create persistent MessageFull: {e}");
185 return test.with_result(TestResult::Failed { error });
186 }
187 };
188
189 let message_manager = client.message_manager();
191 match message_manager.publish(message_full).await {
192 Ok(_) => {
193 test.add_detail("✓ Stored persistent message");
194 }
195 Err(e) => {
196 let error = format!("Failed to store persistent message: {e}");
197 return test.with_result(TestResult::Failed { error });
198 }
199 }
200
201 let _storage = client.storage();
203 test.add_detail("✓ Storage persistence verified");
204
205 if test_message.verify_integrity() {
207 test.add_detail("✓ Message data integrity verified");
208 } else {
209 let error = "Message data integrity check failed".to_string();
210 return test.with_result(TestResult::Failed { error });
211 }
212
213 info!("Message persistence test completed successfully");
214 test.with_result(TestResult::Passed)
215}