Skip to content

Commit f5822a0

Browse files
committed
Introduce InMemoryStore for testing
Recently, `rust-lightning` broke the (async) API of the `TestStore`, making it ~impossible to use in regular tests. Here, we un-DRY our `TestStore` implementation and simply copy over the previous `TestStore` version, now named `InMemoryStore` to discern the objects. We also switch all feasible instances over to use `InMemoryStore` rather than LDK's `test_utils::TestStore`.
1 parent cef82e4 commit f5822a0

File tree

5 files changed

+138
-11
lines changed

5 files changed

+138
-11
lines changed

src/data_store.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,11 @@ where
172172
#[cfg(test)]
173173
mod tests {
174174
use lightning::impl_writeable_tlv_based;
175-
use lightning::util::test_utils::{TestLogger, TestStore};
175+
use lightning::util::test_utils::TestLogger;
176176

177177
use super::*;
178178
use crate::hex_utils;
179+
use crate::io::test_utils::InMemoryStore;
179180

180181
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
181182
struct TestObjectId {
@@ -234,7 +235,7 @@ mod tests {
234235

235236
#[test]
236237
fn data_is_persisted() {
237-
let store: Arc<DynStore> = Arc::new(TestStore::new(false));
238+
let store: Arc<DynStore> = Arc::new(InMemoryStore::new());
238239
let logger = Arc::new(TestLogger::new());
239240
let primary_namespace = "datastore_test_primary".to_string();
240241
let secondary_namespace = "datastore_test_secondary".to_string();

src/event.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,13 +1605,14 @@ mod tests {
16051605
use std::sync::atomic::{AtomicU16, Ordering};
16061606
use std::time::Duration;
16071607

1608-
use lightning::util::test_utils::{TestLogger, TestStore};
1608+
use lightning::util::test_utils::TestLogger;
16091609

16101610
use super::*;
1611+
use crate::io::test_utils::InMemoryStore;
16111612

16121613
#[tokio::test]
16131614
async fn event_queue_persistence() {
1614-
let store: Arc<DynStore> = Arc::new(TestStore::new(false));
1615+
let store: Arc<DynStore> = Arc::new(InMemoryStore::new());
16151616
let logger = Arc::new(TestLogger::new());
16161617
let event_queue = Arc::new(EventQueue::new(Arc::clone(&store), Arc::clone(&logger)));
16171618
assert_eq!(event_queue.next_event(), None);
@@ -1647,7 +1648,7 @@ mod tests {
16471648

16481649
#[tokio::test]
16491650
async fn event_queue_concurrency() {
1650-
let store: Arc<DynStore> = Arc::new(TestStore::new(false));
1651+
let store: Arc<DynStore> = Arc::new(InMemoryStore::new());
16511652
let logger = Arc::new(TestLogger::new());
16521653
let event_queue = Arc::new(EventQueue::new(Arc::clone(&store), Arc::clone(&logger)));
16531654
assert_eq!(event_queue.next_event(), None);

src/io/test_utils.rs

Lines changed: 126 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,24 @@
55
// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
66
// accordance with one or both of these licenses.
77

8+
use std::boxed::Box;
9+
use std::collections::{hash_map, HashMap};
10+
use std::future::Future;
811
use std::panic::RefUnwindSafe;
912
use std::path::PathBuf;
13+
use std::pin::Pin;
14+
use std::sync::Mutex;
1015

1116
use lightning::events::ClosureReason;
1217
use lightning::ln::functional_test_utils::{
1318
connect_block, create_announced_chan_between_nodes, create_chanmon_cfgs, create_dummy_block,
1419
create_network, create_node_cfgs, create_node_chanmgrs, send_payment, TestChanMonCfg,
1520
};
1621
use lightning::util::persist::{
17-
KVStoreSync, MonitorUpdatingPersister, KVSTORE_NAMESPACE_KEY_MAX_LEN,
22+
KVStore, KVStoreSync, MonitorUpdatingPersister, KVSTORE_NAMESPACE_KEY_MAX_LEN,
1823
};
1924
use lightning::util::test_utils;
20-
use lightning::{check_added_monitors, check_closed_broadcast, check_closed_event};
25+
use lightning::{check_added_monitors, check_closed_broadcast, check_closed_event, io};
2126
use rand::distr::Alphanumeric;
2227
use rand::{rng, Rng};
2328

@@ -32,6 +37,125 @@ type TestMonitorUpdatePersister<'a, K> = MonitorUpdatingPersister<
3237

3338
const EXPECTED_UPDATES_PER_PAYMENT: u64 = 5;
3439

40+
pub struct InMemoryStore {
41+
persisted_bytes: Mutex<HashMap<String, HashMap<String, Vec<u8>>>>,
42+
}
43+
44+
impl InMemoryStore {
45+
pub fn new() -> Self {
46+
let persisted_bytes = Mutex::new(HashMap::new());
47+
Self { persisted_bytes }
48+
}
49+
50+
fn read_internal(
51+
&self, primary_namespace: &str, secondary_namespace: &str, key: &str,
52+
) -> io::Result<Vec<u8>> {
53+
let persisted_lock = self.persisted_bytes.lock().unwrap();
54+
let prefixed = format!("{primary_namespace}/{secondary_namespace}");
55+
56+
if let Some(outer_ref) = persisted_lock.get(&prefixed) {
57+
if let Some(inner_ref) = outer_ref.get(key) {
58+
let bytes = inner_ref.clone();
59+
Ok(bytes)
60+
} else {
61+
Err(io::Error::new(io::ErrorKind::NotFound, "Key not found"))
62+
}
63+
} else {
64+
Err(io::Error::new(io::ErrorKind::NotFound, "Namespace not found"))
65+
}
66+
}
67+
68+
fn write_internal(
69+
&self, primary_namespace: &str, secondary_namespace: &str, key: &str, buf: Vec<u8>,
70+
) -> io::Result<()> {
71+
let mut persisted_lock = self.persisted_bytes.lock().unwrap();
72+
73+
let prefixed = format!("{primary_namespace}/{secondary_namespace}");
74+
let outer_e = persisted_lock.entry(prefixed).or_insert(HashMap::new());
75+
outer_e.insert(key.to_string(), buf);
76+
Ok(())
77+
}
78+
79+
fn remove_internal(
80+
&self, primary_namespace: &str, secondary_namespace: &str, key: &str, _lazy: bool,
81+
) -> io::Result<()> {
82+
let mut persisted_lock = self.persisted_bytes.lock().unwrap();
83+
84+
let prefixed = format!("{primary_namespace}/{secondary_namespace}");
85+
if let Some(outer_ref) = persisted_lock.get_mut(&prefixed) {
86+
outer_ref.remove(&key.to_string());
87+
}
88+
89+
Ok(())
90+
}
91+
92+
fn list_internal(
93+
&self, primary_namespace: &str, secondary_namespace: &str,
94+
) -> io::Result<Vec<String>> {
95+
let mut persisted_lock = self.persisted_bytes.lock().unwrap();
96+
97+
let prefixed = format!("{primary_namespace}/{secondary_namespace}");
98+
match persisted_lock.entry(prefixed) {
99+
hash_map::Entry::Occupied(e) => Ok(e.get().keys().cloned().collect()),
100+
hash_map::Entry::Vacant(_) => Ok(Vec::new()),
101+
}
102+
}
103+
}
104+
105+
impl KVStore for InMemoryStore {
106+
fn read(
107+
&self, primary_namespace: &str, secondary_namespace: &str, key: &str,
108+
) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, io::Error>> + 'static + Send>> {
109+
let res = self.read_internal(&primary_namespace, &secondary_namespace, &key);
110+
Box::pin(async move { res })
111+
}
112+
fn write(
113+
&self, primary_namespace: &str, secondary_namespace: &str, key: &str, buf: Vec<u8>,
114+
) -> Pin<Box<dyn Future<Output = Result<(), io::Error>> + 'static + Send>> {
115+
let res = self.write_internal(&primary_namespace, &secondary_namespace, &key, buf);
116+
Box::pin(async move { res })
117+
}
118+
fn remove(
119+
&self, primary_namespace: &str, secondary_namespace: &str, key: &str, lazy: bool,
120+
) -> Pin<Box<dyn Future<Output = Result<(), io::Error>> + 'static + Send>> {
121+
let res = self.remove_internal(&primary_namespace, &secondary_namespace, &key, lazy);
122+
Box::pin(async move { res })
123+
}
124+
fn list(
125+
&self, primary_namespace: &str, secondary_namespace: &str,
126+
) -> Pin<Box<dyn Future<Output = Result<Vec<String>, io::Error>> + 'static + Send>> {
127+
let res = self.list_internal(primary_namespace, secondary_namespace);
128+
Box::pin(async move { res })
129+
}
130+
}
131+
132+
impl KVStoreSync for InMemoryStore {
133+
fn read(
134+
&self, primary_namespace: &str, secondary_namespace: &str, key: &str,
135+
) -> io::Result<Vec<u8>> {
136+
self.read_internal(primary_namespace, secondary_namespace, key)
137+
}
138+
139+
fn write(
140+
&self, primary_namespace: &str, secondary_namespace: &str, key: &str, buf: Vec<u8>,
141+
) -> io::Result<()> {
142+
self.write_internal(primary_namespace, secondary_namespace, key, buf)
143+
}
144+
145+
fn remove(
146+
&self, primary_namespace: &str, secondary_namespace: &str, key: &str, lazy: bool,
147+
) -> io::Result<()> {
148+
self.remove_internal(primary_namespace, secondary_namespace, key, lazy)
149+
}
150+
151+
fn list(&self, primary_namespace: &str, secondary_namespace: &str) -> io::Result<Vec<String>> {
152+
self.list_internal(primary_namespace, secondary_namespace)
153+
}
154+
}
155+
156+
unsafe impl Sync for InMemoryStore {}
157+
unsafe impl Send for InMemoryStore {}
158+
35159
pub(crate) fn random_storage_path() -> PathBuf {
36160
let mut temp_path = std::env::temp_dir();
37161
let mut rng = rng();

src/payment/asynchronous/static_invoice_store.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,15 +157,15 @@ mod tests {
157157
use lightning::offers::offer::OfferBuilder;
158158
use lightning::offers::static_invoice::{StaticInvoice, StaticInvoiceBuilder};
159159
use lightning::sign::EntropySource;
160-
use lightning::util::test_utils::TestStore;
161160
use lightning_types::features::BlindedHopFeatures;
162161

162+
use crate::io::test_utils::InMemoryStore;
163163
use crate::payment::asynchronous::static_invoice_store::StaticInvoiceStore;
164164
use crate::types::DynStore;
165165

166166
#[tokio::test]
167167
async fn static_invoice_store_test() {
168-
let store: Arc<DynStore> = Arc::new(TestStore::new(false));
168+
let store: Arc<DynStore> = Arc::new(InMemoryStore::new());
169169
let static_invoice_store = StaticInvoiceStore::new(Arc::clone(&store));
170170

171171
let static_invoice = invoice();

src/peer_store.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,13 +152,14 @@ mod tests {
152152
use std::str::FromStr;
153153
use std::sync::Arc;
154154

155-
use lightning::util::test_utils::{TestLogger, TestStore};
155+
use lightning::util::test_utils::TestLogger;
156156

157157
use super::*;
158+
use crate::io::test_utils::InMemoryStore;
158159

159160
#[test]
160161
fn peer_info_persistence() {
161-
let store: Arc<DynStore> = Arc::new(TestStore::new(false));
162+
let store: Arc<DynStore> = Arc::new(InMemoryStore::new());
162163
let logger = Arc::new(TestLogger::new());
163164
let peer_store = PeerStore::new(Arc::clone(&store), Arc::clone(&logger));
164165

0 commit comments

Comments
 (0)