@@ -1009,6 +1009,41 @@ public async Task FilterOrchestrationsByName()
10091009 await Assert . ThrowsAsync < OperationCanceledException > ( async ( ) => await server . Client . WaitForInstanceCompletionAsync ( instanceId , new CancellationTokenSource ( TimeSpan . FromSeconds ( 5 ) ) . Token ) ) ;
10101010 }
10111011
1012+ [ Obsolete ( "Experimental" ) ]
1013+ [ Fact ]
1014+ public async Task FilterOrchestrationsByNamePassesWhenNotMatching ( )
1015+ {
1016+ // Setup a worker with an Orchestration Filter.
1017+ TaskName orchestratorName = nameof ( EmptyOrchestration ) ;
1018+ var orchestrationFilter = new OrchestrationFilter ( ) ;
1019+ await using HostTestLifetime server = await this . StartWorkerAsync ( b =>
1020+ {
1021+ b . AddTasks ( tasks => tasks . AddOrchestratorFunc ( orchestratorName , ctx => Task . FromResult < object ? > ( null ) ) ) ;
1022+ b . UseOrchestrationFilter ( orchestrationFilter ) ;
1023+ } ) ;
1024+
1025+ // Nothing in the filter set, the orchestration should complete.
1026+ string instanceId = await server . Client . ScheduleNewOrchestrationInstanceAsync ( orchestratorName ) ;
1027+ OrchestrationMetadata metadata = await server . Client . WaitForInstanceCompletionAsync (
1028+ instanceId , this . TimeoutToken ) ;
1029+
1030+ Assert . NotNull ( metadata ) ;
1031+ Assert . Equal ( instanceId , metadata . InstanceId ) ;
1032+ Assert . Equal ( OrchestrationRuntimeStatus . Completed , metadata . RuntimeStatus ) ;
1033+
1034+ // Update the filter and re-enqueue. The name doesn't match so the filter should be OK.
1035+ orchestrationFilter . NameDenySet . Add ( $ "not-{ orchestratorName } ") ;
1036+
1037+ // This should throw as the work is denied.
1038+ instanceId = await server . Client . ScheduleNewOrchestrationInstanceAsync ( orchestratorName ) ;
1039+ metadata = await server . Client . WaitForInstanceCompletionAsync (
1040+ instanceId , this . TimeoutToken ) ;
1041+
1042+ Assert . NotNull ( metadata ) ;
1043+ Assert . Equal ( instanceId , metadata . InstanceId ) ;
1044+ Assert . Equal ( OrchestrationRuntimeStatus . Completed , metadata . RuntimeStatus ) ;
1045+ }
1046+
10121047 [ Obsolete ( "Experimental" ) ]
10131048 [ Fact ]
10141049 public async Task FilterOrchestrationsByTag ( )
@@ -1049,16 +1084,62 @@ public async Task FilterOrchestrationsByTag()
10491084 await Assert . ThrowsAsync < OperationCanceledException > ( async ( ) => await server . Client . WaitForInstanceCompletionAsync ( instanceId , new CancellationTokenSource ( TimeSpan . FromSeconds ( 5 ) ) . Token ) ) ;
10501085 }
10511086
1087+ [ Obsolete ( "Experimental" ) ]
1088+ [ Fact ]
1089+ public async Task FilterOrchestrationsByTagPassesWithNoMatch ( )
1090+ {
1091+ // Setup a worker with an Orchestration Filter.
1092+ TaskName orchestratorName = nameof ( EmptyOrchestration ) ;
1093+ IReadOnlyDictionary < string , string > orchestratorTags = new Dictionary < string , string >
1094+ {
1095+ { "test" , "true" }
1096+ } ;
1097+ var orchestrationFilter = new OrchestrationFilter ( ) ;
1098+ await using HostTestLifetime server = await this . StartWorkerAsync ( b =>
1099+ {
1100+ b . AddTasks ( tasks => tasks . AddOrchestratorFunc ( orchestratorName , ctx => Task . FromResult < object ? > ( null ) ) ) ;
1101+ b . UseOrchestrationFilter ( orchestrationFilter ) ;
1102+ } ) ;
1103+
1104+ // Nothing in the filter set, the orchestration should complete.
1105+ string instanceId = await server . Client . ScheduleNewOrchestrationInstanceAsync ( orchestratorName , new StartOrchestrationOptions
1106+ {
1107+ Tags = orchestratorTags ,
1108+ } ) ;
1109+ OrchestrationMetadata metadata = await server . Client . WaitForInstanceCompletionAsync (
1110+ instanceId , this . TimeoutToken ) ;
1111+
1112+ Assert . NotNull ( metadata ) ;
1113+ Assert . Equal ( instanceId , metadata . InstanceId ) ;
1114+ Assert . Equal ( OrchestrationRuntimeStatus . Completed , metadata . RuntimeStatus ) ;
1115+
1116+ // Update the filter and re-enqueue. The tags don't match so the orchestration should be OK.
1117+ orchestrationFilter . TagDenyDict . Add ( "test" , "false" ) ;
1118+
1119+ // This should throw as the work is denied.
1120+ instanceId = await server . Client . ScheduleNewOrchestrationInstanceAsync ( orchestratorName , new StartOrchestrationOptions
1121+ {
1122+ Tags = orchestratorTags ,
1123+ } ) ;
1124+ metadata = await server . Client . WaitForInstanceCompletionAsync (
1125+ instanceId , this . TimeoutToken ) ;
1126+
1127+ Assert . NotNull ( metadata ) ;
1128+ Assert . Equal ( instanceId , metadata . InstanceId ) ;
1129+ Assert . Equal ( OrchestrationRuntimeStatus . Completed , metadata . RuntimeStatus ) ;
1130+ }
1131+
1132+ [ Obsolete ( "Experimental" ) ]
10521133 class OrchestrationFilter : IOrchestrationFilter
10531134 {
10541135 public ISet < string > NameDenySet { get ; set ; } = new HashSet < string > ( ) ;
10551136 public IDictionary < string , string > TagDenyDict = new Dictionary < string , string > ( ) ;
10561137
1057- public Task < bool > IsOrchestrationValidAsync ( OrchestrationInfo info , CancellationToken cancellationToken = default )
1138+ public ValueTask < bool > IsOrchestrationValidAsync ( OrchestrationFilterParameters info , CancellationToken cancellationToken = default )
10581139 {
1059- return Task . FromResult (
1140+ return ValueTask . FromResult (
10601141 ! this . NameDenySet . Contains ( info . Name )
1061- && ! this . TagDenyDict . Any ( kvp => info . Tags . ContainsKey ( kvp . Key ) && info . Tags [ kvp . Key ] == kvp . Value ) ) ;
1142+ && ! this . TagDenyDict . Any ( kvp => info . Tags != null && info . Tags . ContainsKey ( kvp . Key ) && info . Tags [ kvp . Key ] == kvp . Value ) ) ;
10621143 }
10631144 }
10641145
0 commit comments