@@ -320,10 +320,14 @@ pub unsafe extern "C" fn cass_future_tracing_id(
320
320
321
321
#[ cfg( test) ]
322
322
mod tests {
323
- use crate :: testing:: assert_cass_future_error_message_eq;
323
+ use crate :: testing:: { assert_cass_error_eq , assert_cass_future_error_message_eq} ;
324
324
325
325
use super :: * ;
326
- use std:: { os:: raw:: c_char, thread, time:: Duration } ;
326
+ use std:: {
327
+ os:: raw:: c_char,
328
+ thread:: { self } ,
329
+ time:: Duration ,
330
+ } ;
327
331
328
332
// This is not a particularly smart test, but if some thread is granted access the value
329
333
// before it is truly computed, then weird things should happen, even a segfault.
@@ -385,4 +389,77 @@ mod tests {
385
389
cass_future_free ( cass_fut) ;
386
390
}
387
391
}
392
+
393
+ #[ test]
394
+ #[ ntest:: timeout( 500 ) ]
395
+ fn test_cass_future_callback ( ) {
396
+ unsafe {
397
+ const ERROR_MSG : & str = "NOBODY EXPECTED SPANISH INQUISITION" ;
398
+ const HUNDRED_MILLIS_IN_MICROS : u64 = 100 * 1000 ;
399
+
400
+ let create_future_and_flag = || {
401
+ unsafe extern "C" fn mark_flag_cb ( _fut : * const CassFuture , data : * mut c_void ) {
402
+ let flag = data as * mut bool ;
403
+ * flag = true ;
404
+ }
405
+
406
+ const ERROR_MSG : & str = "NOBODY EXPECTED SPANISH INQUISITION" ;
407
+ let fut = async move {
408
+ tokio:: time:: sleep ( Duration :: from_micros ( HUNDRED_MILLIS_IN_MICROS ) ) . await ;
409
+ Err ( ( CassError :: CASS_OK , ERROR_MSG . into ( ) ) )
410
+ } ;
411
+ let cass_fut = CassFuture :: make_raw ( fut) ;
412
+ let flag = Box :: new ( false ) ;
413
+ let flag_ptr = Box :: into_raw ( flag) ;
414
+
415
+ assert_cass_error_eq ! (
416
+ cass_future_set_callback( cass_fut, Some ( mark_flag_cb) , flag_ptr as * mut c_void) ,
417
+ CassError :: CASS_OK
418
+ ) ;
419
+
420
+ ( cass_fut, flag_ptr)
421
+ } ;
422
+
423
+ // Callback executed after awaiting.
424
+ {
425
+ let ( cass_fut, flag_ptr) = create_future_and_flag ( ) ;
426
+ cass_future_wait ( cass_fut) ;
427
+
428
+ assert_cass_future_error_message_eq ! ( cass_fut, Some ( ERROR_MSG ) ) ;
429
+ assert ! ( * flag_ptr) ;
430
+
431
+ cass_future_free ( cass_fut) ;
432
+ let _ = Box :: from_raw ( flag_ptr) ;
433
+ }
434
+
435
+ // Callback executed after timeouts.
436
+ {
437
+ let ( cass_fut, flag_ptr) = create_future_and_flag ( ) ;
438
+
439
+ // This should timeout on tokio::time::timeout.
440
+ let timed_result = cass_future_wait_timed ( cass_fut, HUNDRED_MILLIS_IN_MICROS / 5 ) ;
441
+ assert_eq ! ( 0 , timed_result) ;
442
+ // This should timeout on cond variable (previous call consumed JoinHandle).
443
+ let timed_result = cass_future_wait_timed ( cass_fut, HUNDRED_MILLIS_IN_MICROS / 5 ) ;
444
+ assert_eq ! ( 0 , timed_result) ;
445
+ assert_cass_future_error_message_eq ! ( cass_fut, Some ( ERROR_MSG ) ) ;
446
+ assert ! ( * flag_ptr) ;
447
+
448
+ cass_future_free ( cass_fut) ;
449
+ let _ = Box :: from_raw ( flag_ptr) ;
450
+ }
451
+
452
+ // Don't await the future. Just sleep.
453
+ {
454
+ let ( cass_fut, flag_ptr) = create_future_and_flag ( ) ;
455
+
456
+ std:: thread:: sleep ( Duration :: from_micros ( HUNDRED_MILLIS_IN_MICROS + 10 * 1000 ) ) ;
457
+
458
+ assert ! ( * flag_ptr) ;
459
+
460
+ cass_future_free ( cass_fut) ;
461
+ let _ = Box :: from_raw ( flag_ptr) ;
462
+ }
463
+ }
464
+ }
388
465
}
0 commit comments