@@ -478,6 +478,185 @@ public async Task OperationTransformer_CanAccessTransientServiceFromContextAppli
478
478
Assert . Equal ( 4 , Dependency . InstantiationCount ) ;
479
479
}
480
480
481
+ [ Fact ]
482
+ public async Task AddOpenApiOperationTransformer_CanApplyTransformer ( )
483
+ {
484
+ var builder = CreateBuilder ( ) ;
485
+
486
+ builder . MapGet ( "/" , ( ) => { } )
487
+ . AddOpenApiOperationTransformer ( ( operation , context , cancellationToken ) =>
488
+ {
489
+ operation . Description = "Operation Description" ;
490
+ return Task . CompletedTask ;
491
+ } ) ;
492
+
493
+ await VerifyOpenApiDocument ( builder , document =>
494
+ {
495
+ Assert . Collection ( document . Paths . OrderBy ( p => p . Key ) ,
496
+ path =>
497
+ {
498
+ Assert . Equal ( "/" , path . Key ) ;
499
+ var operation = Assert . Single ( path . Value . Operations . Values ) ;
500
+ Assert . Equal ( "Operation Description" , operation . Description ) ;
501
+ } ) ;
502
+ } ) ;
503
+ }
504
+
505
+ [ Fact ]
506
+ public async Task AddOpenApiOperationTransformer_TransformerRunsAfterOtherTransformers ( )
507
+ {
508
+ var builder = CreateBuilder ( ) ;
509
+
510
+ builder . MapGet ( "/" , ( ) => { } )
511
+ . AddOpenApiOperationTransformer ( ( operation , context , cancellationToken ) =>
512
+ {
513
+ operation . Description = "Operation Description" ;
514
+ return Task . CompletedTask ;
515
+ } ) ;
516
+
517
+ var options = new OpenApiOptions ( ) ;
518
+ options . AddOperationTransformer ( ( operation , context , cancellationToken ) =>
519
+ {
520
+ operation . Description = "Operation Description 2" ;
521
+ return Task . CompletedTask ;
522
+ } ) ;
523
+
524
+ await VerifyOpenApiDocument ( builder , document =>
525
+ {
526
+ Assert . Collection ( document . Paths . OrderBy ( p => p . Key ) ,
527
+ path =>
528
+ {
529
+ Assert . Equal ( "/" , path . Key ) ;
530
+ var operation = Assert . Single ( path . Value . Operations . Values ) ;
531
+ Assert . Equal ( "Operation Description" , operation . Description ) ;
532
+ } ) ;
533
+ } ) ;
534
+ }
535
+
536
+ [ Fact ]
537
+ public async Task AddOpenApiOperationTransformer_SupportsMultipleTransformers ( )
538
+ {
539
+ var builder = CreateBuilder ( ) ;
540
+
541
+ builder . MapGet ( "/" , ( ) => { } )
542
+ . AddOpenApiOperationTransformer ( ( operation , context , cancellationToken ) =>
543
+ {
544
+ operation . Description = "Operation Description" ;
545
+ return Task . CompletedTask ;
546
+ } )
547
+ . AddOpenApiOperationTransformer ( ( operation , context , cancellationToken ) =>
548
+ {
549
+ operation . Description += " 2" ;
550
+ operation . Deprecated = true ;
551
+ return Task . CompletedTask ;
552
+ } )
553
+ . AddOpenApiOperationTransformer ( ( operation , context , cancellationToken ) =>
554
+ {
555
+ operation . Description += " 3" ;
556
+ operation . OperationId = "OperationId" ;
557
+ return Task . CompletedTask ;
558
+ } ) ;
559
+
560
+ await VerifyOpenApiDocument ( builder , document =>
561
+ {
562
+ Assert . Collection ( document . Paths . OrderBy ( p => p . Key ) ,
563
+ path =>
564
+ {
565
+ Assert . Equal ( "/" , path . Key ) ;
566
+ var operation = Assert . Single ( path . Value . Operations . Values ) ;
567
+ Assert . Equal ( "Operation Description 2 3" , operation . Description ) ;
568
+ Assert . True ( operation . Deprecated ) ;
569
+ Assert . Equal ( "OperationId" , operation . OperationId ) ;
570
+ } ) ;
571
+ } ) ;
572
+ }
573
+
574
+ [ Fact ]
575
+ public async Task OperationTransformer_RespectsOperationCancellation ( )
576
+ {
577
+ var builder = CreateBuilder ( ) ;
578
+ builder . MapGet ( "/todo" , ( ) => { } ) ;
579
+
580
+ var options = new OpenApiOptions ( ) ;
581
+ var transformerCalled = false ;
582
+ var exceptionThrown = false ;
583
+ var tcs = new TaskCompletionSource ( ) ;
584
+
585
+ options . AddOperationTransformer ( async ( operation , context , cancellationToken ) =>
586
+ {
587
+ transformerCalled = true ;
588
+ try
589
+ {
590
+ await tcs . Task . WaitAsync ( cancellationToken ) ;
591
+ operation . Description = "Should not be set" ;
592
+ }
593
+ catch ( OperationCanceledException )
594
+ {
595
+ exceptionThrown = true ;
596
+ throw ;
597
+ }
598
+ } ) ;
599
+
600
+ using var cts = new CancellationTokenSource ( ) ;
601
+ cts . CancelAfter ( 1 ) ;
602
+
603
+ await Assert . ThrowsAsync < TaskCanceledException > ( async ( ) =>
604
+ {
605
+ await VerifyOpenApiDocument ( builder , options , _ => { } , cts . Token ) ;
606
+ } ) ;
607
+
608
+ Assert . True ( transformerCalled ) ;
609
+ Assert . True ( exceptionThrown ) ;
610
+ }
611
+
612
+ [ Fact ]
613
+ public async Task OperationTransformer_ExecutesAsynchronously ( )
614
+ {
615
+ var builder = CreateBuilder ( ) ;
616
+ builder . MapGet ( "/todo" , ( ) => { } ) ;
617
+
618
+ var options = new OpenApiOptions ( ) ;
619
+ var transformerOrder = new List < int > ( ) ;
620
+ var tcs1 = new TaskCompletionSource ( ) ;
621
+ var tcs2 = new TaskCompletionSource ( ) ;
622
+
623
+ options . AddOperationTransformer ( async ( operation , context , cancellationToken ) =>
624
+ {
625
+ await tcs1 . Task ;
626
+ transformerOrder . Add ( 1 ) ;
627
+ operation . Description = "First" ;
628
+ } ) ;
629
+
630
+ options . AddOperationTransformer ( ( operation , context , cancellationToken ) =>
631
+ {
632
+ transformerOrder . Add ( 2 ) ;
633
+ operation . Description += " Second" ;
634
+ tcs2 . TrySetResult ( ) ;
635
+ return Task . CompletedTask ;
636
+ } ) ;
637
+
638
+ options . AddOperationTransformer ( async ( operation , context , cancellationToken ) =>
639
+ {
640
+ await tcs2 . Task ;
641
+ transformerOrder . Add ( 3 ) ;
642
+ operation . Description += " Third" ;
643
+ } ) ;
644
+
645
+ var documentTask = VerifyOpenApiDocument ( builder , options , document =>
646
+ {
647
+ var operation = Assert . Single ( document . Paths [ "/todo" ] . Operations . Values ) ;
648
+ Assert . Equal ( "First Second Third" , operation . Description ) ;
649
+ } ) ;
650
+
651
+ tcs1 . TrySetResult ( ) ;
652
+
653
+ await documentTask ;
654
+
655
+ // Verify transformers executed in the correct order, once for each transformer
656
+ // since there is a single operation in the document.
657
+ Assert . Equal ( [ 1 , 2 , 3 ] , transformerOrder ) ;
658
+ }
659
+
481
660
private class ActivatedTransformer : IOpenApiOperationTransformer
482
661
{
483
662
public Task TransformAsync ( OpenApiOperation operation , OpenApiOperationTransformerContext context , CancellationToken cancellationToken )
0 commit comments