linera_views/test_utils/
test_views.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Some [`View`][`crate::views::View`]s that are easy to use with test cases.
5
6use std::{
7    collections::{HashMap, HashSet},
8    fmt::Debug,
9};
10
11use crate::{
12    self as linera_views,
13    bucket_queue_view::BucketQueueView,
14    collection_view::CollectionView,
15    context::MemoryContext,
16    log_view::LogView,
17    map_view::MapView,
18    queue_view::QueueView,
19    register_view::RegisterView,
20    set_view::SetView,
21    views::{ClonableView, RootView},
22    ViewError,
23};
24
25/// A [`View`][`crate::views::View`] to be used in test cases.
26pub trait TestView: RootView<Context = MemoryContext<()>> + ClonableView {
27    /// Representation of the view's state.
28    type State: Debug + Eq + Send;
29
30    /// Performs some initial changes to the view, staging them, and returning a representation of
31    /// the view's state.
32    async fn stage_initial_changes(&mut self) -> Result<Self::State, ViewError>;
33
34    /// Stages some changes to the view that won't be persisted during the test.
35    ///
36    /// Assumes that the current view state is the initially staged changes. Returns the updated
37    /// state.
38    async fn stage_changes_to_be_discarded(&mut self) -> Result<Self::State, ViewError>;
39
40    /// Stages some changes to the view that will be persisted during the test.
41    ///
42    /// Assumes that the current view state is the initially staged changes. Returns the updated
43    /// state.
44    async fn stage_changes_to_be_persisted(&mut self) -> Result<Self::State, ViewError>;
45
46    /// Reads the view's current state.
47    async fn read(&self) -> Result<Self::State, ViewError>;
48}
49
50/// Wrapper to test with a [`RegisterView`].
51#[derive(RootView, ClonableView)]
52pub struct TestRegisterView<C> {
53    byte: RegisterView<C, u8>,
54}
55
56impl TestView for TestRegisterView<MemoryContext<()>> {
57    type State = u8;
58
59    async fn stage_initial_changes(&mut self) -> Result<Self::State, ViewError> {
60        let dummy_value = 82;
61        self.byte.set(dummy_value);
62        Ok(dummy_value)
63    }
64
65    async fn stage_changes_to_be_discarded(&mut self) -> Result<Self::State, ViewError> {
66        let dummy_value = 209;
67        self.byte.set(dummy_value);
68        Ok(dummy_value)
69    }
70
71    async fn stage_changes_to_be_persisted(&mut self) -> Result<Self::State, ViewError> {
72        let dummy_value = 15;
73        self.byte.set(dummy_value);
74        Ok(dummy_value)
75    }
76
77    async fn read(&self) -> Result<Self::State, ViewError> {
78        Ok(*self.byte.get())
79    }
80}
81
82const INITIAL_LOG_QUEUE_VIEW_CHANGES: &[u16] = &[1, 2, 3, 4, 5];
83
84/// Wrapper to test with a [`LogView`].
85#[derive(RootView, ClonableView)]
86pub struct TestLogView<C> {
87    log: LogView<C, u16>,
88}
89
90impl TestView for TestLogView<MemoryContext<()>> {
91    type State = Vec<u16>;
92
93    async fn stage_initial_changes(&mut self) -> Result<Self::State, ViewError> {
94        for value in INITIAL_LOG_QUEUE_VIEW_CHANGES {
95            self.log.push(*value);
96        }
97
98        Ok(INITIAL_LOG_QUEUE_VIEW_CHANGES.to_vec())
99    }
100
101    async fn stage_changes_to_be_discarded(&mut self) -> Result<Self::State, ViewError> {
102        let new_values = [10_000, 20_000, 30_000];
103
104        for value in new_values {
105            self.log.push(value);
106        }
107
108        Ok(INITIAL_LOG_QUEUE_VIEW_CHANGES
109            .iter()
110            .cloned()
111            .chain(new_values)
112            .collect())
113    }
114
115    async fn stage_changes_to_be_persisted(&mut self) -> Result<Self::State, ViewError> {
116        let new_values = [201, 1, 50_050];
117
118        for value in new_values {
119            self.log.push(value);
120        }
121
122        Ok(INITIAL_LOG_QUEUE_VIEW_CHANGES
123            .iter()
124            .cloned()
125            .chain(new_values)
126            .collect())
127    }
128
129    async fn read(&self) -> Result<Self::State, ViewError> {
130        self.log.read(..).await
131    }
132}
133
134const INITIAL_MAP_COLLECTION_VIEW_CHANGES: &[(i32, &str)] = &[
135    (0, "zero"),
136    (-1, "minus one"),
137    (2, "two"),
138    (-3, "minus three"),
139    (4, "four"),
140    (-5, "minus five"),
141];
142
143/// Wrapper to test with a [`MapView`].
144#[derive(RootView, ClonableView)]
145pub struct TestMapView<C> {
146    map: MapView<C, i32, String>,
147}
148
149impl TestView for TestMapView<MemoryContext<()>> {
150    type State = HashMap<i32, String>;
151
152    async fn stage_initial_changes(&mut self) -> Result<Self::State, ViewError> {
153        for (key, value) in INITIAL_MAP_COLLECTION_VIEW_CHANGES {
154            self.map.insert(key, value.to_string())?;
155        }
156
157        Ok(INITIAL_MAP_COLLECTION_VIEW_CHANGES
158            .iter()
159            .map(|(key, value)| (*key, value.to_string()))
160            .collect::<HashMap<_, _>>())
161    }
162
163    async fn stage_changes_to_be_discarded(&mut self) -> Result<Self::State, ViewError> {
164        let new_entries = [(-1_000_000, "foo"), (2_000_000, "bar")]
165            .into_iter()
166            .map(|(key, value)| (key, value.to_owned()));
167
168        let entries_to_remove = [0, -3];
169
170        for (key, value) in new_entries.clone() {
171            self.map.insert(&key, value)?;
172        }
173
174        for key in entries_to_remove {
175            self.map.remove(&key)?;
176        }
177
178        let new_state = INITIAL_MAP_COLLECTION_VIEW_CHANGES
179            .iter()
180            .filter(|(key, _)| !entries_to_remove.contains(key))
181            .map(|(key, value)| (*key, value.to_string()))
182            .chain(new_entries)
183            .collect();
184
185        Ok(new_state)
186    }
187
188    async fn stage_changes_to_be_persisted(&mut self) -> Result<Self::State, ViewError> {
189        let new_entries = [(1_234, "first new entry"), (-2_101_010, "second_new_entry")]
190            .into_iter()
191            .map(|(key, value)| (key, value.to_owned()));
192
193        let entries_to_remove = [-1, 2, 4];
194
195        for (key, value) in new_entries.clone() {
196            self.map.insert(&key, value)?;
197        }
198
199        for key in entries_to_remove {
200            self.map.remove(&key)?;
201        }
202
203        let new_state = INITIAL_MAP_COLLECTION_VIEW_CHANGES
204            .iter()
205            .filter(|(key, _)| !entries_to_remove.contains(key))
206            .map(|(key, value)| (*key, value.to_string()))
207            .chain(new_entries)
208            .collect();
209
210        Ok(new_state)
211    }
212
213    async fn read(&self) -> Result<Self::State, ViewError> {
214        let mut state = HashMap::new();
215        self.map
216            .for_each_index_value(|key, value| {
217                let value = value.into_owned();
218                state.insert(key, value);
219                Ok(())
220            })
221            .await?;
222        Ok(state)
223    }
224}
225
226/// Wrapper to test with a [`SetView`].
227#[derive(RootView, ClonableView)]
228pub struct TestSetView<C> {
229    set: SetView<C, i32>,
230}
231
232const INITIAL_SET_VIEW_CHANGES: &[i32] = &[0, -1, 2, -3, 4, -5];
233
234impl TestView for TestSetView<MemoryContext<()>> {
235    type State = HashSet<i32>;
236
237    async fn stage_initial_changes(&mut self) -> Result<Self::State, ViewError> {
238        for key in INITIAL_SET_VIEW_CHANGES {
239            self.set.insert(key)?;
240        }
241
242        Ok(INITIAL_SET_VIEW_CHANGES.iter().cloned().collect())
243    }
244
245    async fn stage_changes_to_be_discarded(&mut self) -> Result<Self::State, ViewError> {
246        let mut state = INITIAL_SET_VIEW_CHANGES
247            .iter()
248            .cloned()
249            .collect::<HashSet<_>>();
250        let new_entries = [-1_000_000, 2_000_000];
251
252        let entries_to_remove = [0, -3];
253
254        for key in new_entries {
255            self.set.insert(&key)?;
256            state.insert(key);
257        }
258
259        for key in entries_to_remove {
260            self.set.remove(&key)?;
261            state.remove(&key);
262        }
263
264        Ok(state)
265    }
266
267    async fn stage_changes_to_be_persisted(&mut self) -> Result<Self::State, ViewError> {
268        let mut state = INITIAL_SET_VIEW_CHANGES
269            .iter()
270            .cloned()
271            .collect::<HashSet<_>>();
272        let new_entries = [1_234, -2_101_010];
273
274        let entries_to_remove = [-1, 2, 4];
275
276        for key in new_entries {
277            self.set.insert(&key)?;
278            state.insert(key);
279        }
280
281        for key in entries_to_remove {
282            self.set.remove(&key)?;
283            state.remove(&key);
284        }
285
286        Ok(state)
287    }
288
289    async fn read(&self) -> Result<Self::State, ViewError> {
290        let indices = self.set.indices().await?;
291        Ok(indices.into_iter().collect())
292    }
293}
294
295/// Wrapper to test with a [`CollectionView`].
296#[derive(RootView, ClonableView)]
297pub struct TestCollectionView<C> {
298    collection: CollectionView<C, i32, RegisterView<C, String>>,
299}
300
301impl TestView for TestCollectionView<MemoryContext<()>> {
302    type State = HashMap<i32, String>;
303
304    async fn stage_initial_changes(&mut self) -> Result<Self::State, ViewError> {
305        for (key, value) in INITIAL_MAP_COLLECTION_VIEW_CHANGES {
306            self.collection
307                .load_entry_mut(key)
308                .await?
309                .set(value.to_string());
310        }
311
312        Ok(INITIAL_MAP_COLLECTION_VIEW_CHANGES
313            .iter()
314            .map(|(key, value)| (*key, value.to_string()))
315            .collect::<HashMap<_, _>>())
316    }
317
318    async fn stage_changes_to_be_discarded(&mut self) -> Result<Self::State, ViewError> {
319        let new_entries = [(-1_000_000, "foo"), (2_000_000, "bar")]
320            .into_iter()
321            .map(|(key, value)| (key, value.to_owned()));
322
323        let entries_to_remove = [0, -3];
324
325        for (key, value) in new_entries.clone() {
326            self.collection.load_entry_mut(&key).await?.set(value);
327        }
328
329        for key in entries_to_remove {
330            self.collection.remove_entry(&key)?;
331        }
332
333        let new_state = INITIAL_MAP_COLLECTION_VIEW_CHANGES
334            .iter()
335            .filter(|(key, _)| !entries_to_remove.contains(key))
336            .map(|(key, value)| (*key, value.to_string()))
337            .chain(new_entries)
338            .collect();
339
340        Ok(new_state)
341    }
342
343    async fn stage_changes_to_be_persisted(&mut self) -> Result<Self::State, ViewError> {
344        let new_entries = [(1_234, "first new entry"), (-2_101_010, "second_new_entry")]
345            .into_iter()
346            .map(|(key, value)| (key, value.to_owned()));
347
348        let entries_to_remove = [-1, 2, 4];
349
350        for (key, value) in new_entries.clone() {
351            self.collection.load_entry_mut(&key).await?.set(value);
352        }
353
354        for key in entries_to_remove {
355            self.collection.remove_entry(&key)?;
356        }
357
358        let new_state = INITIAL_MAP_COLLECTION_VIEW_CHANGES
359            .iter()
360            .filter(|(key, _)| !entries_to_remove.contains(key))
361            .map(|(key, value)| (*key, value.to_string()))
362            .chain(new_entries)
363            .collect();
364
365        Ok(new_state)
366    }
367
368    async fn read(&self) -> Result<Self::State, ViewError> {
369        let indices = self.collection.indices().await?;
370        let mut state = HashMap::with_capacity(indices.len());
371
372        for index in indices {
373            if let Some(value) = self.collection.try_load_entry(&index).await? {
374                state.insert(index, value.get().clone());
375            }
376        }
377
378        Ok(state)
379    }
380}
381
382/// Wrapper to test with a [`QueueView`].
383#[derive(RootView, ClonableView)]
384pub struct TestQueueView<C> {
385    queue: QueueView<C, u16>,
386}
387
388impl TestView for TestQueueView<MemoryContext<()>> {
389    type State = Vec<u16>;
390
391    async fn stage_initial_changes(&mut self) -> Result<Self::State, ViewError> {
392        for value in INITIAL_LOG_QUEUE_VIEW_CHANGES {
393            self.queue.push_back(*value);
394        }
395
396        Ok(INITIAL_LOG_QUEUE_VIEW_CHANGES.to_vec())
397    }
398
399    async fn stage_changes_to_be_discarded(&mut self) -> Result<Self::State, ViewError> {
400        let mut initial_state = INITIAL_LOG_QUEUE_VIEW_CHANGES.to_vec();
401        let new_values = [10_000, 20_000, 30_000];
402
403        for value in new_values {
404            self.queue.push_back(value);
405            initial_state.push(value);
406        }
407        self.queue.delete_front();
408        initial_state.remove(0);
409        self.queue.delete_front();
410        initial_state.remove(0);
411
412        Ok(initial_state)
413    }
414
415    async fn stage_changes_to_be_persisted(&mut self) -> Result<Self::State, ViewError> {
416        let mut initial_state = INITIAL_LOG_QUEUE_VIEW_CHANGES.to_vec();
417        let new_values = [201, 1, 50_050, 203];
418
419        for value in new_values {
420            self.queue.push_back(value);
421            initial_state.push(value);
422        }
423        self.queue.delete_front();
424        initial_state.remove(0);
425
426        Ok(initial_state)
427    }
428
429    async fn read(&self) -> Result<Self::State, ViewError> {
430        self.queue.elements().await
431    }
432}
433
434/// Wrapper to test with a [`BucketQueueView`].
435#[derive(RootView, ClonableView)]
436pub struct TestBucketQueueView<C> {
437    queue: BucketQueueView<C, u16, 2>,
438}
439
440impl TestView for TestBucketQueueView<MemoryContext<()>> {
441    type State = Vec<u16>;
442
443    async fn stage_initial_changes(&mut self) -> Result<Self::State, ViewError> {
444        for value in INITIAL_LOG_QUEUE_VIEW_CHANGES {
445            self.queue.push_back(*value);
446        }
447
448        Ok(INITIAL_LOG_QUEUE_VIEW_CHANGES.to_vec())
449    }
450
451    async fn stage_changes_to_be_discarded(&mut self) -> Result<Self::State, ViewError> {
452        let mut initial_state = INITIAL_LOG_QUEUE_VIEW_CHANGES.to_vec();
453        let new_values = [10_000, 20_000, 30_000];
454
455        for value in new_values {
456            self.queue.push_back(value);
457            initial_state.push(value);
458        }
459        self.queue.delete_front().await?;
460        initial_state.remove(0);
461        self.queue.delete_front().await?;
462        initial_state.remove(0);
463
464        Ok(initial_state)
465    }
466
467    async fn stage_changes_to_be_persisted(&mut self) -> Result<Self::State, ViewError> {
468        let mut initial_state = INITIAL_LOG_QUEUE_VIEW_CHANGES.to_vec();
469        let new_values = [201, 1, 50_050, 203];
470
471        for value in new_values {
472            self.queue.push_back(value);
473            initial_state.push(value);
474        }
475        self.queue.delete_front().await?;
476        initial_state.remove(0);
477
478        Ok(initial_state)
479    }
480
481    async fn read(&self) -> Result<Self::State, ViewError> {
482        self.queue.elements().await
483    }
484}