coven_database/
database_operations_tests.rs1use super::Database;
4use crate::DbError;
5
6impl Database {
7 pub async fn test_track_work(
10 &self,
11 counter: crate::test_utils::WorkCounter,
12 ) -> Result<(), DbError> {
13 self.call(move |inner| {
14 inner.access.with_writer(|writer| {
15 writer.test_track_work(counter.clone());
16 Ok::<_, DbError>(())
17 })?;
18 inner.access.readers.test_track_work(&counter);
19 inner.inputs.test_track_work(&counter);
20 Ok(())
21 })
22 .await
23 }
24
25 pub async fn test_snapshot_section_bytes(
28 &self,
29 id: coven_format::admin::SnapshotId,
30 ) -> Result<
31 [u64; coven_format::snapshot::SECTIONS],
32 crate::SnapshotWriteError<std::convert::Infallible>,
33 > {
34 let sections =
35 std::sync::Arc::new(std::sync::Mutex::new([0; coven_format::snapshot::SECTIONS]));
36 let counted = sections.clone();
37 self.write_snapshot(
38 id,
39 |_| Ok(()),
40 move |frame| {
41 if let Some(section) = coven_format::snapshot::frame_section(&frame) {
42 counted.lock().expect("no test panics counting")[section] += frame.len() as u64;
43 }
44 Ok(())
45 },
46 )
47 .await?;
48 let bytes = *sections.lock().expect("no test panics counting");
49 Ok(bytes)
50 }
51
52 pub async fn test_on_write_checkpoint(
56 &self,
57 callback: impl Fn(crate::test_utils::WriteCheckpoint) + Send + 'static,
58 ) -> Result<(), DbError> {
59 self.call(move |inner| {
60 inner.access.with_writer(|writer| {
61 writer.on_write_checkpoint(callback);
62 Ok(())
63 })
64 })
65 .await
66 }
67
68 pub async fn test_panic_in_next_write(&self, message: &'static str) -> Result<(), DbError> {
72 let armed = std::sync::atomic::AtomicBool::new(true);
73 self.test_on_write_checkpoint(move |point| {
74 if point == crate::test_utils::WriteCheckpoint::Judged
75 && armed.swap(false, std::sync::atomic::Ordering::SeqCst)
76 {
77 panic!("{message}");
78 }
79 })
80 .await
81 }
82
83 pub async fn test_fail_sync_status(&self) -> Result<(), DbError> {
87 self.call(move |inner| {
88 inner.access.with_writer(|writer| {
89 writer.batch(
90 "CREATE TEMP TRIGGER fail_sync_status
91 BEFORE UPDATE OF last_pass,moving,last_synced ON coven_sync_status
92 BEGIN SELECT RAISE(ABORT,'injected sync status failure'); END;",
93 )
94 })
95 })
96 .await
97 }
98
99 pub async fn test_fail_device_reset(&self) -> Result<(), DbError> {
101 self.call(move |inner| {
102 inner.access.with_writer(|writer| {
103 writer.batch(
104 "CREATE TEMP TRIGGER fail_device_reset BEFORE INSERT ON _coven_device_reset
105 BEGIN SELECT RAISE(ABORT,'injected reset notice failure'); END;",
106 )
107 })
108 })
109 .await
110 }
111
112 pub async fn test_fail_retry_effect(&self) -> Result<(), DbError> {
114 self.call(move |inner| {
115 inner.access.with_writer(|writer| {
116 writer.batch(
117 "CREATE TEMP TRIGGER fail_retry_effect BEFORE UPDATE ON coven_retry_effect
118 BEGIN SELECT RAISE(ABORT,'injected retry effect failure'); END;",
119 )
120 })
121 })
122 .await
123 }
124
125 pub async fn test_queued_writes(
127 &self,
128 ) -> Result<Vec<coven_format::write::WriteRecord>, DbError> {
129 self.call(move |inner| {
130 inner.access.with_writer(|writer| {
131 writer
132 .query("SELECT record FROM _coven_uploads ORDER BY device,number", [], |r| {
133 r.get::<_, Vec<u8>>(0)
134 })?
135 .iter()
136 .map(|bytes| {
137 coven_format::write_stream::decode_plaintext(bytes).map_err(Into::into)
138 })
139 .collect()
140 })
141 })
142 .await
143 }
144}
145
146#[cfg(test)]
149pub(crate) fn fill_for_plans(db: &rusqlite::Connection) {
150 db.execute_batch(
151 "INSERT INTO _coven_gone_storage_cleared SELECT n FROM fixture;
152 INSERT INTO _coven_requests_ended SELECT n FROM fixture;",
153 )
154 .unwrap();
155}