capsules_extra/test/
kv_system.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Test for Tock KV System capsules.
6//!
7//! This capsule implements the tests for KV system libraries in Tock.
8//! This is originally written to test TicKV.
9//!
10//!    hil::flash
11//!
12//! The tests can be enabled by adding this line to the `main()`
13//!
14//! ```rust,ignore
15//! tickv_test::run_tickv_tests(kvstore)
16//! ```
17//!
18//! You should then see the following output
19//!
20//! ```text
21//! ---Starting TicKV Tests---
22//! Key: [18, 52, 86, 120, 154, 188, 222, 240] with value [16, 32, 48] was added
23//! Now retrieving the key
24//! Key: [18, 52, 86, 120, 154, 188, 222, 240] with value [16, 32, 48, 0] was retrieved
25//! Removed Key: [18, 52, 86, 120, 154, 188, 222, 240]
26//! Try to read removed key: [18, 52, 86, 120, 154, 188, 222, 240]
27//! Unable to find key: [18, 52, 86, 120, 154, 188, 222, 240]
28//! Let's start a garbage collection
29//! Finished garbage collection
30//! ---Finished TicKV Tests---
31//! ```
32
33use crate::tickv::{KVSystem, KVSystemClient, KeyType};
34use core::cell::Cell;
35use core::marker::PhantomData;
36use kernel::debug;
37use kernel::utilities::cells::{MapCell, TakeCell};
38use kernel::utilities::leasable_buffer::SubSliceMut;
39use kernel::ErrorCode;
40
41#[derive(Clone, Copy, PartialEq)]
42enum CurrentState {
43    Normal,
44    ExpectGetValueFail,
45}
46
47pub struct KVSystemTest<'a, S: KVSystem<'static>, T: KeyType> {
48    kv_system: &'a S,
49    phantom: PhantomData<&'a T>,
50    value: MapCell<SubSliceMut<'static, u8>>,
51    ret_buffer: TakeCell<'static, [u8]>,
52    state: Cell<CurrentState>,
53}
54
55impl<'a, S: KVSystem<'static>, T: KeyType> KVSystemTest<'a, S, T> {
56    pub fn new(
57        kv_system: &'a S,
58        value: SubSliceMut<'static, u8>,
59        static_buf: &'static mut [u8; 4],
60    ) -> KVSystemTest<'a, S, T> {
61        debug!("---Starting TicKV Tests---");
62
63        Self {
64            kv_system,
65            phantom: PhantomData,
66            value: MapCell::new(value),
67            ret_buffer: TakeCell::new(static_buf),
68            state: Cell::new(CurrentState::Normal),
69        }
70    }
71}
72
73impl<S: KVSystem<'static, K = T>, T: KeyType + core::fmt::Debug> KVSystemClient<T>
74    for KVSystemTest<'_, S, T>
75{
76    fn generate_key_complete(
77        &self,
78        result: Result<(), ErrorCode>,
79        _unhashed_key: SubSliceMut<'static, u8>,
80        key_buf: &'static mut T,
81    ) {
82        match result {
83            Ok(()) => {
84                debug!("Generated key: {:?}", key_buf);
85                debug!("Now appending the key");
86                self.kv_system
87                    .append_key(key_buf, self.value.take().unwrap())
88                    .unwrap();
89            }
90            Err(e) => {
91                panic!("Error adding key: {:?}", e);
92            }
93        }
94    }
95
96    fn append_key_complete(
97        &self,
98        result: Result<(), ErrorCode>,
99        key: &'static mut T,
100        value: SubSliceMut<'static, u8>,
101    ) {
102        match result {
103            Ok(()) => {
104                debug!("Key: {:?} with value {:?} was added", key, value);
105                debug!("Now retrieving the key");
106                self.kv_system
107                    .get_value(key, SubSliceMut::new(self.ret_buffer.take().unwrap()))
108                    .unwrap();
109            }
110            Err(e) => {
111                panic!("Error adding key: {:?}", e);
112            }
113        }
114    }
115
116    fn get_value_complete(
117        &self,
118        result: Result<(), ErrorCode>,
119        key: &'static mut T,
120        ret_buf: SubSliceMut<'static, u8>,
121    ) {
122        match result {
123            Ok(()) => {
124                debug!("Key: {:?} with value {:?} was retrieved", key, ret_buf);
125                self.ret_buffer.replace(ret_buf.take());
126                self.kv_system.invalidate_key(key).unwrap();
127            }
128            Err(e) => {
129                if self.state.get() == CurrentState::ExpectGetValueFail {
130                    // We expected this failure
131                    debug!("Unable to find key: {:?}", key);
132                    self.state.set(CurrentState::Normal);
133
134                    debug!("Let's start a garbage collection");
135                    self.kv_system.garbage_collect().unwrap();
136                } else {
137                    panic!("Error finding key: {:?}", e);
138                }
139            }
140        }
141    }
142
143    fn invalidate_key_complete(&self, result: Result<(), ErrorCode>, key: &'static mut T) {
144        match result {
145            Ok(()) => {
146                debug!("Removed Key: {:?}", key);
147
148                debug!("Try to read removed key: {:?}", key);
149                self.state.set(CurrentState::ExpectGetValueFail);
150                self.kv_system
151                    .get_value(key, SubSliceMut::new(self.ret_buffer.take().unwrap()))
152                    .unwrap();
153            }
154            Err(e) => {
155                panic!("Error invalidating key: {:?}", e);
156            }
157        }
158    }
159
160    fn garbage_collect_complete(&self, result: Result<(), ErrorCode>) {
161        match result {
162            Ok(()) => {
163                debug!("Finished garbage collection");
164                debug!("---Finished TicKV Tests---");
165            }
166            Err(e) => {
167                panic!("Error running garbage collection: {:?}", e);
168            }
169        }
170    }
171}