1use std::collections::BTreeMap;
2use std::time::Duration;
3
4use fedimint_core::db::DbMigrationFnContext;
5use futures::future::ready;
6use futures::{Future, FutureExt, StreamExt};
7use rand::Rng;
8use tokio::join;
9
10use super::{
11 Database, DatabaseTransaction, DatabaseVersion, DatabaseVersionKey, DatabaseVersionKeyV0,
12 DbMigrationError, DbMigrationFn, apply_migrations, apply_migrations_dbtx,
13 create_database_version_dbtx,
14};
15use crate::core::ModuleKind;
16use crate::db::mem_impl::MemDatabase;
17use crate::db::{IDatabaseTransactionOps, IDatabaseTransactionOpsCoreTyped, MODULE_GLOBAL_PREFIX};
18use crate::encoding::{Decodable, Encodable};
19use crate::module::registry::ModuleDecoderRegistry;
20
21pub async fn future_returns_shortly<F: Future>(fut: F) -> Option<F::Output> {
22 crate::runtime::timeout(Duration::from_millis(10), fut)
23 .await
24 .ok()
25}
26
27#[repr(u8)]
28#[derive(Clone)]
29pub enum TestDbKeyPrefix {
30 Test = 0x42,
31 AltTest = 0x43,
32 PercentTestKey = 0x25,
33}
34
35#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)]
36pub(super) struct TestKey(pub u64);
37
38#[derive(Debug, Encodable, Decodable)]
39struct DbPrefixTestPrefix;
40
41impl_db_record!(
42 key = TestKey,
43 value = TestVal,
44 db_prefix = TestDbKeyPrefix::Test,
45 notify_on_modify = true,
46);
47impl_db_lookup!(key = TestKey, query_prefix = DbPrefixTestPrefix);
48
49#[derive(Debug, Encodable, Decodable)]
50struct TestKeyV0(u64, u64);
51
52#[derive(Debug, Encodable, Decodable)]
53struct DbPrefixTestPrefixV0;
54
55impl_db_record!(
56 key = TestKeyV0,
57 value = TestVal,
58 db_prefix = TestDbKeyPrefix::Test,
59);
60impl_db_lookup!(key = TestKeyV0, query_prefix = DbPrefixTestPrefixV0);
61
62#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Encodable, Decodable)]
63struct AltTestKey(u64);
64
65#[derive(Debug, Encodable, Decodable)]
66struct AltDbPrefixTestPrefix;
67
68impl_db_record!(
69 key = AltTestKey,
70 value = TestVal,
71 db_prefix = TestDbKeyPrefix::AltTest,
72);
73impl_db_lookup!(key = AltTestKey, query_prefix = AltDbPrefixTestPrefix);
74
75#[derive(Debug, Encodable, Decodable)]
76struct PercentTestKey(u64);
77
78#[derive(Debug, Encodable, Decodable)]
79struct PercentPrefixTestPrefix;
80
81impl_db_record!(
82 key = PercentTestKey,
83 value = TestVal,
84 db_prefix = TestDbKeyPrefix::PercentTestKey,
85);
86
87impl_db_lookup!(key = PercentTestKey, query_prefix = PercentPrefixTestPrefix);
88#[derive(Debug, Encodable, Decodable, Eq, PartialEq, PartialOrd, Ord)]
89pub(super) struct TestVal(pub u64);
90
91const TEST_MODULE_PREFIX: u16 = 1;
92const ALT_MODULE_PREFIX: u16 = 2;
93
94pub async fn verify_insert_elements(db: Database) {
95 let mut dbtx = db.begin_transaction().await;
96 assert!(dbtx.insert_entry(&TestKey(1), &TestVal(2)).await.is_none());
97 assert!(dbtx.insert_entry(&TestKey(2), &TestVal(3)).await.is_none());
98 dbtx.commit_tx().await;
99
100 let mut dbtx = db.begin_transaction().await;
102 assert_eq!(dbtx.get_value(&TestKey(1)).await, Some(TestVal(2)));
103 assert_eq!(dbtx.get_value(&TestKey(2)).await, Some(TestVal(3)));
104 dbtx.commit_tx().await;
105
106 let mut dbtx = db.begin_transaction().await;
108 assert_eq!(
109 dbtx.insert_entry(&TestKey(1), &TestVal(4)).await,
110 Some(TestVal(2))
111 );
112 assert_eq!(
113 dbtx.insert_entry(&TestKey(2), &TestVal(5)).await,
114 Some(TestVal(3))
115 );
116 dbtx.commit_tx().await;
117
118 let mut dbtx = db.begin_transaction().await;
119 assert_eq!(dbtx.get_value(&TestKey(1)).await, Some(TestVal(4)));
120 assert_eq!(dbtx.get_value(&TestKey(2)).await, Some(TestVal(5)));
121 dbtx.commit_tx().await;
122}
123
124pub async fn verify_remove_nonexisting(db: Database) {
125 let mut dbtx = db.begin_transaction().await;
126 assert_eq!(dbtx.get_value(&TestKey(1)).await, None);
127 let removed = dbtx.remove_entry(&TestKey(1)).await;
128 assert!(removed.is_none());
129
130 dbtx.commit_tx().await;
132}
133
134pub async fn verify_remove_existing(db: Database) {
135 let mut dbtx = db.begin_transaction().await;
136
137 assert!(dbtx.insert_entry(&TestKey(1), &TestVal(2)).await.is_none());
138
139 assert_eq!(dbtx.get_value(&TestKey(1)).await, Some(TestVal(2)));
140
141 let removed = dbtx.remove_entry(&TestKey(1)).await;
142 assert_eq!(removed, Some(TestVal(2)));
143 assert_eq!(dbtx.get_value(&TestKey(1)).await, None);
144
145 dbtx.commit_tx().await;
147}
148
149pub async fn verify_read_own_writes(db: Database) {
150 let mut dbtx = db.begin_transaction().await;
151
152 assert!(dbtx.insert_entry(&TestKey(1), &TestVal(2)).await.is_none());
153
154 assert_eq!(dbtx.get_value(&TestKey(1)).await, Some(TestVal(2)));
155
156 dbtx.commit_tx().await;
158}
159
160pub async fn verify_prevent_dirty_reads(db: Database) {
161 let mut dbtx = db.begin_transaction().await;
162
163 assert!(dbtx.insert_entry(&TestKey(1), &TestVal(2)).await.is_none());
164
165 let mut dbtx2 = db.begin_transaction().await;
167 assert_eq!(dbtx2.get_value(&TestKey(1)).await, None);
168
169 dbtx.commit_tx().await;
171}
172
173pub async fn verify_find_by_range(db: Database) {
174 let mut dbtx = db.begin_transaction().await;
175 dbtx.insert_entry(&TestKey(55), &TestVal(9999)).await;
176 dbtx.insert_entry(&TestKey(54), &TestVal(8888)).await;
177 dbtx.insert_entry(&TestKey(56), &TestVal(7777)).await;
178
179 dbtx.insert_entry(&AltTestKey(55), &TestVal(7777)).await;
180 dbtx.insert_entry(&AltTestKey(54), &TestVal(6666)).await;
181
182 {
183 let mut module_dbtx = dbtx.to_ref_with_prefix_module_id(2).0;
184 module_dbtx
185 .insert_entry(&TestKey(300), &TestVal(3000))
186 .await;
187 }
188
189 dbtx.commit_tx().await;
190
191 let mut dbtx = db.begin_transaction_nc().await;
193
194 let returned_keys = dbtx
195 .find_by_range(TestKey(55)..TestKey(56))
196 .await
197 .collect::<Vec<_>>()
198 .await;
199
200 let expected = vec![(TestKey(55), TestVal(9999))];
201
202 assert_eq!(returned_keys, expected);
203
204 let returned_keys = dbtx
205 .find_by_range(TestKey(54)..TestKey(56))
206 .await
207 .collect::<Vec<_>>()
208 .await;
209
210 let expected = vec![(TestKey(54), TestVal(8888)), (TestKey(55), TestVal(9999))];
211 assert_eq!(returned_keys, expected);
212
213 let returned_keys = dbtx
214 .find_by_range(TestKey(54)..TestKey(57))
215 .await
216 .collect::<Vec<_>>()
217 .await;
218
219 let expected = vec![
220 (TestKey(54), TestVal(8888)),
221 (TestKey(55), TestVal(9999)),
222 (TestKey(56), TestVal(7777)),
223 ];
224 assert_eq!(returned_keys, expected);
225
226 let mut module_dbtx = dbtx.with_prefix_module_id(2).0;
227 let test_range = module_dbtx
228 .find_by_range(TestKey(300)..TestKey(301))
229 .await
230 .collect::<Vec<_>>()
231 .await;
232 assert!(test_range.len() == 1);
233}
234
235pub async fn verify_find_by_prefix(db: Database) {
236 let mut dbtx = db.begin_transaction().await;
237 dbtx.insert_entry(&TestKey(55), &TestVal(9999)).await;
238 dbtx.insert_entry(&TestKey(54), &TestVal(8888)).await;
239
240 dbtx.insert_entry(&AltTestKey(55), &TestVal(7777)).await;
241 dbtx.insert_entry(&AltTestKey(54), &TestVal(6666)).await;
242 dbtx.commit_tx().await;
243
244 let mut dbtx = db.begin_transaction().await;
246
247 let returned_keys = dbtx
248 .find_by_prefix(&DbPrefixTestPrefix)
249 .await
250 .collect::<Vec<_>>()
251 .await;
252
253 let expected = vec![(TestKey(54), TestVal(8888)), (TestKey(55), TestVal(9999))];
254 assert_eq!(returned_keys, expected);
255
256 let reversed = dbtx
257 .find_by_prefix_sorted_descending(&DbPrefixTestPrefix)
258 .await
259 .collect::<Vec<_>>()
260 .await;
261 let mut reversed_expected = expected;
262 reversed_expected.reverse();
263 assert_eq!(reversed, reversed_expected);
264
265 let returned_keys = dbtx
266 .find_by_prefix(&AltDbPrefixTestPrefix)
267 .await
268 .collect::<Vec<_>>()
269 .await;
270
271 let expected = vec![
272 (AltTestKey(54), TestVal(6666)),
273 (AltTestKey(55), TestVal(7777)),
274 ];
275 assert_eq!(returned_keys, expected);
276
277 let reversed = dbtx
278 .find_by_prefix_sorted_descending(&AltDbPrefixTestPrefix)
279 .await
280 .collect::<Vec<_>>()
281 .await;
282 let mut reversed_expected = expected;
283 reversed_expected.reverse();
284 assert_eq!(reversed, reversed_expected);
285}
286
287pub async fn verify_commit(db: Database) {
288 let mut dbtx = db.begin_transaction().await;
289
290 assert!(dbtx.insert_entry(&TestKey(1), &TestVal(2)).await.is_none());
291 dbtx.commit_tx().await;
292
293 let mut dbtx2 = db.begin_transaction().await;
295 assert_eq!(dbtx2.get_value(&TestKey(1)).await, Some(TestVal(2)));
296}
297
298pub async fn verify_prevent_nonrepeatable_reads(db: Database) {
299 let mut dbtx = db.begin_transaction().await;
300 assert_eq!(dbtx.get_value(&TestKey(100)).await, None);
301
302 let mut dbtx2 = db.begin_transaction().await;
303
304 dbtx2.insert_entry(&TestKey(100), &TestVal(101)).await;
305
306 assert_eq!(dbtx.get_value(&TestKey(100)).await, None);
307
308 dbtx2.commit_tx().await;
309
310 assert_eq!(dbtx.get_value(&TestKey(100)).await, None);
313
314 let expected_keys = 0;
315 let returned_keys = dbtx
316 .find_by_prefix(&DbPrefixTestPrefix)
317 .await
318 .fold(0, |returned_keys, (key, value)| async move {
319 if key == TestKey(100) {
320 assert!(value.eq(&TestVal(101)));
321 }
322 returned_keys + 1
323 })
324 .await;
325
326 assert_eq!(returned_keys, expected_keys);
327}
328
329pub async fn verify_snapshot_isolation(db: Database) {
330 async fn random_yield() {
331 let times = if rand::thread_rng().gen_bool(0.5) {
332 0
333 } else {
334 10
335 };
336 for _ in 0..times {
337 tokio::task::yield_now().await;
338 }
339 }
340
341 for i in 0..1000 {
343 let base_key = i * 2;
344 let tx_accepted_key = base_key;
345 let spent_input_key = base_key + 1;
346
347 join!(
348 async {
349 random_yield().await;
350 let mut dbtx = db.begin_transaction().await;
351
352 random_yield().await;
353 let a = dbtx.get_value(&TestKey(tx_accepted_key)).await;
354 random_yield().await;
355 let s = match i % 5 {
358 0 => dbtx.get_value(&TestKey(spent_input_key)).await,
359 1 => dbtx.remove_entry(&TestKey(spent_input_key)).await,
360 2 => {
361 dbtx.insert_entry(&TestKey(spent_input_key), &TestVal(200))
362 .await
363 }
364 3 => {
365 dbtx.find_by_prefix(&DbPrefixTestPrefix)
366 .await
367 .filter(|(k, _v)| ready(k == &TestKey(spent_input_key)))
368 .map(|(_k, v)| v)
369 .next()
370 .await
371 }
372 4 => {
373 dbtx.find_by_prefix_sorted_descending(&DbPrefixTestPrefix)
374 .await
375 .filter(|(k, _v)| ready(k == &TestKey(spent_input_key)))
376 .map(|(_k, v)| v)
377 .next()
378 .await
379 }
380 _ => {
381 panic!("woot?");
382 }
383 };
384
385 match (a, s) {
386 (None, None) | (Some(_), Some(_)) => {}
387 (None, Some(_)) => panic!("none some?! {i}"),
388 (Some(_), None) => panic!("some none?! {i}"),
389 }
390 },
391 async {
392 random_yield().await;
393
394 let mut dbtx = db.begin_transaction().await;
395 random_yield().await;
396 assert_eq!(dbtx.get_value(&TestKey(tx_accepted_key)).await, None);
397
398 random_yield().await;
399 assert_eq!(
400 dbtx.insert_entry(&TestKey(spent_input_key), &TestVal(100))
401 .await,
402 None
403 );
404
405 random_yield().await;
406 assert_eq!(
407 dbtx.insert_entry(&TestKey(tx_accepted_key), &TestVal(100))
408 .await,
409 None
410 );
411 random_yield().await;
412 dbtx.commit_tx().await;
413 }
414 );
415 }
416}
417
418pub async fn verify_phantom_entry(db: Database) {
419 let mut dbtx = db.begin_transaction().await;
420
421 dbtx.insert_entry(&TestKey(100), &TestVal(101)).await;
422
423 dbtx.insert_entry(&TestKey(101), &TestVal(102)).await;
424
425 dbtx.commit_tx().await;
426
427 let mut dbtx = db.begin_transaction().await;
428 let expected_keys = 2;
429 let returned_keys = dbtx
430 .find_by_prefix(&DbPrefixTestPrefix)
431 .await
432 .fold(0, |returned_keys, (key, value)| async move {
433 match key {
434 TestKey(100) => {
435 assert!(value.eq(&TestVal(101)));
436 }
437 TestKey(101) => {
438 assert!(value.eq(&TestVal(102)));
439 }
440 _ => {}
441 }
442 returned_keys + 1
443 })
444 .await;
445
446 assert_eq!(returned_keys, expected_keys);
447
448 let mut dbtx2 = db.begin_transaction().await;
449
450 dbtx2.insert_entry(&TestKey(102), &TestVal(103)).await;
451
452 dbtx2.commit_tx().await;
453
454 let returned_keys = dbtx
455 .find_by_prefix(&DbPrefixTestPrefix)
456 .await
457 .fold(0, |returned_keys, (key, value)| async move {
458 match key {
459 TestKey(100) => {
460 assert!(value.eq(&TestVal(101)));
461 }
462 TestKey(101) => {
463 assert!(value.eq(&TestVal(102)));
464 }
465 _ => {}
466 }
467 returned_keys + 1
468 })
469 .await;
470
471 assert_eq!(returned_keys, expected_keys);
472}
473
474pub async fn expect_write_conflict(db: Database) {
475 let mut dbtx = db.begin_transaction().await;
476 dbtx.insert_entry(&TestKey(100), &TestVal(101)).await;
477 dbtx.commit_tx().await;
478
479 let mut dbtx2 = db.begin_transaction().await;
480 let mut dbtx3 = db.begin_transaction().await;
481
482 dbtx2.insert_entry(&TestKey(100), &TestVal(102)).await;
483
484 dbtx3.insert_entry(&TestKey(100), &TestVal(103)).await;
488
489 dbtx2.commit_tx().await;
490 dbtx3.commit_tx_result().await.expect_err("Expecting an error to be returned because this transaction is in a write-write conflict with dbtx");
491}
492
493pub async fn verify_string_prefix(db: Database) {
494 let mut dbtx = db.begin_transaction().await;
495 dbtx.insert_entry(&PercentTestKey(100), &TestVal(101)).await;
496
497 assert_eq!(
498 dbtx.get_value(&PercentTestKey(100)).await,
499 Some(TestVal(101))
500 );
501
502 dbtx.insert_entry(&PercentTestKey(101), &TestVal(100)).await;
503
504 dbtx.insert_entry(&PercentTestKey(101), &TestVal(100)).await;
505
506 dbtx.insert_entry(&PercentTestKey(101), &TestVal(100)).await;
507
508 dbtx.insert_entry(&TestKey(101), &TestVal(100)).await;
511
512 let expected_keys = 4;
513 let returned_keys = dbtx
514 .find_by_prefix(&PercentPrefixTestPrefix)
515 .await
516 .fold(0, |returned_keys, (key, value)| async move {
517 if matches!(key, PercentTestKey(101)) {
518 assert!(value.eq(&TestVal(100)));
519 }
520 returned_keys + 1
521 })
522 .await;
523
524 assert_eq!(returned_keys, expected_keys);
525}
526
527pub async fn verify_remove_by_prefix(db: Database) {
528 let mut dbtx = db.begin_transaction().await;
529
530 dbtx.insert_entry(&TestKey(100), &TestVal(101)).await;
531
532 dbtx.insert_entry(&TestKey(101), &TestVal(102)).await;
533
534 dbtx.commit_tx().await;
535
536 let mut remove_dbtx = db.begin_transaction().await;
537 remove_dbtx.remove_by_prefix(&DbPrefixTestPrefix).await;
538 remove_dbtx.commit_tx().await;
539
540 let mut dbtx = db.begin_transaction().await;
541 let expected_keys = 0;
542 let returned_keys = dbtx
543 .find_by_prefix(&DbPrefixTestPrefix)
544 .await
545 .fold(0, |returned_keys, (key, value)| async move {
546 match key {
547 TestKey(100) => {
548 assert!(value.eq(&TestVal(101)));
549 }
550 TestKey(101) => {
551 assert!(value.eq(&TestVal(102)));
552 }
553 _ => {}
554 }
555 returned_keys + 1
556 })
557 .await;
558
559 assert_eq!(returned_keys, expected_keys);
560}
561
562pub async fn verify_module_db(db: Database, module_db: Database) {
563 let mut dbtx = db.begin_transaction().await;
564
565 dbtx.insert_entry(&TestKey(100), &TestVal(101)).await;
566
567 dbtx.insert_entry(&TestKey(101), &TestVal(102)).await;
568
569 dbtx.commit_tx().await;
570
571 let mut module_dbtx = module_db.begin_transaction().await;
573 assert_eq!(module_dbtx.get_value(&TestKey(100)).await, None);
574
575 assert_eq!(module_dbtx.get_value(&TestKey(101)).await, None);
576
577 let mut dbtx = db.begin_transaction().await;
579 assert_eq!(dbtx.get_value(&TestKey(100)).await, Some(TestVal(101)));
580
581 assert_eq!(dbtx.get_value(&TestKey(101)).await, Some(TestVal(102)));
582
583 let mut module_dbtx = module_db.begin_transaction().await;
584
585 module_dbtx.insert_entry(&TestKey(100), &TestVal(103)).await;
586
587 module_dbtx.insert_entry(&TestKey(101), &TestVal(104)).await;
588
589 module_dbtx.commit_tx().await;
590
591 let expected_keys = 2;
592 let mut dbtx = db.begin_transaction().await;
593 let returned_keys = dbtx
594 .find_by_prefix(&DbPrefixTestPrefix)
595 .await
596 .fold(0, |returned_keys, (key, value)| async move {
597 match key {
598 TestKey(100) => {
599 assert!(value.eq(&TestVal(101)));
600 }
601 TestKey(101) => {
602 assert!(value.eq(&TestVal(102)));
603 }
604 _ => {}
605 }
606 returned_keys + 1
607 })
608 .await;
609
610 assert_eq!(returned_keys, expected_keys);
611
612 let removed = dbtx.remove_entry(&TestKey(100)).await;
613 assert_eq!(removed, Some(TestVal(101)));
614 assert_eq!(dbtx.get_value(&TestKey(100)).await, None);
615
616 let mut module_dbtx = module_db.begin_transaction().await;
617 assert_eq!(
618 module_dbtx.get_value(&TestKey(100)).await,
619 Some(TestVal(103))
620 );
621}
622
623pub async fn verify_module_prefix(db: Database) {
624 let mut test_dbtx = db.begin_transaction().await;
625 {
626 let mut test_module_dbtx = test_dbtx.to_ref_with_prefix_module_id(TEST_MODULE_PREFIX).0;
627
628 test_module_dbtx
629 .insert_entry(&TestKey(100), &TestVal(101))
630 .await;
631
632 test_module_dbtx
633 .insert_entry(&TestKey(101), &TestVal(102))
634 .await;
635 }
636
637 test_dbtx.commit_tx().await;
638
639 let mut alt_dbtx = db.begin_transaction().await;
640 {
641 let mut alt_module_dbtx = alt_dbtx.to_ref_with_prefix_module_id(ALT_MODULE_PREFIX).0;
642
643 alt_module_dbtx
644 .insert_entry(&TestKey(100), &TestVal(103))
645 .await;
646
647 alt_module_dbtx
648 .insert_entry(&TestKey(101), &TestVal(104))
649 .await;
650 }
651
652 alt_dbtx.commit_tx().await;
653
654 let mut test_dbtx = db.begin_transaction().await;
656 let mut test_module_dbtx = test_dbtx.to_ref_with_prefix_module_id(TEST_MODULE_PREFIX).0;
657 assert_eq!(
658 test_module_dbtx.get_value(&TestKey(100)).await,
659 Some(TestVal(101))
660 );
661
662 assert_eq!(
663 test_module_dbtx.get_value(&TestKey(101)).await,
664 Some(TestVal(102))
665 );
666
667 let expected_keys = 2;
668 let returned_keys = test_module_dbtx
669 .find_by_prefix(&DbPrefixTestPrefix)
670 .await
671 .fold(0, |returned_keys, (key, value)| async move {
672 match key {
673 TestKey(100) => {
674 assert!(value.eq(&TestVal(101)));
675 }
676 TestKey(101) => {
677 assert!(value.eq(&TestVal(102)));
678 }
679 _ => {}
680 }
681 returned_keys + 1
682 })
683 .await;
684
685 assert_eq!(returned_keys, expected_keys);
686
687 let removed = test_module_dbtx.remove_entry(&TestKey(100)).await;
688 assert_eq!(removed, Some(TestVal(101)));
689 assert_eq!(test_module_dbtx.get_value(&TestKey(100)).await, None);
690
691 let mut test_dbtx = db.begin_transaction().await;
694 assert_eq!(test_dbtx.get_value(&TestKey(101)).await, None);
695
696 test_dbtx.commit_tx().await;
697}
698
699#[cfg(test)]
700#[tokio::test]
701pub async fn verify_test_migration() {
702 let db = Database::new(MemDatabase::new(), ModuleDecoderRegistry::default());
704 let expected_test_keys_size: usize = 100;
705 let mut dbtx = db.begin_transaction().await;
706 for i in 0..expected_test_keys_size {
707 dbtx.insert_new_entry(&TestKeyV0(i as u64, (i + 1) as u64), &TestVal(i as u64))
708 .await;
709 }
710
711 dbtx.insert_new_entry(&DatabaseVersionKeyV0, &DatabaseVersion(0))
713 .await;
714 dbtx.commit_tx().await;
715
716 let mut migrations: BTreeMap<DatabaseVersion, DbMigrationFn<()>> = BTreeMap::new();
717
718 migrations.insert(
719 DatabaseVersion(0),
720 Box::new(|ctx| migrate_test_db_version_0(ctx).boxed()),
721 );
722
723 apply_migrations(&db, (), "TestModule".to_string(), migrations, None, None)
724 .await
725 .expect("Error applying migrations for TestModule");
726
727 let mut dbtx = db.begin_transaction().await;
729
730 assert!(
733 dbtx.get_value(&DatabaseVersionKey(MODULE_GLOBAL_PREFIX.into()))
734 .await
735 .is_some()
736 );
737
738 let test_keys = dbtx
740 .find_by_prefix(&DbPrefixTestPrefix)
741 .await
742 .collect::<Vec<_>>()
743 .await;
744 let test_keys_size = test_keys.len();
745 assert_eq!(test_keys_size, expected_test_keys_size);
746 for (key, val) in test_keys {
747 assert_eq!(key.0, val.0 + 1);
748 }
749}
750
751#[cfg(test)]
752#[tokio::test]
753async fn apply_migrations_rejects_newer_on_disk_version() {
754 let db = Database::new(MemDatabase::new(), ModuleDecoderRegistry::default());
755 let mut dbtx = db.begin_transaction().await;
756
757 create_database_version_dbtx(
759 &mut dbtx.to_ref_nc(),
760 DatabaseVersion(5),
761 None,
762 "test".to_owned(),
763 true,
764 )
765 .await;
766
767 let err = apply_migrations_dbtx(
769 &mut dbtx.to_ref_nc(),
770 (),
771 "test".to_owned(),
772 BTreeMap::new(),
773 None,
774 None,
775 )
776 .await
777 .expect_err("on-disk version 5 must not be accepted by code at version 0");
778
779 assert!(matches!(
780 err,
781 DbMigrationError::VersionTooHigh {
782 on_disk: DatabaseVersion(5),
783 target: DatabaseVersion(0),
784 ..
785 }
786 ));
787}
788
789#[allow(dead_code)]
790async fn migrate_test_db_version_0(
791 mut ctx: DbMigrationFnContext<'_, ()>,
792) -> Result<(), DbMigrationError> {
793 let mut dbtx = ctx.dbtx();
794 let example_keys_v0 = dbtx
795 .find_by_prefix(&DbPrefixTestPrefixV0)
796 .await
797 .collect::<Vec<_>>()
798 .await;
799 dbtx.remove_by_prefix(&DbPrefixTestPrefixV0).await;
800 for (key, val) in example_keys_v0 {
801 let key_v2 = TestKey(key.1);
802 dbtx.insert_new_entry(&key_v2, &val).await;
803 }
804 Ok(())
805}
806
807#[cfg(test)]
808#[tokio::test]
809async fn test_autocommit() {
810 use std::marker::PhantomData;
811 use std::ops::Range;
812 use std::path::Path;
813
814 use async_trait::async_trait;
815
816 use crate::ModuleDecoderRegistry;
817 use crate::db::{
818 AutocommitError, BaseDatabaseTransaction, DatabaseError, DatabaseResult,
819 IDatabaseTransaction, IDatabaseTransactionOps, IDatabaseTransactionOpsCore, IRawDatabase,
820 IRawDatabaseTransaction,
821 };
822
823 #[derive(Debug)]
824 struct FakeDatabase;
825
826 #[async_trait]
827 impl IRawDatabase for FakeDatabase {
828 type Transaction<'a> = FakeTransaction<'a>;
829 async fn begin_transaction(&self) -> FakeTransaction {
830 FakeTransaction(PhantomData)
831 }
832
833 fn checkpoint(&self, _backup_path: &Path) -> DatabaseResult<()> {
834 Ok(())
835 }
836 }
837
838 #[derive(Debug)]
839 struct FakeTransaction<'a>(PhantomData<&'a ()>);
840
841 #[async_trait]
842 impl IDatabaseTransactionOpsCore for FakeTransaction<'_> {
843 async fn raw_insert_bytes(
844 &mut self,
845 _key: &[u8],
846 _value: &[u8],
847 ) -> DatabaseResult<Option<Vec<u8>>> {
848 unimplemented!()
849 }
850
851 async fn raw_get_bytes(&mut self, _key: &[u8]) -> DatabaseResult<Option<Vec<u8>>> {
852 unimplemented!()
853 }
854
855 async fn raw_remove_entry(&mut self, _key: &[u8]) -> DatabaseResult<Option<Vec<u8>>> {
856 unimplemented!()
857 }
858
859 async fn raw_find_by_range(
860 &mut self,
861 _key_range: Range<&[u8]>,
862 ) -> DatabaseResult<crate::db::PrefixStream<'_>> {
863 unimplemented!()
864 }
865
866 async fn raw_find_by_prefix(
867 &mut self,
868 _key_prefix: &[u8],
869 ) -> DatabaseResult<crate::db::PrefixStream<'_>> {
870 unimplemented!()
871 }
872
873 async fn raw_remove_by_prefix(&mut self, _key_prefix: &[u8]) -> DatabaseResult<()> {
874 unimplemented!()
875 }
876
877 async fn raw_find_by_prefix_sorted_descending(
878 &mut self,
879 _key_prefix: &[u8],
880 ) -> DatabaseResult<crate::db::PrefixStream<'_>> {
881 unimplemented!()
882 }
883 }
884
885 impl IDatabaseTransactionOps for FakeTransaction<'_> {}
886
887 #[async_trait]
888 impl IRawDatabaseTransaction for FakeTransaction<'_> {
889 async fn commit_tx(self) -> DatabaseResult<()> {
890 use crate::db::DatabaseError;
891
892 Err(DatabaseError::backend(std::io::Error::other(
893 "Can't commit!",
894 )))
895 }
896 }
897
898 let db = Database::new(FakeDatabase, ModuleDecoderRegistry::default());
899 let err = db
900 .autocommit::<_, _, ()>(|_dbtx, _| Box::pin(async { Ok(()) }), Some(5))
901 .await
902 .unwrap_err();
903
904 match err {
905 AutocommitError::CommitFailed {
906 attempts: failed_attempts,
907 ..
908 } => {
909 assert_eq!(failed_attempts, 5);
910 }
911 AutocommitError::ClosureError { .. } => panic!("Closure did not return error"),
912 }
913}