@@ -278,18 +278,18 @@ await db.Execute(
278278 [ Fact ( Timeout = 2000 ) ]
279279 public async Task ReadWhileWriteIsRunningTest ( )
280280 {
281- var tcs = new TaskCompletionSource < bool > ( ) ;
281+ var sem = new TaskCompletionSource < bool > ( ) ;
282282
283283 // This wont resolve or free until another connection free's it
284284 var writeTask = db . WriteLock ( async context =>
285285 {
286- await tcs . Task ; // Wait until read lock signals to proceed
286+ await sem . Task ; // Wait until read lock signals to proceed
287287 } ) ;
288288
289289 var readTask = db . ReadLock ( async context =>
290290 {
291291 // Read logic could execute here while writeLock is still open
292- tcs . SetResult ( true ) ;
292+ sem . SetResult ( true ) ;
293293 await Task . CompletedTask ;
294294 return 42 ;
295295 } ) ;
@@ -469,15 +469,15 @@ await db.Execute(
469469 public async Task TestConcurrentReadsTest ( )
470470 {
471471 await db . Execute ( "INSERT INTO assets(id) VALUES(?)" , [ "O6-conccurent-1" ] ) ;
472- var tcs = new TaskCompletionSource < bool > ( ) ;
472+ var sem = new TaskCompletionSource < bool > ( ) ;
473473
474474 // Start a long-running write transaction
475475 var transactionTask = Task . Run ( async ( ) =>
476476 {
477477 await db . WriteTransaction ( async tx =>
478478 {
479479 await tx . Execute ( "INSERT INTO assets(id) VALUES(?)" , [ "O6-conccurent-2" ] ) ;
480- await tcs . Task ;
480+ await sem . Task ;
481481 await tx . Commit ( ) ;
482482 } ) ;
483483 } ) ;
@@ -487,7 +487,7 @@ await db.WriteTransaction(async tx =>
487487 Assert . Single ( result ) ; // The transaction is not commited yet, we should only read 1 asset
488488
489489 // Let the transaction complete
490- tcs . SetResult ( true ) ;
490+ sem . SetResult ( true ) ;
491491 await transactionTask ;
492492
493493 // Read again after the transaction is committed
@@ -509,7 +509,7 @@ public async Task GetUploadQueueStatsTest()
509509 }
510510
511511 [ Fact ]
512- public async Task DynamicQueryTest ( )
512+ public async Task QueryDynamicTest ( )
513513 {
514514 string id = Guid . NewGuid ( ) . ToString ( ) ;
515515 string description = "new description" ;
@@ -526,7 +526,7 @@ await db.Execute(
526526 }
527527
528528 [ Fact ( Timeout = 2000 ) ]
529- public async Task DynamicWatchTest ( )
529+ public async Task WatchDynamicTest ( )
530530 {
531531 string id = Guid . NewGuid ( ) . ToString ( ) ;
532532 string description = "new description" ;
@@ -569,40 +569,29 @@ await tx.Execute(
569569 await watched . Task ;
570570 }
571571
572- private class WrappedTCS
573- {
574- public TaskCompletionSource < bool > TCS { get ; protected set ; } = new ( ) ;
575- public Task < bool > Task => TCS . Task ;
576-
577- public void Complete ( ) => TCS . TrySetResult ( true ) ;
578- public void Reset ( ) => TCS = new ( ) ;
579- }
580-
581572 [ Fact ( Timeout = 2000 ) ]
582573 public async void WatchDisposableSubscriptionTest ( )
583574 {
584575 int callCount = 0 ;
585- var tcs = new WrappedTCS ( ) ;
576+ var semaphore = new SemaphoreSlim ( 0 ) ;
586577
587578 var query = await db . Watch ( "select id from assets" , null , new ( )
588579 {
589580 OnResult = ( results ) =>
590581 {
591582 callCount ++ ;
592- tcs . Complete ( ) ;
583+ semaphore . Release ( ) ;
593584 } ,
594585 OnError = ( ex ) => Assert . Fail ( ex . ToString ( ) )
595586 } ) ;
596- await tcs . Task ;
597- tcs . Reset ( ) ;
587+ await semaphore . WaitAsync ( ) ;
598588 Assert . Equal ( 1 , callCount ) ;
599589
600590 await db . Execute (
601591 "insert into assets(id, description, make) values (?, ?, ?)" ,
602592 [ Guid . NewGuid ( ) . ToString ( ) , "some desc" , "some make" ]
603593 ) ;
604- await tcs . Task ;
605- tcs . Reset ( ) ;
594+ await semaphore . WaitAsync ( ) ;
606595 Assert . Equal ( 2 , callCount ) ;
607596
608597 query . Dispose ( ) ;
@@ -611,39 +600,38 @@ await db.Execute(
611600 "insert into assets(id, description, make) values (?, ?, ?)" ,
612601 [ Guid . NewGuid ( ) . ToString ( ) , "some desc" , "some make" ]
613602 ) ;
614- await Task . Delay ( 100 ) ;
615- Assert . Equal ( 2 , callCount ) ; // Same value
603+ bool receivedResult = await semaphore . WaitAsync ( 100 ) ;
604+ Assert . False ( receivedResult , "Received update after disposal" ) ;
605+ Assert . Equal ( 2 , callCount ) ;
616606 }
617607
618608 [ Fact ( Timeout = 2000 ) ]
619609 public async void WatchDisposableCustomTokenTest ( )
620610 {
621611 var customTokenSource = new CancellationTokenSource ( ) ;
622612 int callCount = 0 ;
623- var tcs = new WrappedTCS ( ) ;
613+ var sem = new SemaphoreSlim ( 0 ) ;
624614
625615 using var query = await db . Watch ( "select id, description, make from assets" , null , new ( )
626616 {
627617 OnResult = ( results ) =>
628618 {
629619 callCount ++ ;
630- tcs . Complete ( ) ;
620+ sem . Release ( ) ;
631621 } ,
632622 OnError = ( ex ) => Assert . Fail ( ex . ToString ( ) )
633623 } , new ( )
634624 {
635625 Signal = customTokenSource . Token
636626 } ) ;
637- await tcs . Task ;
638- tcs . Reset ( ) ;
627+ await sem . WaitAsync ( ) ;
639628 Assert . Equal ( 1 , callCount ) ;
640629
641630 await db . Execute (
642631 "insert into assets(id, description, make) values (?, ?, ?)" ,
643632 [ Guid . NewGuid ( ) . ToString ( ) , "some desc" , "some make" ]
644633 ) ;
645- await tcs . Task ;
646- tcs . Reset ( ) ;
634+ await sem . WaitAsync ( ) ;
647635 Assert . Equal ( 2 , callCount ) ;
648636
649637 customTokenSource . Cancel ( ) ;
@@ -652,47 +640,40 @@ await db.Execute(
652640 "insert into assets(id, description, make) values (?, ?, ?)" ,
653641 [ Guid . NewGuid ( ) . ToString ( ) , "some desc" , "some make" ]
654642 ) ;
655- await Task . Delay ( 100 ) ;
656- Assert . Equal ( 2 , callCount ) ; // Same value
643+ bool receivedResult = await sem . WaitAsync ( 100 ) ;
644+ Assert . False ( receivedResult , "Received update after disposal" ) ;
645+
646+ Assert . Equal ( 2 , callCount ) ;
657647 }
658648
659649 [ Fact ( Timeout = 2000 ) ]
660650 public async void WatchSingleCancelledTest ( )
661651 {
662652 int callCount = 0 ;
663- object lockObject = new object ( ) ;
664653
665- var watchHandlerFactory = ( WrappedTCS tcs ) => new WatchHandler < IdResult >
654+ var watchHandlerFactory = ( SemaphoreSlim sem ) => new WatchHandler < IdResult >
666655 {
667656 OnResult = ( result ) =>
668657 {
669- lock ( lockObject )
670- {
671- callCount ++ ;
672- }
673- tcs . Complete ( ) ;
658+ Interlocked . Increment ( ref callCount ) ;
659+ sem . Release ( ) ;
674660 } ,
675661 OnError = ( ex ) => Assert . Fail ( ex . ToString ( ) ) ,
676662 } ;
677663
678- var tcsAlwaysRunning = new WrappedTCS ( ) ;
679- var tcsCancelled = new WrappedTCS ( ) ;
680- // Make queryAlwaysRunning slightly more expensive
681- using var queryAlwaysRunning = await db . Watch ( "select id from assets order by id" , null , watchHandlerFactory ( tcsAlwaysRunning ) ) ;
682- using var queryCancelled = await db . Watch ( "select id from assets" , null , watchHandlerFactory ( tcsCancelled ) ) ;
664+ var semAlwaysRunning = new SemaphoreSlim ( 0 ) ;
665+ var semCancelled = new SemaphoreSlim ( 0 ) ;
666+ using var queryAlwaysRunning = await db . Watch ( "select id from assets" , null , watchHandlerFactory ( semAlwaysRunning ) ) ;
667+ using var queryCancelled = await db . Watch ( "select id from assets" , null , watchHandlerFactory ( semCancelled ) ) ;
683668
684- await Task . WhenAll ( tcsAlwaysRunning . Task , tcsCancelled . Task ) ;
685- tcsAlwaysRunning . Reset ( ) ;
686- tcsCancelled . Reset ( ) ;
669+ await Task . WhenAll ( semAlwaysRunning . WaitAsync ( ) , semCancelled . WaitAsync ( ) ) ;
687670 Assert . Equal ( 2 , callCount ) ;
688671
689672 await db . Execute (
690673 "insert into assets(id, description, make) values (?, ?, ?)" ,
691674 [ Guid . NewGuid ( ) . ToString ( ) , "some desc" , "some make" ]
692675 ) ;
693- await Task . WhenAll ( tcsAlwaysRunning . Task , tcsCancelled . Task ) ;
694- tcsAlwaysRunning . Reset ( ) ;
695- tcsCancelled . Reset ( ) ;
676+ await Task . WhenAll ( semAlwaysRunning . WaitAsync ( ) , semCancelled . WaitAsync ( ) ) ;
696677 Assert . Equal ( 4 , callCount ) ;
697678
698679 // Close one query
@@ -702,50 +683,43 @@ await db.Execute(
702683 "insert into assets(id, description, make) values (?, ?, ?)" ,
703684 [ Guid . NewGuid ( ) . ToString ( ) , "some desc" , "some make" ]
704685 ) ;
705- // Because queryAlwaysRunning is more expensive than queryCancelled, we would expect
706- // queryCancelled to complete before it if the cancellation failed, hence we can just
707- // wait for queryAlwaysRunning to complete.
708- await tcsAlwaysRunning . Task ;
709686
687+ // Ensure nothing received from cancelled result
688+ bool receivedResult = await semCancelled . WaitAsync ( 100 ) ;
689+ Assert . False ( receivedResult , "Received update after disposal" ) ;
690+
691+ await semAlwaysRunning . WaitAsync ( ) ;
710692 Assert . Equal ( 5 , callCount ) ;
711693 }
712694
713695 [ Fact ( Timeout = 2000 ) ]
714696 public async void WatchMultipleCancelledTest ( )
715697 {
716698 int callCount = 0 ;
717- object lockObject = new object ( ) ;
718699
719- var watchHandlerFactory = ( WrappedTCS tcs ) => new WatchHandler < IdResult >
700+ var watchHandlerFactory = ( SemaphoreSlim sem ) => new WatchHandler < IdResult >
720701 {
721702 OnResult = ( result ) =>
722703 {
723- lock ( lockObject )
724- {
725- callCount ++ ;
726- }
727- tcs . Complete ( ) ;
704+ Interlocked . Increment ( ref callCount ) ;
705+ sem . Release ( ) ;
728706 } ,
729707 OnError = ( ex ) => Assert . Fail ( ex . ToString ( ) ) ,
730708 } ;
731709
732- var tcs1 = new WrappedTCS ( ) ;
733- var tcs2 = new WrappedTCS ( ) ;
734- using var query1 = await db . Watch ( "select id from assets" , null , watchHandlerFactory ( tcs1 ) ) ;
735- using var query2 = await db . Watch ( "select id from assets" , null , watchHandlerFactory ( tcs2 ) ) ;
710+ var sem1 = new SemaphoreSlim ( 0 ) ;
711+ var sem2 = new SemaphoreSlim ( 0 ) ;
712+ using var query1 = await db . Watch ( "select id from assets" , null , watchHandlerFactory ( sem1 ) ) ;
713+ using var query2 = await db . Watch ( "select id from assets" , null , watchHandlerFactory ( sem2 ) ) ;
736714
737- await Task . WhenAll ( tcs1 . Task , tcs2 . Task ) ;
738- tcs1 . Reset ( ) ;
739- tcs2 . Reset ( ) ;
715+ await Task . WhenAll ( sem1 . WaitAsync ( ) , sem2 . WaitAsync ( ) ) ;
740716 Assert . Equal ( 2 , callCount ) ;
741717
742718 await db . Execute (
743719 "insert into assets(id, description, make) values (?, ?, ?)" ,
744720 [ Guid . NewGuid ( ) . ToString ( ) , "some desc" , "some make" ]
745721 ) ;
746- await Task . WhenAll ( tcs1 . Task , tcs2 . Task ) ;
747- tcs1 . Reset ( ) ;
748- tcs2 . Reset ( ) ;
722+ await Task . WhenAll ( sem1 . WaitAsync ( ) , sem2 . WaitAsync ( ) ) ;
749723 Assert . Equal ( 4 , callCount ) ;
750724
751725 db . UnsubscribeAllQueries ( ) ;
@@ -754,8 +728,10 @@ await db.Execute(
754728 "insert into assets(id, description, make) values (?, ?, ?)" ,
755729 [ Guid . NewGuid ( ) . ToString ( ) , "some desc" , "some make" ]
756730 ) ;
757- // Short wait to ensure unsubscription was successful
758- await Task . Delay ( 100 ) ;
731+ // Ensure no result received from either query
732+ bool receivedResult = await sem1 . WaitAsync ( 100 ) || await sem2 . WaitAsync ( 100 ) ;
733+ Assert . False ( receivedResult , "Received update after disposal" ) ;
734+
759735 Assert . Equal ( 4 , callCount ) ;
760736 }
761737}
0 commit comments