@@ -364,6 +364,114 @@ describe('Child process plugin', () => {
364
364
} )
365
365
} )
366
366
367
+ describe ( 'Bluebird Promise Compatibility' , ( ) => {
368
+ // BLUEBIRD REGRESSION TEST - Prevents "this._then is not a function" bug
369
+
370
+ let childProcess , tracer , util
371
+ let originalPromise
372
+ let Bluebird
373
+
374
+ beforeEach ( ( ) => {
375
+ return agent . load ( 'child_process' , undefined , { flushInterval : 1 } ) . then ( ( ) => {
376
+ tracer = require ( '../../dd-trace' )
377
+ childProcess = require ( 'child_process' )
378
+ util = require ( 'util' )
379
+ tracer . use ( 'child_process' , { enabled : true } )
380
+ Bluebird = require ( '../../../versions/bluebird' ) . get ( )
381
+
382
+ originalPromise = global . Promise
383
+ global . Promise = Bluebird
384
+ } )
385
+ } )
386
+
387
+ afterEach ( ( ) => {
388
+ global . Promise = originalPromise
389
+ return agent . close ( { ritmReset : false } )
390
+ } )
391
+
392
+ it ( 'should not crash with "this._then is not a function" when using Bluebird promises' , async ( ) => {
393
+ const execFileAsync = util . promisify ( childProcess . execFile )
394
+
395
+ expect ( global . Promise ) . to . equal ( Bluebird )
396
+ expect ( global . Promise . version ) . to . exist
397
+
398
+ const expectedPromise = expectSomeSpan ( agent , {
399
+ type : 'system' ,
400
+ name : 'command_execution' ,
401
+ error : 0 ,
402
+ meta : {
403
+ component : 'subprocess' ,
404
+ 'cmd.exec' : '["echo","bluebird-test"]' ,
405
+ }
406
+ } )
407
+
408
+ const result = await execFileAsync ( 'echo' , [ 'bluebird-test' ] )
409
+ expect ( result ) . to . exist
410
+ expect ( result . stdout ) . to . contain ( 'bluebird-test' )
411
+
412
+ return expectedPromise
413
+ } )
414
+
415
+ it ( 'should work with concurrent Bluebird promise calls' , async ( ) => {
416
+ const execFileAsync = util . promisify ( childProcess . execFile )
417
+
418
+ const promises = [ ]
419
+ for ( let i = 0 ; i < 5 ; i ++ ) {
420
+ promises . push (
421
+ execFileAsync ( 'echo' , [ `concurrent-test-${ i } ` ] )
422
+ . then ( result => {
423
+ expect ( result . stdout ) . to . contain ( `concurrent-test-${ i } ` )
424
+ return result
425
+ } )
426
+ )
427
+ }
428
+
429
+ const results = await Promise . all ( promises )
430
+ expect ( results ) . to . have . length ( 5 )
431
+ } )
432
+
433
+ it ( 'should handle Bluebird promise rejection properly' , async ( ) => {
434
+ global . Promise = Bluebird
435
+
436
+ const execFileAsync = util . promisify ( childProcess . execFile )
437
+
438
+ const expectedPromise = expectSomeSpan ( agent , {
439
+ type : 'system' ,
440
+ name : 'command_execution' ,
441
+ error : 1 ,
442
+ meta : {
443
+ component : 'subprocess' ,
444
+ 'cmd.exec' : '["node","-invalidFlag"]'
445
+ }
446
+ } )
447
+
448
+ try {
449
+ await execFileAsync ( 'node' , [ '-invalidFlag' ] , { stdio : 'pipe' } )
450
+ throw new Error ( 'Expected command to fail' )
451
+ } catch ( error ) {
452
+ expect ( error ) . to . exist
453
+ expect ( error . code ) . to . exist
454
+ }
455
+
456
+ return expectedPromise
457
+ } )
458
+
459
+ it ( 'should work with util.promisify when global Promise is Bluebird' , async ( ) => {
460
+ // Re-require util to get Bluebird-aware promisify
461
+ delete require . cache [ require . resolve ( 'util' ) ]
462
+ const utilWithBluebird = require ( 'util' )
463
+
464
+ const execFileAsync = utilWithBluebird . promisify ( childProcess . execFile )
465
+
466
+ const promise = execFileAsync ( 'echo' , [ 'util-promisify-test' ] )
467
+ expect ( promise . constructor ) . to . equal ( Bluebird )
468
+ expect ( promise . constructor . version ) . to . exist
469
+
470
+ const result = await promise
471
+ expect ( result . stdout ) . to . contain ( 'util-promisify-test' )
472
+ } )
473
+ } )
474
+
367
475
describe ( 'Integration' , ( ) => {
368
476
describe ( 'Methods which spawn a shell by default' , ( ) => {
369
477
const execAsyncMethods = [ 'exec' ]
0 commit comments