5
5
using System . Collections . Generic ;
6
6
using System . IO ;
7
7
using System . Linq ;
8
+ using System . Reflection ;
8
9
using System . Threading . Tasks ;
9
10
using Microsoft . AspNetCore . Hosting ;
10
11
using Microsoft . Azure . WebJobs . Script . Description ;
13
14
using Microsoft . Azure . WebJobs . Script . ManagedDependencies ;
14
15
using Microsoft . Azure . WebJobs . Script . Workers ;
15
16
using Microsoft . Azure . WebJobs . Script . Workers . Rpc ;
17
+ using Microsoft . Extensions . Logging ;
16
18
using Microsoft . Extensions . Options ;
19
+ using Microsoft . WebJobs . Script . Tests ;
17
20
using Moq ;
18
21
using Xunit ;
19
22
using FunctionMetadata = Microsoft . Azure . WebJobs . Script . Description . FunctionMetadata ;
@@ -23,7 +26,18 @@ namespace Microsoft.Azure.WebJobs.Script.Tests.Workers.Rpc
23
26
public class RpcFunctionInvocationDispatcherTests
24
27
{
25
28
private static TestRpcWorkerChannel _javaTestChannel ;
26
- private static TestLogger _testLogger = new TestLogger ( "FunctionDispatcherTests" ) ;
29
+ private static ILogger _testLogger ;
30
+ private static TestLoggerProvider _testLoggerProvider ;
31
+ private static LoggerFactory _testLoggerFactory ;
32
+
33
+ public RpcFunctionInvocationDispatcherTests ( )
34
+ {
35
+ _testLoggerProvider = new TestLoggerProvider ( ) ;
36
+ _testLoggerFactory = new LoggerFactory ( ) ;
37
+ _testLoggerFactory . AddProvider ( _testLoggerProvider ) ;
38
+
39
+ _testLogger = _testLoggerProvider . CreateLogger ( "FunctionDispatcherTests" ) ;
40
+ }
27
41
28
42
[ Fact ]
29
43
public async Task GetWorkerStatusesAsync_ReturnsExpectedResult ( )
@@ -47,18 +61,22 @@ public async Task GetWorkerStatusesAsync_ReturnsExpectedResult()
47
61
[ Fact ]
48
62
public async Task Starting_MultipleJobhostChannels_Succeeds ( )
49
63
{
64
+ _testLoggerProvider . ClearAllLogMessages ( ) ;
50
65
int expectedProcessCount = 3 ;
51
66
RpcFunctionInvocationDispatcher functionDispatcher = GetTestFunctionDispatcher ( expectedProcessCount ) ;
52
67
await functionDispatcher . InitializeAsync ( GetTestFunctionsList ( RpcWorkerConstants . NodeLanguageWorkerName ) ) ;
53
68
54
69
var finalChannelCount = await WaitForJobhostWorkerChannelsToStartup ( functionDispatcher , expectedProcessCount ) ;
55
70
Assert . Equal ( expectedProcessCount , finalChannelCount ) ;
71
+
72
+ VerifyStartIntervals ( TimeSpan . FromSeconds ( 10 ) , TimeSpan . FromSeconds ( 15 ) ) ;
56
73
}
57
74
58
75
[ Fact ]
59
76
public async Task Starting_MultipleWebhostChannels_Succeeds ( )
60
77
{
61
- int expectedProcessCount = 2 ;
78
+ _testLoggerProvider . ClearAllLogMessages ( ) ;
79
+ int expectedProcessCount = 3 ;
62
80
RpcFunctionInvocationDispatcher functionDispatcher = GetTestFunctionDispatcher ( expectedProcessCount , true ) ;
63
81
await functionDispatcher . InitializeAsync ( GetTestFunctionsList ( RpcWorkerConstants . JavaLanguageWorkerName ) ) ;
64
82
@@ -67,6 +85,26 @@ public async Task Starting_MultipleWebhostChannels_Succeeds()
67
85
68
86
var finalJobhostChannelCount = functionDispatcher . JobHostLanguageWorkerChannelManager . GetChannels ( ) . Count ( ) ;
69
87
Assert . Equal ( 0 , finalJobhostChannelCount ) ;
88
+
89
+ // ignore first start as we added a WebhostChannel on GetTestFunctionDispatcher call
90
+ VerifyStartIntervals ( TimeSpan . FromSeconds ( 10 ) , TimeSpan . FromSeconds ( 15 ) , true ) ;
91
+ }
92
+
93
+ [ Fact ]
94
+ public async Task Starting_MultipleJobhostChannels_Failed ( )
95
+ {
96
+ _testLoggerProvider . ClearAllLogMessages ( ) ;
97
+ int expectedProcessCount = 3 ;
98
+ RpcFunctionInvocationDispatcher functionDispatcher = GetTestFunctionDispatcher ( expectedProcessCount , throwOnProcessStartUp : true ) ;
99
+ await functionDispatcher . InitializeAsync ( GetTestFunctionsList ( RpcWorkerConstants . NodeLanguageWorkerName ) ) ;
100
+
101
+ var finalChannelCount = await WaitForJobhostWorkerChannelsToStartup ( functionDispatcher , expectedProcessCount , false ) ;
102
+ Assert . Equal ( expectedProcessCount , finalChannelCount ) ;
103
+
104
+ var logMessages = _testLoggerProvider . GetAllLogMessages ( ) . ToList ( ) ;
105
+
106
+ Assert . Equal ( logMessages . Where ( x => x . FormattedMessage
107
+ . Contains ( "Failed to start a new language worker" ) ) . Count ( ) , 3 ) ;
70
108
}
71
109
72
110
[ Fact ]
@@ -421,7 +459,7 @@ public async Task FunctionDispatcher_DoNot_Restart_ErroredChannels_If_WorkerRunt
421
459
await functionDispatcher . InitializeAsync ( GetTestFunctionsList ( RpcWorkerConstants . NodeLanguageWorkerName ) ) ;
422
460
await WaitForJobhostWorkerChannelsToStartup ( functionDispatcher , expectedProcessCount ) ;
423
461
_javaTestChannel . RaiseWorkerError ( ) ;
424
- var testLogs = _testLogger . GetLogMessages ( ) ;
462
+ var testLogs = _testLoggerProvider . GetAllLogMessages ( ) ;
425
463
Assert . False ( testLogs . Any ( m => m . FormattedMessage . Contains ( "Restarting worker channel for runtime:java" ) ) ) ;
426
464
Assert . Equal ( expectedProcessCount , functionDispatcher . JobHostLanguageWorkerChannelManager . GetChannels ( ) . Count ( ) ) ;
427
465
}
@@ -449,10 +487,11 @@ public async Task FunctionDispatcher_ShouldRestartChannel_Returns_True(string wo
449
487
[ Fact ]
450
488
public async Task FunctionDispatcher_ErroredWebHostChannel ( )
451
489
{
490
+ _testLoggerProvider . ClearAllLogMessages ( ) ;
452
491
RpcFunctionInvocationDispatcher functionDispatcher = GetTestFunctionDispatcher ( throwOnProcessStartUp : true , addWebhostChannel : true ) ;
453
492
await functionDispatcher . InitializeAsync ( GetTestFunctionsList ( RpcWorkerConstants . JavaLanguageWorkerName ) ) ;
454
- var testLogs = _testLogger . GetLogMessages ( ) ;
455
- Assert . False ( testLogs . Any ( m => m . FormattedMessage . Contains ( "Removing errored webhost language worker channel for runtime" ) ) ) ;
493
+ var testLogs = _testLoggerProvider . GetAllLogMessages ( ) ;
494
+ Assert . True ( testLogs . Any ( m => m . FormattedMessage . Contains ( "Removing errored webhost language worker channel for runtime" ) ) ) ;
456
495
}
457
496
458
497
private static RpcFunctionInvocationDispatcher GetTestFunctionDispatcher ( int maxProcessCountValue = 1 , bool addWebhostChannel = false , Mock < IWebHostRpcWorkerChannelManager > mockwebHostLanguageWorkerChannelManager = null , bool throwOnProcessStartUp = false )
@@ -464,8 +503,6 @@ private static RpcFunctionInvocationDispatcher GetTestFunctionDispatcher(int max
464
503
465
504
testEnv . SetEnvironmentVariable ( RpcWorkerConstants . FunctionsWorkerProcessCountSettingName , maxProcessCountValue . ToString ( ) ) ;
466
505
467
- var loggerFactory = MockNullLoggerFactory . CreateLoggerFactory ( ) ;
468
-
469
506
var options = new ScriptJobHostOptions
470
507
{
471
508
RootLogPath = Path . GetTempPath ( )
@@ -479,7 +516,7 @@ private static RpcFunctionInvocationDispatcher GetTestFunctionDispatcher(int max
479
516
} ;
480
517
IRpcWorkerChannelFactory testLanguageWorkerChannelFactory = new TestRpcWorkerChannelFactory ( eventManager , _testLogger , scriptOptions . Value . RootScriptPath , throwOnProcessStartUp ) ;
481
518
IWebHostRpcWorkerChannelManager testWebHostLanguageWorkerChannelManager = new TestRpcWorkerChannelManager ( eventManager , _testLogger , scriptOptions . Value . RootScriptPath , testLanguageWorkerChannelFactory ) ;
482
- IJobHostRpcWorkerChannelManager jobHostLanguageWorkerChannelManager = new JobHostRpcWorkerChannelManager ( loggerFactory ) ;
519
+ IJobHostRpcWorkerChannelManager jobHostLanguageWorkerChannelManager = new JobHostRpcWorkerChannelManager ( _testLoggerFactory ) ;
483
520
if ( addWebhostChannel )
484
521
{
485
522
testWebHostLanguageWorkerChannelManager . InitializeChannelAsync ( "java" ) ;
@@ -497,7 +534,7 @@ private static RpcFunctionInvocationDispatcher GetTestFunctionDispatcher(int max
497
534
testEnv ,
498
535
mockApplicationLifetime . Object ,
499
536
eventManager ,
500
- loggerFactory ,
537
+ _testLoggerFactory ,
501
538
testLanguageWorkerChannelFactory ,
502
539
optionsMonitor ,
503
540
testWebHostLanguageWorkerChannelManager ,
@@ -506,15 +543,17 @@ private static RpcFunctionInvocationDispatcher GetTestFunctionDispatcher(int max
506
543
mockFunctionDispatcherLoadBalancer . Object ) ;
507
544
}
508
545
509
- private async Task < int > WaitForJobhostWorkerChannelsToStartup ( RpcFunctionInvocationDispatcher functionDispatcher , int expectedCount )
546
+ private async Task < int > WaitForJobhostWorkerChannelsToStartup ( RpcFunctionInvocationDispatcher functionDispatcher , int expectedCount , bool allReadyForInvocations = true )
510
547
{
511
548
int currentChannelCount = 0 ;
512
549
await TestHelpers . Await ( ( ) =>
513
550
{
514
551
currentChannelCount = functionDispatcher . JobHostLanguageWorkerChannelManager . GetChannels ( ) . Count ( ) ;
515
552
if ( currentChannelCount == expectedCount )
516
553
{
517
- return functionDispatcher . JobHostLanguageWorkerChannelManager . GetChannels ( ) . All ( ch => ch . IsChannelReadyForInvocations ( ) ) ;
554
+ var channels = functionDispatcher . JobHostLanguageWorkerChannelManager . GetChannels ( ) ;
555
+
556
+ return allReadyForInvocations ? channels . All ( ch => ch . IsChannelReadyForInvocations ( ) ) : true ;
518
557
}
519
558
return false ;
520
559
} , pollingInterval : expectedCount * 5 * 1000 , timeout : 60 * 1000 ) ;
@@ -562,5 +601,20 @@ private IEnumerable<FunctionMetadata> GetTestFunctionsList(string runtime)
562
601
}
563
602
} ;
564
603
}
604
+
605
+ private void VerifyStartIntervals ( TimeSpan from , TimeSpan to , bool ignoreFirstStart = false )
606
+ {
607
+ var startTimestamps = _testLoggerProvider . GetAllLogMessages ( ) . Where ( x => x . FormattedMessage
608
+ . Contains ( "RegisterFunctions called" ) ) . Select ( x => x . Timestamp ) . ToList ( ) ;
609
+ if ( ignoreFirstStart )
610
+ {
611
+ startTimestamps . RemoveAt ( 0 ) ;
612
+ }
613
+ for ( int i = 1 ; i < startTimestamps . Count ( ) ; i ++ )
614
+ {
615
+ var diff = startTimestamps [ i ] - startTimestamps [ i - 1 ] ;
616
+ Assert . True ( diff > from && diff < to ) ;
617
+ }
618
+ }
565
619
}
566
620
}
0 commit comments