@@ -661,15 +661,63 @@ test('"onError" middleware should be able to short circuit response', async (t)
661
661
} )
662
662
663
663
// streamifyResponse
664
+
665
+ // mock implementation awslambda.HttpResponseStream
666
+ const DELIMITER_LEN = 8
664
667
globalThis . awslambda = {
665
668
streamifyResponse : ( cb ) => cb ,
666
669
HttpResponseStream : {
667
- from : ( responseStream , metadata ) => {
668
- return responseStream
670
+ from : ( underlyingStream , prelude ) => {
671
+ // https://github.com/aws/aws-lambda-nodejs-runtime-interface-client/blob/main/src/HttpResponseStream.js
672
+ // Wrap the underlyingStream to ensure _onBeforeFirstWrite is called before the first write operation
673
+ const wrapStream = ( ) => {
674
+ let isFirstWrite = true
675
+ const originalWrite = underlyingStream . write
676
+ underlyingStream . write = ( ...args ) => {
677
+ if (
678
+ isFirstWrite &&
679
+ typeof underlyingStream . _onBeforeFirstWrite === 'function'
680
+ ) {
681
+ isFirstWrite = false
682
+ underlyingStream . _onBeforeFirstWrite ( )
683
+ }
684
+ return originalWrite . apply ( underlyingStream , args )
685
+ }
686
+
687
+ return underlyingStream
688
+ }
689
+
690
+ // Execute _onBeforeFirstWrite before the first write operation
691
+ underlyingStream . _onBeforeFirstWrite = ( ) => {
692
+ const metadataPrelude = JSON . stringify ( prelude )
693
+ underlyingStream . write ( metadataPrelude )
694
+ underlyingStream . write ( new Uint8Array ( DELIMITER_LEN ) )
695
+ }
696
+ return wrapStream ( )
669
697
}
670
698
}
671
699
}
672
700
701
+ function createResponseStreamMockAndCapture ( ) {
702
+ function processChunkResponse ( chunkResponse ) {
703
+ const indexOf = chunkResponse . indexOf ( new Uint8Array ( DELIMITER_LEN ) )
704
+ const prelude = chunkResponse . slice ( 0 , indexOf )
705
+ const content = chunkResponse . slice ( indexOf + DELIMITER_LEN * 2 - 1 )
706
+ return { prelude, content }
707
+ }
708
+
709
+ let chunkResponse = ''
710
+ const responseStream = createWritableStream ( ( chunk ) => {
711
+ chunkResponse += chunk
712
+ } )
713
+ return {
714
+ responseStream,
715
+ chunkResponse : ( ) => chunkResponse ,
716
+ prelude : ( ) => processChunkResponse ( chunkResponse ) . prelude ,
717
+ content : ( ) => processChunkResponse ( chunkResponse ) . content
718
+ }
719
+ }
720
+
673
721
test ( 'Should throw with streamifyResponse:true using object' , async ( t ) => {
674
722
const input = { }
675
723
const handler = middy (
@@ -692,27 +740,28 @@ test('Should throw with streamifyResponse:true using object', async (t) => {
692
740
693
741
test ( 'Should return with streamifyResponse:true using body undefined' , async ( t ) => {
694
742
const input = ''
743
+ const metadata = {
744
+ statusCode : 200 ,
745
+ headers : {
746
+ 'Content-Type' : 'plain/text'
747
+ }
748
+ }
695
749
const handler = middy (
696
750
( event , context , { signal } ) => {
697
- return {
698
- statusCode : 200 ,
699
- headers : {
700
- 'Content-Type' : 'plain/text'
701
- }
702
- }
751
+ return metadata
703
752
} ,
704
753
{
705
754
streamifyResponse : true
706
755
}
707
756
)
708
757
709
- let chunkResponse = ''
710
- const responseStream = createWritableStream ( ( chunk ) => {
711
- chunkResponse += chunk
712
- } )
758
+ const { responseStream, prelude, content } =
759
+ createResponseStreamMockAndCapture ( )
760
+
713
761
const response = await handler ( event , responseStream , context )
714
762
t . is ( response , undefined )
715
- t . is ( chunkResponse , input )
763
+ t . is ( prelude ( ) , JSON . stringify ( metadata ) )
764
+ t . is ( content ( ) , input )
716
765
} )
717
766
718
767
test ( 'Should return with streamifyResponse:true using string' , async ( t ) => {
@@ -723,13 +772,11 @@ test('Should return with streamifyResponse:true using string', async (t) => {
723
772
return input
724
773
} )
725
774
726
- let chunkResponse = ''
727
- const responseStream = createWritableStream ( ( chunk ) => {
728
- chunkResponse += chunk
729
- } )
775
+ const { responseStream, chunkResponse } = createResponseStreamMockAndCapture ( )
776
+
730
777
const response = await handler ( event , responseStream , context )
731
778
t . is ( response , undefined )
732
- t . is ( chunkResponse , input )
779
+ t . is ( chunkResponse ( ) , input )
733
780
} )
734
781
735
782
test ( 'Should return with streamifyResponse:true using body string' , async ( t ) => {
@@ -746,13 +793,39 @@ test('Should return with streamifyResponse:true using body string', async (t) =>
746
793
}
747
794
} )
748
795
749
- let chunkResponse = ''
750
- const responseStream = createWritableStream ( ( chunk ) => {
751
- chunkResponse += chunk
796
+ const { responseStream, content } = createResponseStreamMockAndCapture ( )
797
+ const response = await handler ( event , responseStream , context )
798
+ t . is ( response , undefined )
799
+ t . is ( content ( ) , input )
800
+ } )
801
+
802
+ test ( 'Should return with streamifyResponse:true using empty body string and prelude' , async ( t ) => {
803
+ const input = ''
804
+ const metadata = {
805
+ statusCode : 301 ,
806
+ headers : {
807
+ 'Content-Type' : 'plain/text' ,
808
+ Location : 'https://example.com'
809
+ }
810
+ }
811
+
812
+ const handler = middy ( {
813
+ streamifyResponse : true
814
+ } ) . handler ( ( event , context , { signal } ) => {
815
+ return {
816
+ ...metadata ,
817
+ body : input
818
+ }
752
819
} )
820
+
821
+ const { responseStream, prelude, content } =
822
+ createResponseStreamMockAndCapture ( )
823
+
753
824
const response = await handler ( event , responseStream , context )
825
+
754
826
t . is ( response , undefined )
755
- t . is ( chunkResponse , input )
827
+ t . is ( prelude ( ) , JSON . stringify ( metadata ) )
828
+ t . is ( content ( ) , input )
756
829
} )
757
830
758
831
test ( 'Should return with streamifyResponse:true using ReadableStream' , async ( t ) => {
@@ -766,13 +839,10 @@ test('Should return with streamifyResponse:true using ReadableStream', async (t)
766
839
}
767
840
)
768
841
769
- let chunkResponse = ''
770
- const responseStream = createWritableStream ( ( chunk ) => {
771
- chunkResponse += chunk
772
- } )
842
+ const { responseStream, chunkResponse } = createResponseStreamMockAndCapture ( )
773
843
const response = await handler ( event , responseStream , context )
774
844
t . is ( response , undefined )
775
- t . is ( chunkResponse , input )
845
+ t . is ( chunkResponse ( ) , input )
776
846
} )
777
847
778
848
test ( 'Should return with streamifyResponse:true using body ReadableStream' , async ( t ) => {
@@ -792,13 +862,10 @@ test('Should return with streamifyResponse:true using body ReadableStream', asyn
792
862
}
793
863
)
794
864
795
- let chunkResponse = ''
796
- const responseStream = createWritableStream ( ( chunk ) => {
797
- chunkResponse += chunk
798
- } )
865
+ const { responseStream, content } = createResponseStreamMockAndCapture ( )
799
866
const response = await handler ( event , responseStream , context )
800
867
t . is ( response , undefined )
801
- t . is ( chunkResponse , input )
868
+ t . is ( content ( ) , input )
802
869
} )
803
870
804
871
test ( 'Should return with streamifyResponse:true using ReadableStream.pipe(...)' , async ( t ) => {
@@ -812,13 +879,10 @@ test('Should return with streamifyResponse:true using ReadableStream.pipe(...)',
812
879
}
813
880
)
814
881
815
- let chunkResponse = ''
816
- const responseStream = createWritableStream ( ( chunk ) => {
817
- chunkResponse += chunk
818
- } )
882
+ const { responseStream, chunkResponse } = createResponseStreamMockAndCapture ( )
819
883
const response = await handler ( event , responseStream , context )
820
884
t . is ( response , undefined )
821
- t . is ( chunkResponse , input )
885
+ t . is ( chunkResponse ( ) , input )
822
886
} )
823
887
824
888
test ( 'Should return with streamifyResponse:true using body ReadableStream.pipe(...)' , async ( t ) => {
@@ -838,13 +902,10 @@ test('Should return with streamifyResponse:true using body ReadableStream.pipe(.
838
902
}
839
903
)
840
904
841
- let chunkResponse = ''
842
- const responseStream = createWritableStream ( ( chunk ) => {
843
- chunkResponse += chunk
844
- } )
905
+ const { responseStream, content } = createResponseStreamMockAndCapture ( )
845
906
const response = await handler ( event , responseStream , context )
846
907
t . is ( response , undefined )
847
- t . is ( chunkResponse , input )
908
+ t . is ( content ( ) , input )
848
909
} )
849
910
850
911
// Plugin
0 commit comments