|
18 | 18 |
|
19 | 19 | #[cfg(test)] |
20 | 20 | mod tests { |
21 | | - use crate::rvm::program::Program; |
22 | 21 | use crate::rvm::tests::instruction_parser::{parse_instruction, parse_loop_mode}; |
23 | 22 | use crate::rvm::tests::test_utils::test_round_trip_serialization; |
24 | | - #[cfg(any(test, not(feature = "std")))] |
25 | | - use crate::utils::limits::set_time_source; |
26 | | - use crate::utils::limits::{ |
27 | | - acquire_limits_test_lock, fallback_execution_timer_config, |
28 | | - set_fallback_execution_timer_config, ExecutionTimerConfig, TimeSource, |
29 | | - }; |
| 23 | + use crate::utils::limits::ExecutionTimerConfig; |
30 | 24 | use core::num::NonZeroU32; |
31 | 25 | use core::time::Duration; |
32 | 26 | #[derive(Debug, Clone, Deserialize, Serialize, Default)] |
@@ -57,122 +51,11 @@ mod tests { |
57 | 51 | use anyhow::Result; |
58 | 52 | use serde::{Deserialize, Serialize}; |
59 | 53 | use std::fs; |
60 | | - use std::sync::{Mutex, Once}; |
61 | 54 | use test_generator::test_resources; |
62 | 55 |
|
63 | 56 | extern crate alloc; |
64 | 57 | extern crate std; |
65 | 58 |
|
66 | | - struct FallbackGuard(Option<ExecutionTimerConfig>); |
67 | | - impl Drop for FallbackGuard { |
68 | | - fn drop(&mut self) { |
69 | | - set_fallback_execution_timer_config(self.0); |
70 | | - } |
71 | | - } |
72 | | - |
73 | | - fn install_fallback_config(config: Option<ExecutionTimerConfig>) -> FallbackGuard { |
74 | | - let previous = fallback_execution_timer_config(); |
75 | | - set_fallback_execution_timer_config(config); |
76 | | - FallbackGuard(previous) |
77 | | - } |
78 | | - |
79 | | - struct TimeSourceGuard { |
80 | | - previous_default: Duration, |
81 | | - previous_template: Vec<Duration>, |
82 | | - } |
83 | | - |
84 | | - impl Drop for TimeSourceGuard { |
85 | | - fn drop(&mut self) { |
86 | | - let mut state = TIME_SOURCE_STATE |
87 | | - .lock() |
88 | | - .unwrap_or_else(|poisoned| poisoned.into_inner()); |
89 | | - state.default_increment = self.previous_default; |
90 | | - state.template_increments = self.previous_template.clone(); |
91 | | - state.reset_from_template(); |
92 | | - } |
93 | | - } |
94 | | - |
95 | | - fn configure_time_source( |
96 | | - increments: Vec<Duration>, |
97 | | - default_increment: Duration, |
98 | | - ) -> TimeSourceGuard { |
99 | | - ensure_time_source_registered(); |
100 | | - |
101 | | - let mut state = TIME_SOURCE_STATE |
102 | | - .lock() |
103 | | - .unwrap_or_else(|poisoned| poisoned.into_inner()); |
104 | | - |
105 | | - let guard = TimeSourceGuard { |
106 | | - previous_default: state.default_increment, |
107 | | - previous_template: state.template_increments.clone(), |
108 | | - }; |
109 | | - |
110 | | - state.default_increment = default_increment; |
111 | | - state.template_increments = increments; |
112 | | - state.reset_from_template(); |
113 | | - |
114 | | - guard |
115 | | - } |
116 | | - |
117 | | - struct TestTimeSource; |
118 | | - |
119 | | - struct TimeSourceState { |
120 | | - current: Duration, |
121 | | - started: bool, |
122 | | - default_increment: Duration, |
123 | | - increments: VecDeque<Duration>, |
124 | | - template_increments: Vec<Duration>, |
125 | | - } |
126 | | - |
127 | | - impl TimeSourceState { |
128 | | - const fn new() -> Self { |
129 | | - Self { |
130 | | - current: Duration::ZERO, |
131 | | - started: false, |
132 | | - default_increment: Duration::from_millis(1), |
133 | | - increments: VecDeque::new(), |
134 | | - template_increments: Vec::new(), |
135 | | - } |
136 | | - } |
137 | | - |
138 | | - fn reset_from_template(&mut self) { |
139 | | - self.current = Duration::ZERO; |
140 | | - self.started = false; |
141 | | - self.increments = VecDeque::from(self.template_increments.clone()); |
142 | | - } |
143 | | - } |
144 | | - |
145 | | - impl TimeSource for TestTimeSource { |
146 | | - fn now(&self) -> Option<Duration> { |
147 | | - let mut state = TIME_SOURCE_STATE |
148 | | - .lock() |
149 | | - .unwrap_or_else(|poisoned| poisoned.into_inner()); |
150 | | - |
151 | | - if !state.started { |
152 | | - state.started = true; |
153 | | - return Some(state.current); |
154 | | - } |
155 | | - |
156 | | - let increment = state |
157 | | - .increments |
158 | | - .pop_front() |
159 | | - .unwrap_or(state.default_increment); |
160 | | - state.current = state.current.saturating_add(increment); |
161 | | - Some(state.current) |
162 | | - } |
163 | | - } |
164 | | - |
165 | | - static TEST_TIME_SOURCE: TestTimeSource = TestTimeSource; |
166 | | - static TIME_SOURCE_STATE: Mutex<TimeSourceState> = Mutex::new(TimeSourceState::new()); |
167 | | - static TIME_SOURCE_ONCE: Once = Once::new(); |
168 | | - |
169 | | - fn ensure_time_source_registered() { |
170 | | - #[cfg(any(test, not(feature = "std")))] |
171 | | - TIME_SOURCE_ONCE.call_once(|| { |
172 | | - let _ = set_time_source(&TEST_TIME_SOURCE); |
173 | | - }); |
174 | | - } |
175 | | - |
176 | 59 | #[derive(Debug, Clone, Deserialize, Serialize)] |
177 | 60 | struct HostAwaitResponseSpec { |
178 | 61 | id: crate::Value, |
@@ -1129,158 +1012,6 @@ mod tests { |
1129 | 1012 | Ok(()) |
1130 | 1013 | } |
1131 | 1014 |
|
1132 | | - #[test] |
1133 | | - fn vm_execution_time_limit_triggers_error() -> Result<()> { |
1134 | | - use crate::rvm::instructions::Instruction; |
1135 | | - use crate::utils::limits::acquire_limits_test_lock; |
1136 | | - use core::num::NonZeroU32; |
1137 | | - use core::time::Duration; |
1138 | | - |
1139 | | - let _lock = acquire_limits_test_lock(); |
1140 | | - let config = ExecutionTimerConfig { |
1141 | | - limit: Duration::from_nanos(1), |
1142 | | - check_interval: NonZeroU32::new(1).unwrap(), |
1143 | | - }; |
1144 | | - let _guard = install_fallback_config(Some(config)); |
1145 | | - |
1146 | | - let mut program = Program::new(); |
1147 | | - program.dispatch_window_size = 2; |
1148 | | - program.max_rule_window_size = 2; |
1149 | | - program.entry_points.insert("main".to_string(), 0); |
1150 | | - |
1151 | | - const INSTRUCTION_COUNT: usize = 60_000; |
1152 | | - program.instructions = (0..INSTRUCTION_COUNT) |
1153 | | - .map(|_| Instruction::LoadNull { dest: 0 }) |
1154 | | - .collect(); |
1155 | | - program.instructions.push(Instruction::Return { value: 0 }); |
1156 | | - program.instruction_spans = alloc::vec![None; program.instructions.len()]; |
1157 | | - program.main_entry_point = 0; |
1158 | | - |
1159 | | - let program = Arc::new(program); |
1160 | | - |
1161 | | - let mut vm = RegoVM::new(); |
1162 | | - vm.set_max_instructions(usize::MAX); |
1163 | | - vm.load_program(program); |
1164 | | - |
1165 | | - let result = vm.execute(); |
1166 | | - assert!( |
1167 | | - matches!(result, Err(VmError::TimeLimitExceeded { .. })), |
1168 | | - "expected time limit error but got {result:?}" |
1169 | | - ); |
1170 | | - |
1171 | | - Ok(()) |
1172 | | - } |
1173 | | - |
1174 | | - #[test] |
1175 | | - fn vm_execution_time_limit_override_allows_completion() -> Result<()> { |
1176 | | - use crate::rvm::instructions::Instruction; |
1177 | | - use crate::utils::limits::acquire_limits_test_lock; |
1178 | | - use core::num::NonZeroU32; |
1179 | | - use core::time::Duration; |
1180 | | - |
1181 | | - let _lock = acquire_limits_test_lock(); |
1182 | | - let strict_config = ExecutionTimerConfig { |
1183 | | - limit: Duration::from_nanos(1), |
1184 | | - check_interval: NonZeroU32::new(1).unwrap(), |
1185 | | - }; |
1186 | | - let _guard = install_fallback_config(Some(strict_config)); |
1187 | | - |
1188 | | - let mut program = Program::new(); |
1189 | | - program.dispatch_window_size = 2; |
1190 | | - program.max_rule_window_size = 2; |
1191 | | - program.entry_points.insert("main".to_string(), 0); |
1192 | | - program.instructions = alloc::vec![ |
1193 | | - Instruction::LoadNull { dest: 0 }, |
1194 | | - Instruction::Return { value: 0 }, |
1195 | | - ]; |
1196 | | - program.instruction_spans = alloc::vec![None; program.instructions.len()]; |
1197 | | - program.main_entry_point = 0; |
1198 | | - |
1199 | | - let program = Arc::new(program); |
1200 | | - |
1201 | | - let mut vm = RegoVM::new(); |
1202 | | - vm.load_program(program); |
1203 | | - |
1204 | | - let relaxed_config = ExecutionTimerConfig { |
1205 | | - limit: Duration::from_millis(10), |
1206 | | - check_interval: NonZeroU32::new(1).unwrap(), |
1207 | | - }; |
1208 | | - vm.set_execution_timer_config(Some(relaxed_config)); |
1209 | | - |
1210 | | - let result = vm.execute(); |
1211 | | - assert!( |
1212 | | - result.is_ok(), |
1213 | | - "expected successful execution, got {result:?}" |
1214 | | - ); |
1215 | | - |
1216 | | - Ok(()) |
1217 | | - } |
1218 | | - |
1219 | | - #[test] |
1220 | | - fn vm_suspend_resume_excludes_suspended_time_from_limit() -> Result<()> { |
1221 | | - use crate::rvm::instructions::Instruction; |
1222 | | - |
1223 | | - let _lock = acquire_limits_test_lock(); |
1224 | | - let _guard = install_fallback_config(Some(ExecutionTimerConfig { |
1225 | | - limit: Duration::from_millis(10), |
1226 | | - check_interval: NonZeroU32::new(1).unwrap(), |
1227 | | - })); |
1228 | | - |
1229 | | - let _time_guard = configure_time_source( |
1230 | | - alloc::vec![ |
1231 | | - Duration::from_millis(1), |
1232 | | - Duration::from_millis(1), |
1233 | | - Duration::from_millis(1), |
1234 | | - Duration::from_millis(1), |
1235 | | - Duration::from_millis(100), |
1236 | | - Duration::from_millis(1), |
1237 | | - ], |
1238 | | - Duration::from_millis(1), |
1239 | | - ); |
1240 | | - |
1241 | | - let mut program = Program::new(); |
1242 | | - program.dispatch_window_size = 3; |
1243 | | - program.max_rule_window_size = 3; |
1244 | | - program.entry_points.insert("main".to_string(), 0); |
1245 | | - program.literals = alloc::vec![Value::from("id"), Value::from(1)]; |
1246 | | - program.instructions = alloc::vec![ |
1247 | | - Instruction::Load { |
1248 | | - dest: 0, |
1249 | | - literal_idx: 0 |
1250 | | - }, |
1251 | | - Instruction::Load { |
1252 | | - dest: 1, |
1253 | | - literal_idx: 1 |
1254 | | - }, |
1255 | | - Instruction::HostAwait { |
1256 | | - dest: 2, |
1257 | | - arg: 1, |
1258 | | - id: 0 |
1259 | | - }, |
1260 | | - Instruction::Return { value: 2 }, |
1261 | | - ]; |
1262 | | - program.instruction_spans = alloc::vec![None; program.instructions.len()]; |
1263 | | - program.main_entry_point = 0; |
1264 | | - |
1265 | | - let program = Arc::new(program); |
1266 | | - let mut vm = RegoVM::new(); |
1267 | | - vm.set_execution_mode(ExecutionMode::Suspendable); |
1268 | | - vm.load_program(program); |
1269 | | - |
1270 | | - let _ = vm.execute()?; |
1271 | | - match vm.execution_state() { |
1272 | | - ExecutionState::Suspended { reason, .. } => { |
1273 | | - assert!(matches!(reason, SuspendReason::HostAwait { .. })); |
1274 | | - } |
1275 | | - other => panic!("expected suspension, got {other:?}"), |
1276 | | - } |
1277 | | - |
1278 | | - let resumed = vm.resume(Some(Value::from(42)))?; |
1279 | | - assert_eq!(resumed, Value::from(42)); |
1280 | | - |
1281 | | - Ok(()) |
1282 | | - } |
1283 | | - |
1284 | 1015 | #[test_resources("tests/rvm/vm/suites/*.yaml")] |
1285 | 1016 | fn run_vm_test_file(file: &str) { |
1286 | 1017 | run_vm_test_suite(file).unwrap() |
|
0 commit comments