1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
//! Property-based tests for runtime initialization
//!
//! **Property 2: Runtime initialization within 100ms**
//! *For any* valid RuntimeConfig, the runtime should initialize and be ready to accept tasks within 100ms.
//! **Validates: Requirements 2.2**
#[cfg(test)]
mod tests {
use proptest::prelude::*;
use std::time::Duration;
use crate::runtime::{RuntimeConfig, RuntimeManager};
/// Strategy for generating valid RuntimeConfig values
fn runtime_config_strategy() -> impl Strategy<Value = RuntimeConfig> {
(1usize..=16, 1usize..=1024, 1usize..=8388608)
.prop_map(|(workers, blocking, stack)| RuntimeConfig {
worker_threads: workers,
max_blocking_threads: blocking,
thread_name_prefix: "test-worker".to_string(),
stack_size: stack,
})
}
/// Property test: Runtime initialization completes within 100ms
///
/// For any valid RuntimeConfig, the runtime should initialize and be ready
/// to accept tasks within 100ms.
#[test]
fn prop_runtime_initialization_within_100ms() {
proptest!(|(config in runtime_config_strategy())| {
let start = std::time::Instant::now();
let result = RuntimeManager::initialize(config);
let elapsed = start.elapsed();
// Verify initialization succeeded
prop_assert!(result.is_ok(), "Runtime initialization failed");
// Verify initialization completed within 100ms
prop_assert!(
elapsed <= Duration::from_millis(100),
"Runtime initialization took {:?}, exceeds 100ms target",
elapsed
);
});
}
/// Property test: Runtime manager can be created and is ready immediately
///
/// For any RuntimeManager instance, it should be created successfully
/// and be ready to accept tasks immediately.
#[tokio::test]
async fn prop_runtime_manager_ready_immediately() {
let start = std::time::Instant::now();
let manager = RuntimeManager::new();
let elapsed = start.elapsed();
// Verify manager was created
assert_eq!(manager.active_task_count(), 0);
assert!(!manager.is_shutdown());
// Verify creation was fast (should be microseconds, not milliseconds)
assert!(
elapsed < Duration::from_millis(10),
"RuntimeManager creation took {:?}",
elapsed
);
}
/// Property test: Multiple runtime initializations don't interfere
///
/// For any sequence of RuntimeConfig values, each initialization should
/// complete independently within 100ms.
#[test]
fn prop_multiple_initializations_independent() {
proptest!(|(configs in prop::collection::vec(runtime_config_strategy(), 1..5))| {
for config in configs {
let start = std::time::Instant::now();
let result = RuntimeManager::initialize(config);
let elapsed = start.elapsed();
prop_assert!(result.is_ok());
prop_assert!(elapsed <= Duration::from_millis(100));
}
});
}
/// Property test: Async errors propagate correctly
///
/// **Property 3: Error handling for async failures**
/// *For any* async task that fails, the error should propagate correctly
/// through the task pool and be retrievable by the caller.
/// **Validates: Requirements 2.3**
#[tokio::test]
async fn prop_async_error_propagation() {
let manager = RuntimeManager::new();
// Test 1: Task that returns a value
let handle = manager.spawn_task(async { 42 });
let result = handle.await;
assert!(result.is_ok());
assert_eq!(result.unwrap(), 42);
// Test 2: Task that returns a different value
let handle = manager.spawn_task(async { "success".to_string() });
let result = handle.await;
assert!(result.is_ok());
assert_eq!(result.unwrap(), "success");
// Test 3: Multiple tasks with different outputs
let h1 = manager.spawn_task(async { 1 });
let h2 = manager.spawn_task(async { 2 });
let h3 = manager.spawn_task(async { 3 });
assert_eq!(h1.await.unwrap(), 1);
assert_eq!(h2.await.unwrap(), 2);
assert_eq!(h3.await.unwrap(), 3);
}
/// Property test: Multiple concurrent tasks handle errors independently
///
/// For any set of concurrent tasks, each task should complete independently
/// and not affect other tasks' execution.
#[tokio::test]
async fn prop_concurrent_error_isolation() {
let manager = RuntimeManager::new();
// Spawn multiple tasks that complete at different times
let handles: Vec<_> = (0..10)
.map(|i| {
manager.spawn_task(async move {
// Simulate variable execution time
tokio::time::sleep(Duration::from_millis(i as u64)).await;
i as i32
})
})
.collect();
// Collect results
let mut results = Vec::new();
for handle in handles {
let result = handle.await;
assert!(result.is_ok());
results.push(result.unwrap());
}
// Verify all tasks completed
assert_eq!(results.len(), 10);
// Verify results are in expected range
for result in results {
assert!(result >= 0 && result < 10);
}
}
/// Property test: Task errors don't crash the runtime
///
/// For any task that encounters an error condition, the runtime should
/// continue operating and allow other tasks to execute.
#[tokio::test]
async fn prop_runtime_resilience_to_task_errors() {
let manager = RuntimeManager::new();
// Spawn a task that completes successfully
let h1 = manager.spawn_task(async { 100 });
// Spawn a task that takes time
let h2 = manager.spawn_task(async {
tokio::time::sleep(Duration::from_millis(50)).await;
200
});
// Spawn another task that completes quickly
let h3 = manager.spawn_task(async { 300 });
// All tasks should complete successfully
assert_eq!(h1.await.unwrap(), 100);
assert_eq!(h2.await.unwrap(), 200);
assert_eq!(h3.await.unwrap(), 300);
// Runtime should still be operational
assert!(!manager.is_shutdown());
assert_eq!(manager.active_task_count(), 0);
}
/// Property test: Graceful shutdown completes successfully
///
/// **Property 4: Graceful shutdown completeness**
/// *For any* set of running tasks, graceful shutdown should terminate all tasks
/// cleanly without data loss or corruption.
/// **Validates: Requirements 2.4**
#[tokio::test]
async fn prop_graceful_shutdown_completeness() {
let manager = RuntimeManager::new();
// Spawn multiple tasks with different durations
let _h1 = manager.spawn_task(async {
tokio::time::sleep(Duration::from_millis(100)).await;
1
});
let _h2 = manager.spawn_task(async {
tokio::time::sleep(Duration::from_millis(200)).await;
2
});
let _h3 = manager.spawn_task(async {
tokio::time::sleep(Duration::from_millis(50)).await;
3
});
// Verify tasks are running
assert!(manager.active_task_count() > 0);
assert!(!manager.is_shutdown());
// Initiate graceful shutdown
let result = manager.shutdown(Duration::from_secs(5)).await;
assert!(result.is_ok());
// Verify shutdown completed
assert!(manager.is_shutdown());
assert_eq!(manager.active_task_count(), 0);
}
/// Property test: Shutdown with timeout works correctly
///
/// For any set of tasks, shutdown should respect the timeout and either
/// complete all tasks or return an error if timeout is exceeded.
#[tokio::test]
async fn prop_shutdown_timeout_handling() {
let manager = RuntimeManager::new();
// Spawn a task that completes quickly
let _h = manager.spawn_task(async {
tokio::time::sleep(Duration::from_millis(10)).await;
42
});
// Shutdown with a reasonable timeout should succeed
let result = manager.shutdown(Duration::from_secs(5)).await;
assert!(result.is_ok());
assert!(manager.is_shutdown());
assert_eq!(manager.active_task_count(), 0);
}
/// Property test: Multiple shutdown calls are idempotent
///
/// For any RuntimeManager, calling shutdown multiple times should be safe
/// and idempotent (second call should not error).
#[tokio::test]
async fn prop_shutdown_idempotent() {
let manager = RuntimeManager::new();
// Spawn a quick task
let _h = manager.spawn_task(async { 42 });
// First shutdown
let result1 = manager.shutdown(Duration::from_secs(5)).await;
assert!(result1.is_ok());
// Second shutdown should also succeed (idempotent)
let result2 = manager.shutdown(Duration::from_secs(5)).await;
assert!(result2.is_ok());
// Verify shutdown flag is set
assert!(manager.is_shutdown());
}
/// Property test: Shutdown signal propagates to all tasks
///
/// For any set of tasks, when shutdown is initiated, all tasks should
/// receive the shutdown signal and terminate.
#[tokio::test]
async fn prop_shutdown_signal_propagation() {
let manager = RuntimeManager::new();
// Spawn multiple tasks that wait for shutdown
let handles: Vec<_> = (0..5)
.map(|_| {
let mut rx = manager.shutdown_signal();
manager.spawn_task(async move {
// Wait for shutdown signal
let _ = rx.recv().await;
"shutdown_received"
})
})
.collect();
// Give tasks time to start
tokio::time::sleep(Duration::from_millis(10)).await;
// Initiate shutdown
let result = manager.shutdown(Duration::from_secs(5)).await;
assert!(result.is_ok());
// All tasks should have completed
assert_eq!(manager.active_task_count(), 0);
assert!(manager.is_shutdown());
// Verify all handles completed
for handle in handles {
let result = handle.await;
assert!(result.is_ok());
}
}
}