@@ -12,6 +12,7 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Test.Durable
1212 using System . Linq ;
1313 using System . Threading ;
1414 using Microsoft . Azure . Functions . PowerShellWorker . Durable ;
15+ using WebJobs . Script . Grpc . Messages ;
1516 using Xunit ;
1617
1718 public class ActivityInvocationTrackerTests
@@ -21,6 +22,11 @@ public class ActivityInvocationTrackerTests
2122 private const string InvocationResult = "Invocation result" ;
2223 private const string InvocationResultJson = "\" Invocation result\" " ;
2324
25+ private const string ActivityTriggerBindingType = "activityTrigger" ;
26+
27+ private readonly IEnumerable < AzFunctionInfo > _loadedFunctions =
28+ new [ ] { CreateFakeActivityTriggerAzFunctionInfo ( FunctionName ) } ;
29+
2430 private int _nextEventId = 1 ;
2531
2632 [ Theory ]
@@ -33,8 +39,9 @@ public void ReplayActivityOrStop_ReplaysActivity_IfActivityCompleted(
3339 var allOutput = new List < object > ( ) ;
3440
3541 var activityInvocationTracker = new ActivityInvocationTracker ( ) ;
36- activityInvocationTracker . ReplayActivityOrStop ( FunctionName , FunctionInput , orchestrationContext , noWait : false ,
37- output => { allOutput . Add ( output ) ; } ) ;
42+ activityInvocationTracker . ReplayActivityOrStop (
43+ FunctionName , FunctionInput , orchestrationContext , _loadedFunctions , noWait : false ,
44+ output => { allOutput . Add ( output ) ; } ) ;
3845
3946 VerifyCallActivityActionAdded ( orchestrationContext ) ;
4047 Assert . Equal ( InvocationResult , allOutput . Single ( ) ) ;
@@ -53,8 +60,9 @@ public void ReplayActivityOrStop_OutputsNothing_IfActivityNotCompleted(
5360 var activityInvocationTracker = new ActivityInvocationTracker ( ) ;
5461 EmulateStop ( activityInvocationTracker ) ;
5562
56- activityInvocationTracker . ReplayActivityOrStop ( FunctionName , FunctionInput , orchestrationContext , noWait : false ,
57- _ => { Assert . True ( false , "Unexpected output" ) ; } ) ;
63+ activityInvocationTracker . ReplayActivityOrStop (
64+ FunctionName , FunctionInput , orchestrationContext , _loadedFunctions , noWait : false ,
65+ _ => { Assert . True ( false , "Unexpected output" ) ; } ) ;
5866
5967 VerifyCallActivityActionAdded ( orchestrationContext ) ;
6068 }
@@ -77,13 +85,19 @@ public void ReplayActivityOrStop_WaitsForStop_IfActivityNotCompleted(bool schedu
7785 ( ) =>
7886 {
7987 activityInvocationTracker . ReplayActivityOrStop (
80- FunctionName , FunctionInput , orchestrationContext , noWait : false , _ => { } ) ;
88+ FunctionName , FunctionInput , orchestrationContext , _loadedFunctions , noWait : false , _ => { } ) ;
8189 } ) ;
8290 }
8391
8492 [ Fact ]
8593 public void ReplayActivityOrStop_ReplaysMultipleActivitiesWithTheSameName ( )
8694 {
95+ var loadedFunctions = new [ ]
96+ {
97+ CreateFakeActivityTriggerAzFunctionInfo ( "FunctionA" ) ,
98+ CreateFakeActivityTriggerAzFunctionInfo ( "FunctionB" )
99+ } ;
100+
87101 var history = MergeHistories (
88102 CreateHistory ( "FunctionA" , scheduled : true , completed : true , output : "\" Result1\" " ) ,
89103 CreateHistory ( "FunctionB" , scheduled : true , completed : true , output : "\" Result2\" " ) ,
@@ -98,7 +112,7 @@ public void ReplayActivityOrStop_ReplaysMultipleActivitiesWithTheSameName()
98112 for ( var i = 0 ; i < 2 ; ++ i )
99113 {
100114 activityInvocationTracker . ReplayActivityOrStop (
101- "FunctionA" , FunctionInput , orchestrationContext , noWait : false ,
115+ "FunctionA" , FunctionInput , orchestrationContext , loadedFunctions , noWait : false ,
102116 output => { allOutput . Add ( output ) ; } ) ;
103117 }
104118
@@ -120,13 +134,68 @@ public void ReplayActivityOrStop_OutputsActivityTask_WhenNoWaitRequested(
120134
121135 var activityInvocationTracker = new ActivityInvocationTracker ( ) ;
122136 activityInvocationTracker . ReplayActivityOrStop (
123- FunctionName , FunctionInput , orchestrationContext , noWait : true ,
137+ FunctionName , FunctionInput , orchestrationContext , _loadedFunctions , noWait : true ,
124138 output => { allOutput . Add ( ( ActivityInvocationTask ) output ) ; } ) ;
125139
126140 VerifyCallActivityActionAdded ( orchestrationContext ) ;
127141 Assert . Equal ( FunctionName , allOutput . Single ( ) . Name ) ;
128142 }
129143
144+ [ Fact ]
145+ public void ReplayActivityOrStop_Throws_WhenActivityFunctionDoesNotExist ( )
146+ {
147+ var history = CreateHistory ( scheduled : false , completed : false , output : InvocationResultJson ) ;
148+ var orchestrationContext = new OrchestrationContext { History = history } ;
149+
150+ var loadedFunctions = new [ ]
151+ {
152+ CreateFakeAzFunctionInfo ( FunctionName , "fakeTriggerBindingName" , ActivityTriggerBindingType , BindingInfo . Types . Direction . In )
153+ } ;
154+
155+ const string wrongFunctionName = "AnotherFunction" ;
156+
157+ var activityInvocationTracker = new ActivityInvocationTracker ( ) ;
158+
159+ var exception =
160+ Assert . Throws < InvalidOperationException > (
161+ ( ) => activityInvocationTracker . ReplayActivityOrStop (
162+ wrongFunctionName , FunctionInput , orchestrationContext , loadedFunctions , noWait : false ,
163+ _ => { Assert . True ( false , "Unexpected output" ) ; } ) ) ;
164+
165+ Assert . Contains ( wrongFunctionName , exception . Message ) ;
166+ Assert . DoesNotContain ( ActivityTriggerBindingType , exception . Message ) ;
167+
168+ VerifyNoCallActivityActionAdded ( orchestrationContext ) ;
169+ }
170+
171+ [ Theory ]
172+ [ InlineData ( "IncorrectBindingType" , BindingInfo . Types . Direction . In ) ]
173+ [ InlineData ( ActivityTriggerBindingType , BindingInfo . Types . Direction . Out ) ]
174+ public void ReplayActivityOrStop_Throws_WhenActivityFunctionHasNoProperBinding (
175+ string bindingType , BindingInfo . Types . Direction bindingDirection )
176+ {
177+ var history = CreateHistory ( scheduled : false , completed : false , output : InvocationResultJson ) ;
178+ var orchestrationContext = new OrchestrationContext { History = history } ;
179+
180+ var loadedFunctions = new [ ]
181+ {
182+ CreateFakeAzFunctionInfo ( FunctionName , "fakeTriggerBindingName" , bindingType , bindingDirection )
183+ } ;
184+
185+ var activityInvocationTracker = new ActivityInvocationTracker ( ) ;
186+
187+ var exception =
188+ Assert . Throws < InvalidOperationException > (
189+ ( ) => activityInvocationTracker . ReplayActivityOrStop (
190+ FunctionName , FunctionInput , orchestrationContext , loadedFunctions , noWait : false ,
191+ _ => { Assert . True ( false , "Unexpected output" ) ; } ) ) ;
192+
193+ Assert . Contains ( FunctionName , exception . Message ) ;
194+ Assert . Contains ( ActivityTriggerBindingType , exception . Message ) ;
195+
196+ VerifyNoCallActivityActionAdded ( orchestrationContext ) ;
197+ }
198+
130199 [ Theory ]
131200 [ InlineData ( true , true ) ]
132201 public void WaitForActivityTasks_OutputsActivityResults_WhenAllTasksCompleted (
@@ -220,6 +289,29 @@ public void WaitForActivityTasks_WaitsForStop_WhenAnyTaskIsNotCompleted(bool sch
220289 } ) ;
221290 }
222291
292+ private static AzFunctionInfo CreateFakeActivityTriggerAzFunctionInfo ( string functionName )
293+ {
294+ return CreateFakeAzFunctionInfo ( functionName , "fakeTriggerBindingName" , ActivityTriggerBindingType , BindingInfo . Types . Direction . In ) ;
295+ }
296+
297+ private static AzFunctionInfo CreateFakeAzFunctionInfo (
298+ string functionName ,
299+ string bindingName ,
300+ string bindingType ,
301+ BindingInfo . Types . Direction bindingDirection )
302+ {
303+ return new AzFunctionInfo (
304+ functionName ,
305+ new ReadOnlyDictionary < string , ReadOnlyBindingInfo > (
306+ new Dictionary < string , ReadOnlyBindingInfo >
307+ {
308+ {
309+ bindingName ,
310+ new ReadOnlyBindingInfo ( bindingType , bindingDirection )
311+ }
312+ } ) ) ;
313+ }
314+
223315 private HistoryEvent [ ] CreateHistory ( bool scheduled , bool completed , string output )
224316 {
225317 return CreateHistory ( FunctionName , scheduled , completed , output ) ;
0 commit comments