reifydb_flow_operator_sdk/testing/
context.rs1use std::{
5 collections::HashMap,
6 sync::{Arc, Mutex},
7};
8
9use reifydb_core::{
10 CommitVersion,
11 value::encoded::{EncodedKey, EncodedValues},
12};
13
14use crate::OperatorContext;
15
16#[derive(Clone)]
18pub struct TestContext {
19 state_store: Arc<Mutex<HashMap<EncodedKey, EncodedValues>>>,
20 version: CommitVersion,
21 logs: Arc<Mutex<Vec<String>>>,
22}
23
24impl TestContext {
25 pub fn new(version: CommitVersion) -> Self {
27 Self {
28 state_store: Arc::new(Mutex::new(HashMap::new())),
29 version,
30 logs: Arc::new(Mutex::new(Vec::new())),
31 }
32 }
33
34 pub fn default() -> Self {
36 Self::new(CommitVersion(1))
37 }
38
39 pub fn state_store(&self) -> &Arc<Mutex<HashMap<EncodedKey, EncodedValues>>> {
41 &self.state_store
42 }
43
44 pub fn logs(&self) -> Vec<String> {
46 self.logs.lock().unwrap().clone()
47 }
48
49 pub fn clear_logs(&self) {
51 self.logs.lock().unwrap().clear();
52 }
53
54 pub fn version(&self) -> CommitVersion {
56 self.version
57 }
58
59 pub fn set_version(&mut self, version: CommitVersion) {
61 self.version = version;
62 }
63
64 pub fn get_state(&self, key: &EncodedKey) -> Option<Vec<u8>> {
66 self.state_store.lock().unwrap().get(key).map(|v| v.0.to_vec())
67 }
68
69 pub fn set_state(&self, key: EncodedKey, value: Vec<u8>) {
71 use reifydb_core::CowVec;
72 self.state_store.lock().unwrap().insert(key, EncodedValues(CowVec::new(value)));
73 }
74
75 pub fn remove_state(&self, key: &EncodedKey) -> Option<Vec<u8>> {
77 self.state_store.lock().unwrap().remove(key).map(|v| v.0.to_vec())
78 }
79
80 pub fn has_state(&self, key: &EncodedKey) -> bool {
82 self.state_store.lock().unwrap().contains_key(key)
83 }
84
85 pub fn state_count(&self) -> usize {
87 self.state_store.lock().unwrap().len()
88 }
89
90 pub fn clear_state(&self) {
92 self.state_store.lock().unwrap().clear();
93 }
94
95 pub fn state_keys(&self) -> Vec<EncodedKey> {
97 self.state_store.lock().unwrap().keys().cloned().collect()
98 }
99
100 pub fn as_operator_context(&self) -> OperatorContext {
117 todo!("Implement test OperatorContext creation - requires FFI callback bridging")
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124 use crate::testing::helpers::encode_key;
125
126 #[test]
127 fn test_context_state_operations() {
128 let ctx = TestContext::default();
129 let key = encode_key("test_key");
130 let value = vec![1, 2, 3];
131
132 ctx.set_state(key.clone(), value.clone());
134 assert_eq!(ctx.get_state(&key), Some(value.clone()));
135 assert!(ctx.has_state(&key));
136
137 let removed = ctx.remove_state(&key);
139 assert_eq!(removed, Some(value));
140 assert!(!ctx.has_state(&key));
141 assert_eq!(ctx.get_state(&key), None);
142 }
143
144 #[test]
145 fn test_context_logs() {
146 let ctx = TestContext::default();
147
148 ctx.logs.lock().unwrap().push("Log 1".to_string());
150 ctx.logs.lock().unwrap().push("Log 2".to_string());
151
152 let logs = ctx.logs();
153 assert_eq!(logs.len(), 2);
154 assert_eq!(logs[0], "Log 1");
155 assert_eq!(logs[1], "Log 2");
156
157 ctx.clear_logs();
158 assert_eq!(ctx.logs().len(), 0);
159 }
160
161 #[test]
162 fn test_context_state_inspection() {
163 let ctx = TestContext::default();
164
165 ctx.set_state(encode_key("key1"), vec![1]);
166 ctx.set_state(encode_key("key2"), vec![2]);
167 ctx.set_state(encode_key("key3"), vec![3]);
168
169 assert_eq!(ctx.state_count(), 3);
170
171 let keys = ctx.state_keys();
172 assert_eq!(keys.len(), 3);
173
174 ctx.clear_state();
175 assert_eq!(ctx.state_count(), 0);
176 }
177}