@@ -4,6 +4,7 @@ const { tspl } = require('@matteo.collina/tspl')
44const { test, after } = require ( 'node:test' )
55const { createServer } = require ( 'node:http' )
66const { once } = require ( 'node:events' )
7+ const { Readable } = require ( 'node:stream' )
78
89const { RetryHandler, Client } = require ( '..' )
910const { RequestHandler } = require ( '../lib/api/api-request' )
@@ -204,6 +205,74 @@ test('Should account for network and response errors', async t => {
204205 await t . completed
205206} )
206207
208+ test ( 'Issue #3288 - request with body (asynciterable)' , async t => {
209+ t = tspl ( t , { plan : 6 } )
210+ const server = createServer ( )
211+ const dispatchOptions = {
212+ method : 'POST' ,
213+ path : '/' ,
214+ headers : {
215+ 'content-type' : 'application/json'
216+ } ,
217+ body : ( function * ( ) {
218+ yield 'hello'
219+ yield 'world'
220+ } ) ( )
221+ }
222+
223+ server . on ( 'request' , ( req , res ) => {
224+ res . writeHead ( 500 , {
225+ 'content-type' : 'application/json'
226+ } )
227+
228+ res . end ( '{"message": "failed"}' )
229+ } )
230+
231+ server . listen ( 0 , ( ) => {
232+ const client = new Client ( `http://localhost:${ server . address ( ) . port } ` )
233+ const handler = new RetryHandler ( dispatchOptions , {
234+ dispatch : client . dispatch . bind ( client ) ,
235+ handler : {
236+ onConnect ( ) {
237+ t . ok ( true , 'pass' )
238+ } ,
239+ onBodySent ( ) {
240+ t . ok ( true , 'pass' )
241+ } ,
242+ onHeaders ( status , _rawHeaders , resume , _statusMessage ) {
243+ t . strictEqual ( status , 500 )
244+ return true
245+ } ,
246+ onData ( chunk ) {
247+ return true
248+ } ,
249+ onComplete ( ) {
250+ t . fail ( )
251+ } ,
252+ onError ( err ) {
253+ t . equal ( err . message , 'Request failed' )
254+ t . equal ( err . statusCode , 500 )
255+ t . equal ( err . data . count , 1 )
256+ }
257+ }
258+ } )
259+
260+ after ( async ( ) => {
261+ await client . close ( )
262+ server . close ( )
263+
264+ await once ( server , 'close' )
265+ } )
266+
267+ client . dispatch (
268+ dispatchOptions ,
269+ handler
270+ )
271+ } )
272+
273+ await t . completed
274+ } )
275+
207276test ( 'Should use retry-after header for retries' , async t => {
208277 t = tspl ( t , { plan : 4 } )
209278
@@ -734,6 +803,145 @@ test('retrying a request with a body', async t => {
734803 await t . completed
735804} )
736805
806+ test ( 'retrying a request with a body (stream)' , async t => {
807+ let counter = 0
808+ const server = createServer ( )
809+ const dispatchOptions = {
810+ retryOptions : {
811+ retry : ( err , { state, opts } , done ) => {
812+ counter ++
813+
814+ if (
815+ err . statusCode === 500 ||
816+ err . message . includes ( 'other side closed' )
817+ ) {
818+ setTimeout ( done , 500 )
819+ return
820+ }
821+
822+ return done ( err )
823+ }
824+ } ,
825+ method : 'POST' ,
826+ path : '/' ,
827+ headers : {
828+ 'content-type' : 'application/json'
829+ } ,
830+ body : Readable . from ( Buffer . from ( JSON . stringify ( { hello : 'world' } ) ) )
831+ }
832+
833+ t = tspl ( t , { plan : 3 } )
834+
835+ server . on ( 'request' , ( req , res ) => {
836+ switch ( counter ) {
837+ case 0 :
838+ res . writeHead ( 500 )
839+ res . end ( 'failed' )
840+ return
841+ default :
842+ t . fail ( )
843+ }
844+ } )
845+
846+ server . listen ( 0 , ( ) => {
847+ const client = new Client ( `http://localhost:${ server . address ( ) . port } ` )
848+ const handler = new RetryHandler ( dispatchOptions , {
849+ dispatch : client . dispatch . bind ( client ) ,
850+ handler : new RequestHandler ( dispatchOptions , ( err , data ) => {
851+ t . equal ( err . statusCode , 500 )
852+ t . equal ( err . data . count , 1 )
853+ t . equal ( err . code , 'UND_ERR_REQ_RETRY' )
854+ } )
855+ } )
856+
857+ after ( async ( ) => {
858+ await client . close ( )
859+ server . close ( )
860+
861+ await once ( server , 'close' )
862+ } )
863+
864+ client . dispatch (
865+ dispatchOptions ,
866+ handler
867+ )
868+ } )
869+
870+ await t . completed
871+ } )
872+
873+ test ( 'retrying a request with a body (buffer)' , async t => {
874+ let counter = 0
875+ const server = createServer ( )
876+ const dispatchOptions = {
877+ retryOptions : {
878+ retry : ( err , { state, opts } , done ) => {
879+ counter ++
880+
881+ if (
882+ err . statusCode === 500 ||
883+ err . message . includes ( 'other side closed' )
884+ ) {
885+ setTimeout ( done , 500 )
886+ return
887+ }
888+
889+ return done ( err )
890+ }
891+ } ,
892+ method : 'POST' ,
893+ path : '/' ,
894+ headers : {
895+ 'content-type' : 'application/json'
896+ } ,
897+ body : Buffer . from ( JSON . stringify ( { hello : 'world' } ) )
898+ }
899+
900+ t = tspl ( t , { plan : 1 } )
901+
902+ server . on ( 'request' , ( req , res ) => {
903+ switch ( counter ) {
904+ case 0 :
905+ req . destroy ( )
906+ return
907+ case 1 :
908+ res . writeHead ( 500 )
909+ res . end ( 'failed' )
910+ return
911+ case 2 :
912+ res . writeHead ( 200 )
913+ res . end ( 'hello world!' )
914+ return
915+ default :
916+ t . fail ( )
917+ }
918+ } )
919+
920+ server . listen ( 0 , ( ) => {
921+ const client = new Client ( `http://localhost:${ server . address ( ) . port } ` )
922+ const handler = new RetryHandler ( dispatchOptions , {
923+ dispatch : client . dispatch . bind ( client ) ,
924+ handler : new RequestHandler ( dispatchOptions , ( err , data ) => {
925+ t . ifError ( err )
926+ } )
927+ } )
928+
929+ after ( async ( ) => {
930+ await client . close ( )
931+ server . close ( )
932+
933+ await once ( server , 'close' )
934+ } )
935+
936+ client . dispatch (
937+ dispatchOptions ,
938+ handler
939+ )
940+ } )
941+
942+ await t . completed
943+ } )
944+
737945test ( 'should not error if request is not meant to be retried' , async t => {
738946 t = tspl ( t , { plan : 3 } )
739947
@@ -777,8 +985,7 @@ test('should not error if request is not meant to be retried', async t => {
777985 t . strictEqual ( Buffer . concat ( chunks ) . toString ( 'utf-8' ) , 'Bad request' )
778986 } ,
779987 onError ( err ) {
780- console . log ( { err } )
781- t . fail ( )
988+ t . fail ( err )
782989 }
783990 }
784991 } )
0 commit comments