@@ -6,6 +6,7 @@ import * as sinon from 'sinon';
6
6
import { AzureFunctionsRpcMessages as rpc } from '../azure-functions-language-worker-protobuf/src/rpc' ;
7
7
import 'mocha' ;
8
8
import { load } from 'grpc' ;
9
+ < < < << << HEAD
9
10
import { FunctionInfo } from '../src/FunctionInfo' ;
10
11
11
12
describe ( 'WorkerChannel' , ( ) => {
@@ -85,6 +86,75 @@ describe('WorkerChannel', () => {
85
86
test : orchestrationTriggerBinding
86
87
}
87
88
} ;
89
+ = === ===
90
+ import { worker } from 'cluster' ;
91
+
92
+ describe ( 'WorkerChannel' , ( ) => {
93
+ var channel : WorkerChannel ;
94
+ var stream : TestEventStream ;
95
+ var loader : sinon . SinonStubbedInstance < FunctionLoader > ;
96
+ var functions ;
97
+
98
+ const runInvokedFunction = ( ) => {
99
+ const triggerDataMock : { [ k : string ] : rpc . ITypedData } = {
100
+ "Headers" : {
101
+ json : JSON . stringify ( { Connection : 'Keep-Alive' } )
102
+ } ,
103
+ "Sys" : {
104
+ json : JSON . stringify ( { MethodName : 'test-js' , UtcNow : '2018' , RandGuid : '3212' } )
105
+ }
106
+ } ;
107
+
108
+ const inputDataValue = {
109
+ name : "req" ,
110
+ data : {
111
+ data : "http" ,
112
+ http :
113
+ {
114
+ body :
115
+ {
116
+ data : "string" ,
117
+ body : "blahh"
118
+ } ,
119
+ rawBody :
120
+ {
121
+ data : "string" ,
122
+ body : "blahh"
123
+ }
124
+ }
125
+ }
126
+ } ;
127
+
128
+ const actualInvocationRequest : rpc . IInvocationRequest = < rpc . IInvocationRequest > {
129
+ functionId : 'id' ,
130
+ invocationId : '1' ,
131
+ inputData : [ inputDataValue ] ,
132
+ triggerMetadata : triggerDataMock ,
133
+ } ;
134
+
135
+ stream . addTestMessage ( {
136
+ invocationRequest : actualInvocationRequest
137
+ } ) ;
138
+
139
+ return [ inputDataValue , actualInvocationRequest ] ;
140
+ }
141
+
142
+ const assertInvokedFunction = ( inputDataValue , actualInvocationRequest ) => {
143
+ sinon . assert . calledWithMatch ( stream . written , < rpc . IStreamingMessage > {
144
+ invocationResponse : {
145
+ invocationId : '1' ,
146
+ result : {
147
+ status : rpc . StatusResult . Status . Success
148
+ } ,
149
+ outputData : [ ]
150
+ }
151
+ } ) ;
152
+
153
+ // triggerMedata will be augmented with inpuDataValue since "RpcHttpTriggerMetadataRemoved" capability is set to true and therefore not populated by the host.
154
+ expect ( JSON . stringify ( actualInvocationRequest . triggerMetadata ! . $request ) ) . to . equal ( JSON . stringify ( inputDataValue . data ) ) ;
155
+ expect ( JSON . stringify ( actualInvocationRequest . triggerMetadata ! . req ) ) . to . equal ( JSON . stringify ( inputDataValue . data ) ) ;
156
+ }
157
+ >>> > >>> 0 ff6fb4 ... feature : add before / after InvocationRequest hooks ( #339 )
88
158
89
159
beforeEach ( ( ) => {
90
160
stream = new TestEventStream ( ) ;
@@ -378,7 +448,14 @@ describe('WorkerChannel', () => {
378
448
expect ( JSON . stringify ( actualInvocationRequest . triggerMetadata ! . $request ) ) . to . equal ( JSON . stringify ( httpInputData . data ) ) ;
379
449
expect ( JSON . stringify ( actualInvocationRequest . triggerMetadata ! . req ) ) . to . equal ( JSON . stringify ( httpInputData . data ) ) ;
380
450
} ) ;
451
+
452
+ describe ( '#invocationRequestBefore, #invocationRequestAfter' , ( ) => {
453
+ afterEach ( ( ) => {
454
+ channel [ '_invocationRequestAfter' ] = [ ] ;
455
+ channel [ '_invocationRequestBefore' ] = [ ] ;
456
+ } ) ;
381
457
458
+ < < < << << HEAD
382
459
it ( 'invokes function' , ( ) => {
383
460
loader . getFunc . returns ( ( context ) => context . done ( ) ) ;
384
461
loader . getInfo . returns ( new FunctionInfo ( orchestratorBinding ) ) ;
@@ -529,11 +606,102 @@ describe('WorkerChannel', () => {
529
606
inputData : [ httpInputData ] ,
530
607
triggerMetadata : getTriggerDataMock ( ) ,
531
608
} ;
609
+ = === ===
610
+ it ( "should apply hook before user function is executed" , ( ) => {
611
+ channel . registerBeforeInvocationRequest ( ( context , userFunction ) => {
612
+ context [ 'magic_flag' ] = 'magic value' ;
613
+ return userFunction . bind ( { __wrapped : true } ) ;
614
+ } ) ;
615
+
616
+ channel . registerBeforeInvocationRequest ( ( context , userFunction ) => {
617
+ context [ "secondary_flag" ] = 'magic value' ;
618
+ return userFunction ;
619
+ } ) ;
532
620
533
- stream . addTestMessage ( {
534
- invocationRequest : actualInvocationRequest
621
+ loader . getFunc . returns ( function ( this : any , context ) {
622
+ expect ( context [ 'magic_flag' ] ) . to . equal ( 'magic value' ) ;
623
+ expect ( context [ 'secondary_flag' ] ) . to . equal ( 'magic value' ) ;
624
+ expect ( this . __wrapped ) . to . equal ( true ) ;
625
+ expect ( channel [ '_invocationRequestBefore' ] . length ) . to . equal ( 2 ) ;
626
+ expect ( channel [ '_invocationRequestAfter' ] . length ) . to . equal ( 0 ) ;
627
+ context . done ( ) ;
628
+ } ) ;
629
+ loader . getInfo . returns ( {
630
+ name : 'test' ,
631
+ outputBindings : { }
632
+ } ) ;
633
+
634
+ const [ inputDataValue , actualInvocationRequest ] = runInvokedFunction ( ) ;
635
+ assertInvokedFunction ( inputDataValue , actualInvocationRequest ) ;
535
636
} ) ;
637
+
638
+ it ( 'should apply hook after user function is executed (callback)' , ( done ) => {
639
+ let finished = false ;
640
+ let count = 0 ;
641
+ channel . registerAfterInvocationRequest ( ( context ) => {
642
+ expect ( finished ) . to . equal ( true ) ;
643
+ count += 1 ;
644
+ } ) ;
645
+
646
+ loader . getFunc . returns ( function ( this : any , context ) {
647
+ finished = true ;
648
+ expect ( channel [ '_invocationRequestBefore' ] . length ) . to . equal ( 0 ) ;
649
+ expect ( channel [ '_invocationRequestAfter' ] . length ) . to . equal ( 1 ) ;
650
+ expect ( count ) . to . equal ( 0 ) ;
651
+ context . done ( ) ;
652
+ expect ( count ) . to . equal ( 1 ) ;
653
+ done ( ) ;
654
+ } ) ;
655
+ loader . getInfo . returns ( {
656
+ name : 'test' ,
657
+ outputBindings : { }
658
+ } ) ;
536
659
660
+ const [ inputDataValue , actualInvocationRequest ] = runInvokedFunction ( ) ;
661
+ assertInvokedFunction ( inputDataValue , actualInvocationRequest ) ;
662
+ } ) ;
663
+
664
+ it ( 'should apply hook after user function resolves (promise)' , ( done ) => {
665
+ let finished = false ;
666
+ let count = 0 ;
667
+ let inputDataValue , actualInvocationRequest ;
668
+ channel . registerAfterInvocationRequest ( ( context ) => {
669
+ expect ( finished ) . to . equal ( true ) ;
670
+ count += 1 ;
671
+ expect ( count ) . to . equal ( 1 ) ;
672
+ assertInvokedFunction ( inputDataValue , actualInvocationRequest ) ;
673
+ done ( ) ;
674
+ } ) ;
675
+ > >>> >>> 0 ff6fb4 ... feature: add before / after InvocationRequest hooks ( #339 )
676
+
677
+ loader . getFunc . returns ( ( ) => new Promise ( ( resolve ) => {
678
+ finished = true ;
679
+ expect ( channel [ '_invocationRequestBefore' ] . length ) . to . equal ( 0 ) ;
680
+ expect ( channel [ '_invocationRequestAfter' ] . length ) . to . equal ( 1 ) ;
681
+ expect ( count ) . to . equal ( 0 ) ;
682
+ resolve ( ) ;
683
+ } ) ) ;
684
+ loader . getInfo . returns ( {
685
+ name : 'test' ,
686
+ outputBindings : { }
687
+ } ) ;
688
+
689
+ [ inputDataValue , actualInvocationRequest ] = runInvokedFunction ( ) ;
690
+ } ) ;
691
+
692
+
693
+ it ( 'should apply hook after user function rejects (promise)' , ( done ) => {
694
+ let finished = false ;
695
+ let count = 0 ;
696
+ channel . registerAfterInvocationRequest ( ( context ) => {
697
+ expect ( finished ) . to . equal ( true ) ;
698
+ count += 1 ;
699
+ expect ( count ) . to . equal ( 1 ) ;
700
+ assertInvokedFunction ( inputDataValue , actualInvocationRequest ) ;
701
+ done ( ) ;
702
+ } ) ;
703
+
704
+ < < < << << HEAD
537
705
sinon . assert. calledWithMatch ( stream . written , < rpc . IStreamingMessage > {
538
706
invocationResponse : {
539
707
invocationId : '1' ,
@@ -682,6 +850,33 @@ describe('WorkerChannel', () => {
682
850
}
683
851
}
684
852
} ) ;
853
+ = === ===
854
+ loader . getFunc . returns ( ( context ) => new Promise ( ( _ , reject ) => {
855
+ finished = true ;
856
+ expect ( channel [ '_invocationRequestBefore' ] . length ) . to . equal ( 0 ) ;
857
+ expect ( channel [ '_invocationRequestAfter' ] . length ) . to . equal ( 1 ) ;
858
+ expect ( count ) . to . equal ( 0 ) ;
859
+ reject ( ) ;
860
+ } ) ) ;
861
+ loader . getInfo . returns ( {
862
+ name : 'test' ,
863
+ outputBindings : { }
864
+ } ) ;
865
+
866
+ const [ inputDataValue , actualInvocationRequest ] = runInvokedFunction ( ) ;
867
+ } ) ;
868
+ } ) ;
869
+
870
+ it ( 'invokes function' , ( ) => {
871
+ loader . getFunc . returns ( ( context ) => context . done ( ) ) ;
872
+ loader . getInfo . returns ( {
873
+ name : 'test' ,
874
+ outputBindings : { }
875
+ } )
876
+
877
+ const [ inputDataValue , actualInvocationRequest ] = runInvokedFunction ( ) ;
878
+ assertInvokedFunction ( inputDataValue , actualInvocationRequest ) ;
879
+ > >>> >>> 0 ff6fb4 ... feature: add before / after InvocationRequest hooks ( #339 )
685
880
} ) ;
686
881
687
882
it ( 'throws for malformed messages' , ( ) => {
0 commit comments