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
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
//! T-COV-95 Generative Falsification: Proptest API Request Assault (PMAT-802)
//!
//! Dr. Popper's directive: "Generate *millions* of valid and invalid API
//! request sequences. Make the machine find the gap."
//!
//! This module implements:
//! 1. Arbitrary BatchConfig generation
//! 2. GpuBatchRequest fuzzing
//! 3. Edge case parameter combinations
//! 4. Serialization roundtrip fuzzing
//!
//! Target: 517 missed lines in api/gpu_handlers.rs via algorithmic search
use crate::api::gpu_handlers::{
BatchConfig, GpuBatchRequest, GpuBatchResponse, GpuBatchResult, GpuBatchStats,
GpuStatusResponse,
};
use proptest::prelude::*;
// ============================================================================
// BatchConfig Strategy
// ============================================================================
/// Generate arbitrary BatchConfig values
fn arb_batch_config() -> impl Strategy<Value = BatchConfig> {
(
0u64..10_000, // window_ms
0usize..1000, // min_batch
0usize..1000, // optimal_batch
0usize..10_000, // max_batch
0usize..100_000, // queue_size
0usize..1000, // gpu_threshold
)
.prop_map(
|(window_ms, min_batch, optimal_batch, max_batch, queue_size, gpu_threshold)| {
BatchConfig {
window_ms,
min_batch,
optimal_batch,
max_batch,
queue_size,
gpu_threshold,
}
},
)
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(1000))]
/// Fuzz BatchConfig creation and methods
#[test]
fn fuzz_batch_config(config in arb_batch_config()) {
// should_process should not panic
let _ = config.should_process(0);
let _ = config.should_process(1);
let _ = config.should_process(config.optimal_batch);
let _ = config.should_process(usize::MAX);
// meets_minimum should not panic
let _ = config.meets_minimum(0);
let _ = config.meets_minimum(1);
let _ = config.meets_minimum(config.min_batch);
let _ = config.meets_minimum(usize::MAX);
// Clone should work
let cloned = config.clone();
prop_assert_eq!(config.window_ms, cloned.window_ms);
}
/// Fuzz BatchConfig with extreme values
#[test]
fn fuzz_batch_config_extremes(
window_ms in prop_oneof![Just(0u64), Just(u64::MAX), any::<u64>()],
min_batch in prop_oneof![Just(0usize), Just(usize::MAX), any::<usize>()],
optimal_batch in prop_oneof![Just(0usize), Just(usize::MAX), any::<usize>()],
) {
let config = BatchConfig {
window_ms,
min_batch,
optimal_batch,
max_batch: 64,
queue_size: 1024,
gpu_threshold: 32,
};
// Should not panic with extreme values
let _ = config.should_process(optimal_batch);
let _ = config.meets_minimum(min_batch);
}
}
// ============================================================================
// GpuBatchRequest Strategy
// ============================================================================
/// Generate arbitrary prompt strings
fn arb_prompt() -> impl Strategy<Value = String> {
prop_oneof![
5 => "[a-zA-Z0-9 ]{0,100}", // Normal ASCII (weighted)
1 => Just(String::new()), // Empty
1 => "[\\x00-\\xff]{0,50}", // Binary garbage
1 => "\\PC{0,200}", // Unicode
1 => Just("x".repeat(10000)), // Very long
]
}
/// Generate arbitrary GpuBatchRequest
fn arb_gpu_batch_request() -> impl Strategy<Value = GpuBatchRequest> {
(
prop::collection::vec(arb_prompt(), 0..20), // prompts
0usize..10000, // max_tokens
0.0f32..10.0, // temperature
0usize..1000, // top_k
prop::collection::vec("[a-z]{0,10}", 0..5), // stop tokens
)
.prop_map(
|(prompts, max_tokens, temperature, top_k, stop)| GpuBatchRequest {
prompts,
max_tokens,
temperature,
top_k,
stop,
},
)
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(500))]
/// Fuzz GpuBatchRequest creation
#[test]
fn fuzz_gpu_batch_request(request in arb_gpu_batch_request()) {
// Clone should work
let cloned = request.clone();
prop_assert_eq!(request.prompts.len(), cloned.prompts.len());
prop_assert_eq!(request.max_tokens, cloned.max_tokens);
// Debug should not panic
let _ = format!("{:?}", request);
}
/// Fuzz GpuBatchRequest with extreme temperatures
#[test]
fn fuzz_extreme_temperature(
temp in prop_oneof![
Just(0.0f32),
Just(f32::MIN_POSITIVE),
Just(1.0f32),
Just(f32::MAX),
Just(f32::INFINITY),
Just(f32::NEG_INFINITY),
Just(f32::NAN),
]
) {
let request = GpuBatchRequest {
prompts: vec!["test".to_string()],
max_tokens: 10,
temperature: temp,
top_k: 40,
stop: vec![],
};
// Should not panic
let _ = format!("{:?}", request);
let _ = request.clone();
}
}
// ============================================================================
// GpuBatchResult Strategy
// ============================================================================
fn arb_gpu_batch_result() -> impl Strategy<Value = GpuBatchResult> {
(
any::<usize>(), // index
prop::collection::vec(any::<u32>(), 0..100), // token_ids
"[a-zA-Z0-9 ]{0,100}", // text
any::<usize>(), // num_generated
)
.prop_map(|(index, token_ids, text, num_generated)| GpuBatchResult {
index,
token_ids,
text,
num_generated,
})
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(300))]
/// Fuzz GpuBatchResult
#[test]
fn fuzz_gpu_batch_result(result in arb_gpu_batch_result()) {
let cloned = result.clone();
prop_assert_eq!(result.index, cloned.index);
prop_assert_eq!(result.token_ids.len(), cloned.token_ids.len());
// Serialization should work
let json = serde_json::to_string(&result);
prop_assert!(json.is_ok());
}
}
// ============================================================================
// GpuBatchStats Strategy
// ============================================================================
fn arb_gpu_batch_stats() -> impl Strategy<Value = GpuBatchStats> {
(
any::<usize>(), // batch_size
any::<bool>(), // gpu_used
any::<usize>(), // total_tokens
0.0f64..1e10, // processing_time_ms
0.0f64..1e10, // throughput_tps
)
.prop_map(
|(batch_size, gpu_used, total_tokens, processing_time_ms, throughput_tps)| {
GpuBatchStats {
batch_size,
gpu_used,
total_tokens,
processing_time_ms,
throughput_tps,
}
},
)
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(300))]
/// Fuzz GpuBatchStats
#[test]
fn fuzz_gpu_batch_stats(stats in arb_gpu_batch_stats()) {
let cloned = stats.clone();
prop_assert_eq!(stats.batch_size, cloned.batch_size);
prop_assert_eq!(stats.gpu_used, cloned.gpu_used);
// Serialization
let json = serde_json::to_string(&stats);
prop_assert!(json.is_ok());
}
/// Fuzz with NaN and Infinity in stats
#[test]
fn fuzz_stats_special_floats(
processing_time in prop_oneof![
Just(0.0f64),
Just(f64::INFINITY),
Just(f64::NEG_INFINITY),
Just(f64::NAN),
Just(f64::MIN_POSITIVE),
Just(f64::MAX),
],
throughput in prop_oneof![
Just(0.0f64),
Just(f64::INFINITY),
Just(f64::NAN),
]
) {
let stats = GpuBatchStats {
batch_size: 1,
gpu_used: true,
total_tokens: 100,
processing_time_ms: processing_time,
throughput_tps: throughput,
};
// Should not panic
let _ = format!("{:?}", stats);
let _ = stats.clone();
}
}
// ============================================================================
// GpuStatusResponse Strategy
// ============================================================================
fn arb_gpu_status_response() -> impl Strategy<Value = GpuStatusResponse> {
(
any::<bool>(), // cache_ready
any::<usize>(), // cache_memory_bytes
any::<usize>(), // batch_threshold
any::<usize>(), // recommended_min_batch
)
.prop_map(
|(cache_ready, cache_memory_bytes, batch_threshold, recommended_min_batch)| {
GpuStatusResponse {
cache_ready,
cache_memory_bytes,
batch_threshold,
recommended_min_batch,
}
},
)
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(200))]
/// Fuzz GpuStatusResponse
#[test]
fn fuzz_gpu_status_response(response in arb_gpu_status_response()) {
let cloned = response.clone();
prop_assert_eq!(response.cache_ready, cloned.cache_ready);
// Serialization
let json = serde_json::to_string(&response);
prop_assert!(json.is_ok());
if let Ok(json_str) = json {
let decoded: Result<GpuStatusResponse, _> = serde_json::from_str(&json_str);
prop_assert!(decoded.is_ok());
}
}
}
// ============================================================================
// Full Response Strategy
// ============================================================================
fn arb_gpu_batch_response() -> impl Strategy<Value = GpuBatchResponse> {
(
prop::collection::vec(arb_gpu_batch_result(), 0..10),
arb_gpu_batch_stats(),
)
.prop_map(|(results, stats)| GpuBatchResponse { results, stats })
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(200))]
/// Fuzz full GpuBatchResponse
#[test]
fn fuzz_gpu_batch_response(response in arb_gpu_batch_response()) {
let cloned = response.clone();
prop_assert_eq!(response.results.len(), cloned.results.len());
// Serialization roundtrip
let json = serde_json::to_string(&response);
prop_assert!(json.is_ok());
if let Ok(json_str) = json {
let decoded: Result<GpuBatchResponse, _> = serde_json::from_str(&json_str);
// May fail if floats are NaN (JSON doesn't support NaN)
let _ = decoded;
}
}
}
// ============================================================================
// JSON Malformation Fuzzing
// ============================================================================
proptest! {
#![proptest_config(ProptestConfig::with_cases(300))]
/// Fuzz JSON deserialization with arbitrary bytes
#[test]
fn fuzz_json_deserialization(
garbage in prop::collection::vec(any::<u8>(), 0..200)
) {
// Should not panic
let result: Result<GpuBatchRequest, _> = serde_json::from_slice(&garbage);
let _ = result;
let result: Result<GpuBatchResponse, _> = serde_json::from_slice(&garbage);
let _ = result;
// BatchConfig is internal (no Deserialize), skip JSON fuzzing
}
/// Fuzz with almost-valid JSON
#[test]
fn fuzz_almost_valid_json(
prompts_count in 0usize..5,
max_tokens in any::<i64>(), // Use i64 to allow negative
temperature in any::<f64>(),
) {
let json = format!(
r#"{{"prompts":[{}],"max_tokens":{},"temperature":{}}}"#,
(0..prompts_count)
.map(|i| format!(r#""prompt_{}""#, i))
.collect::<Vec<_>>()
.join(","),
max_tokens,
if temperature.is_nan() {
"null".to_string()
} else {
temperature.to_string()
}
);
let result: Result<GpuBatchRequest, _> = serde_json::from_str(&json);
// May succeed or fail based on field types
let _ = result;
}
}
// ============================================================================
// Combinatorial Boundary Testing
// ============================================================================
proptest! {
#![proptest_config(ProptestConfig::with_cases(100))]
/// Test all boundary combinations
#[test]
fn fuzz_boundary_combinations(
min_batch in prop::sample::select(&[0usize, 1, 2, 4, 8, 16, 32, 64, 128, usize::MAX]),
optimal in prop::sample::select(&[0usize, 1, 2, 4, 8, 16, 32, 64, 128, usize::MAX]),
test_size in prop::sample::select(&[0usize, 1, 2, 4, 8, 16, 32, 64, 128, usize::MAX]),
) {
let config = BatchConfig {
window_ms: 50,
min_batch,
optimal_batch: optimal,
max_batch: 64,
queue_size: 1024,
gpu_threshold: 32,
};
// All boundary combinations should not panic
let _ = config.should_process(test_size);
let _ = config.meets_minimum(test_size);
}
}