jeudi 19 mai 2016

Track call chain from within mock functions in Node.js

I need to write an automated test that should track the functions call chain. In the example below the functions are called nativefn1 and nativefn2. I can't change their code to make the tracking possible so I need some workaround for this situation.

var async = require('async')

nativefn1 = function(input, cb) {
  setTimeout(
    function() { cb(null,"<" + input + ">") },
    Math.floor(Math.random() * 1000)
  )
}

nativefn2 = function(input, cb) {
  setTimeout(
    function() { nativefn1(input, function(err,result) { cb(null,"<<" + result + ">>") } ) },
    Math.floor(Math.random() * 1000)
  )
}

var callchain_counter = 0
var debug_results = { "???": [] }
var original = {
  nativefn1: nativefn1,
  nativefn2: nativefn2,
}

nativefn2 = function(input, cb) {
  var callchain_number = callchain_counter++
  debug_results[callchain_number] = []
  debug_results[callchain_number].push("Callchain #" + callchain_number + ": nativefn2 call:", arguments)
  original.nativefn2(input,function(err,result) {
    debug_results[callchain_number].push("Callchain #" + callchain_number + ": nativefn2 call result:", arguments)
    cb(null,result)
  })
}

nativefn1 = function(input, cb) {
  var callchain_number = "???"
  debug_results[callchain_number].push("Callchain #" + callchain_number + ": nativefn1 call:", arguments)
  original.nativefn1(input,function(err,result) {
    debug_results[callchain_number].push("Callchain #" + callchain_number + ": nativefn1 call result:", arguments)
    cb(null,result)
  })
}

async.parallel(
  [
    function(done) { nativefn2("Lorem",done) },
    function(done) { nativefn2("ipsum",done) },
    function(done) { nativefn2("dolor",done) },
    function(done) { nativefn2("amet",done) },
    function(done) { nativefn2("sit",done) },
  ],
  function(err,result) {
    console.log(debug_results)
  }
)

Upon execution this code prints debug_results like these:

{ '0': 
   [ 'Callchain #0: nativefn2 call:',
     { '0': 'Lorem', '1': [Function] },
     'Callchain #0: nativefn2 call result:',
     { '0': null, '1': '<<<Lorem>>>' } ],
  '1': 
   [ 'Callchain #1: nativefn2 call:',
     { '0': 'ipsum', '1': [Function] },
     'Callchain #1: nativefn2 call result:',
     { '0': null, '1': '<<<ipsum>>>' } ],
  '2': 
   [ 'Callchain #2: nativefn2 call:',
     { '0': 'dolor', '1': [Function] },
     'Callchain #2: nativefn2 call result:',
     { '0': null, '1': '<<<dolor>>>' } ],
  '3': 
   [ 'Callchain #3: nativefn2 call:',
     { '0': 'amet', '1': [Function] },
     'Callchain #3: nativefn2 call result:',
     { '0': null, '1': '<<<amet>>>' } ],
  '4': 
   [ 'Callchain #4: nativefn2 call:',
     { '0': 'sit', '1': [Function] },
     'Callchain #4: nativefn2 call result:',
     { '0': null, '1': '<<<sit>>>' } ],
  '???': 
   [ 'Callchain #???: nativefn1 call:',
     { '0': 'ipsum', '1': [Function] },
     'Callchain #???: nativefn1 call result:',
     { '0': null, '1': '<ipsum>' },
     'Callchain #???: nativefn1 call:',
     { '0': 'Lorem', '1': [Function] },
     'Callchain #???: nativefn1 call:',
     { '0': 'amet', '1': [Function] },
     'Callchain #???: nativefn1 call:',
     { '0': 'dolor', '1': [Function] },
     'Callchain #???: nativefn1 call:',
     { '0': 'sit', '1': [Function] },
     'Callchain #???: nativefn1 call result:',
     { '0': null, '1': '<Lorem>' },
     'Callchain #???: nativefn1 call result:',
     { '0': null, '1': '<amet>' },
     'Callchain #???: nativefn1 call result:',
     { '0': null, '1': '<dolor>' },
     'Callchain #???: nativefn1 call result:',
     { '0': null, '1': '<sit>' } ] }

But all nativefn1 calls are untracked because I can't find a way to pass the callchain_number from mocked nativefn2 to mocked nativefn1. Is it possible to access the call context or create some additional call context somehow to make this possible? Functions must be called in parallel.





Aucun commentaire:

Enregistrer un commentaire