@@ -385,10 +385,14 @@ pub unsafe extern "C" fn cass_future_tracing_id(
385
385
386
386
#[ cfg( test) ]
387
387
mod tests {
388
- use crate :: testing:: assert_cass_future_error_message_eq;
388
+ use crate :: testing:: { assert_cass_error_eq , assert_cass_future_error_message_eq} ;
389
389
390
390
use super :: * ;
391
- use std:: { os:: raw:: c_char, thread, time:: Duration } ;
391
+ use std:: {
392
+ os:: raw:: c_char,
393
+ thread:: { self } ,
394
+ time:: Duration ,
395
+ } ;
392
396
393
397
// This is not a particularly smart test, but if some thread is granted access the value
394
398
// before it is truly computed, then weird things should happen, even a segfault.
@@ -450,4 +454,84 @@ mod tests {
450
454
cass_future_free ( cass_fut) ;
451
455
}
452
456
}
457
+
458
+ // This test checks whether the future callback is executed correctly when:
459
+ // - a future is awaited indefinitely
460
+ // - a future is awaited, after the timeout appeared (_wait_timed)
461
+ // - a future is not awaited. We simply sleep, and let the tokio runtime resolve
462
+ // the future, and execute its callback
463
+ #[ test]
464
+ #[ ntest:: timeout( 500 ) ]
465
+ fn test_cass_future_callback ( ) {
466
+ unsafe {
467
+ const ERROR_MSG : & str = "NOBODY EXPECTED SPANISH INQUISITION" ;
468
+ const HUNDRED_MILLIS_IN_MICROS : u64 = 100 * 1000 ;
469
+
470
+ let create_future_and_flag = || {
471
+ unsafe extern "C" fn mark_flag_cb ( _fut : * const CassFuture , data : * mut c_void ) {
472
+ let flag = data as * mut bool ;
473
+ * flag = true ;
474
+ }
475
+
476
+ let fut = async move {
477
+ tokio:: time:: sleep ( Duration :: from_micros ( HUNDRED_MILLIS_IN_MICROS ) ) . await ;
478
+ Err ( ( CassError :: CASS_OK , ERROR_MSG . into ( ) ) )
479
+ } ;
480
+ let cass_fut = CassFuture :: make_raw ( fut) ;
481
+ let flag = Box :: new ( false ) ;
482
+ let flag_ptr = Box :: into_raw ( flag) ;
483
+
484
+ assert_cass_error_eq ! (
485
+ cass_future_set_callback( cass_fut, Some ( mark_flag_cb) , flag_ptr as * mut c_void) ,
486
+ CassError :: CASS_OK
487
+ ) ;
488
+
489
+ ( cass_fut, flag_ptr)
490
+ } ;
491
+
492
+ // Callback executed after awaiting.
493
+ {
494
+ let ( cass_fut, flag_ptr) = create_future_and_flag ( ) ;
495
+ cass_future_wait ( cass_fut) ;
496
+
497
+ assert_cass_future_error_message_eq ! ( cass_fut, Some ( ERROR_MSG ) ) ;
498
+ assert ! ( * flag_ptr) ;
499
+
500
+ cass_future_free ( cass_fut) ;
501
+ let _ = Box :: from_raw ( flag_ptr) ;
502
+ }
503
+
504
+ // Callback executed after timeouts.
505
+ {
506
+ let ( cass_fut, flag_ptr) = create_future_and_flag ( ) ;
507
+
508
+ // This should timeout on tokio::time::timeout.
509
+ let timed_result = cass_future_wait_timed ( cass_fut, HUNDRED_MILLIS_IN_MICROS / 5 ) ;
510
+ assert_eq ! ( 0 , timed_result) ;
511
+ // This should timeout on cond variable (previous call consumed JoinHandle).
512
+ let timed_result = cass_future_wait_timed ( cass_fut, HUNDRED_MILLIS_IN_MICROS / 5 ) ;
513
+ assert_eq ! ( 0 , timed_result) ;
514
+ assert_cass_future_error_message_eq ! ( cass_fut, Some ( ERROR_MSG ) ) ;
515
+ assert ! ( * flag_ptr) ;
516
+
517
+ cass_future_free ( cass_fut) ;
518
+ let _ = Box :: from_raw ( flag_ptr) ;
519
+ }
520
+
521
+ // Don't await the future. Just sleep.
522
+ {
523
+ let ( cass_fut, flag_ptr) = create_future_and_flag ( ) ;
524
+
525
+ RUNTIME . block_on ( async {
526
+ tokio:: time:: sleep ( Duration :: from_micros ( HUNDRED_MILLIS_IN_MICROS + 10 * 1000 ) )
527
+ . await
528
+ } ) ;
529
+
530
+ assert ! ( * flag_ptr) ;
531
+
532
+ cass_future_free ( cass_fut) ;
533
+ let _ = Box :: from_raw ( flag_ptr) ;
534
+ }
535
+ }
536
+ }
453
537
}
0 commit comments