diff options
author | Bryan Cantrill <bryan@joyent.com> | 2012-09-21 01:48:55 +0200 |
---|---|---|
committer | Bert Belder <bertbelder@gmail.com> | 2012-09-21 01:51:57 +0200 |
commit | cc1b09d6b7c3cc6b8729804cbf644634ba5d0815 (patch) | |
tree | 97d25564d761c84ad920c29b3e53030ecef29767 | |
parent | bbf6b4ecbb55668a3ccd63695b38c4c41a76b82a (diff) | |
download | android-node-v8-cc1b09d6b7c3cc6b8729804cbf644634ba5d0815.tar.gz android-node-v8-cc1b09d6b7c3cc6b8729804cbf644634ba5d0815.tar.bz2 android-node-v8-cc1b09d6b7c3cc6b8729804cbf644634ba5d0815.zip |
test: add tests for postmortem and DTrace support
-rw-r--r-- | test/pummel/test-dtrace-jsstack.js | 107 | ||||
-rw-r--r-- | test/pummel/test-postmortem-findjsobjects.js | 99 | ||||
-rw-r--r-- | test/pummel/test-postmortem-jsstack.js | 179 |
3 files changed, 385 insertions, 0 deletions
diff --git a/test/pummel/test-dtrace-jsstack.js b/test/pummel/test-dtrace-jsstack.js new file mode 100644 index 0000000000..6779a766a7 --- /dev/null +++ b/test/pummel/test-dtrace-jsstack.js @@ -0,0 +1,107 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); +var os = require('os'); +var util = require('util'); + +if (os.type() != 'SunOS') { + console.error('Skipping because DTrace not available.'); + process.exit(0); +} + +/* + * Some functions to create a recognizable stack. + */ +var frames = [ 'stalloogle', 'bagnoogle', 'doogle' ]; +var expected; + +var stalloogle = function (str) { + expected = str; + os.loadavg(); +}; + +var bagnoogle = function (arg0, arg1) { + stalloogle(arg0 + ' is ' + arg1 + ' except that it is read-only'); +}; + +var done = false; + +var doogle = function () { + if (!done) + setTimeout(doogle, 10); + + bagnoogle('The bfs command', '(almost) like ed(1)'); +}; + +var spawn = require('child_process').spawn; +var prefix = '/var/tmp/node'; +var corefile = prefix + '.' + process.pid; + +/* + * We're going to use DTrace to stop us, gcore us, and set us running again + * when we call getloadavg() -- with the implicit assumption that our + * deepest function is the only caller of os.loadavg(). + */ +var dtrace = spawn('dtrace', [ '-qwn', 'syscall::getloadavg:entry/pid == ' + + process.pid + '/{ustack(100, 8192); exit(0); }' ]); + +var output = ''; + +dtrace.stderr.on('data', function (data) { + console.log('dtrace: ' + data); +}); + +dtrace.stdout.on('data', function (data) { + output += data; +}); + +dtrace.on('exit', function (code) { + if (code != 0) { + console.error('dtrace exited with code ' + code); + process.exit(code); + } + + done = true; + + var sentinel = '(anon) as '; + var lines = output.split('\n'); + + for (var i = 0; i < lines.length; i++) { + var line = lines[i]; + + if (line.indexOf(sentinel) == -1 || frames.length === 0) + continue; + + var frame = line.substr(line.indexOf(sentinel) + sentinel.length); + var top = frames.shift(); + + assert.equal(frame.indexOf(top), 0, 'unexpected frame where ' + + top + ' was expected'); + } + + assert.equal(frames.length, 0, 'did not find expected frame ' + frames[0]); + process.exit(0); +}); + +setTimeout(doogle, 10); + diff --git a/test/pummel/test-postmortem-findjsobjects.js b/test/pummel/test-postmortem-findjsobjects.js new file mode 100644 index 0000000000..568e2ff059 --- /dev/null +++ b/test/pummel/test-postmortem-findjsobjects.js @@ -0,0 +1,99 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); +var os = require('os'); +var util = require('util'); + +if (os.type() != 'SunOS') { + console.error('Skipping because postmortem debugging not available.'); + process.exit(0); +} + +/* + * Now we're going to fork ourselves to gcore + */ +var spawn = require('child_process').spawn; +var prefix = '/var/tmp/node'; +var corefile = prefix + '.' + process.pid; +var gcore = spawn('gcore', [ '-o', prefix, process.pid + '' ]); +var output = ''; +var unlinkSync = require('fs').unlinkSync; +var args = [ corefile ]; + +if (process.env.MDB_LIBRARY_PATH && process.env.MDB_LIBRARY_PATH != '') + args = args.concat([ '-L', process.env.MDB_LIBRARY_PATH ]); + +function LanguageH(chapter) { this.OBEY = 'CHAPTER ' + parseInt(chapter, 10); } +var obj = new LanguageH(1); + +gcore.stderr.on('data', function (data) { + console.log('gcore: ' + data); +}); + +gcore.on('exit', function (code) { + if (code != 0) { + console.error('gcore exited with code ' + code); + process.exit(code); + } + + var mdb = spawn('mdb', args, { stdio: 'pipe' }); + + mdb.on('exit', function (code) { + var retained = '; core retained as ' + corefile; + + if (code != 0) { + console.error('mdb exited with code ' + util.inspect(code) + retained); + process.exit(code); + } + + var lines = output.split('\n'); + var found = 0, i, expected = 'OBEY: ' + obj.OBEY, nexpected = 2; + + for (var i = 0; i < lines.length; i++) { + if (lines[i].indexOf(expected) != -1) + found++; + } + + assert.equal(found, nexpected, 'expected ' + nexpected + + ' objects, found ' + found + retained); + + unlinkSync(corefile); + process.exit(0); + }); + + mdb.stdout.on('data', function (data) { + output += data; + }); + + mdb.stderr.on('data', function (data) { + console.log('mdb stderr: ' + data); + }); + + mdb.stdin.write('::load v8.so\n'); + mdb.stdin.write('::findjsobjects -c LanguageH | '); + mdb.stdin.write('::findjsobjects | ::jsprint\n'); + mdb.stdin.write('::findjsobjects -p OBEY | '); + mdb.stdin.write('::findjsobjects | ::jsprint\n'); + mdb.stdin.end(); +}); + diff --git a/test/pummel/test-postmortem-jsstack.js b/test/pummel/test-postmortem-jsstack.js new file mode 100644 index 0000000000..735e39e210 --- /dev/null +++ b/test/pummel/test-postmortem-jsstack.js @@ -0,0 +1,179 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); +var os = require('os'); +var util = require('util'); + +if (os.type() != 'SunOS') { + console.error('Skipping because postmortem debugging not available.'); + process.exit(0); +} + +/* + * Some functions to create a recognizable stack. + */ +var frames = [ 'stalloogle', 'bagnoogle', 'doogle' ]; +var expected; + +var stalloogle = function (str) { + expected = str; + os.loadavg(); +}; + +var bagnoogle = function (arg0, arg1) { + stalloogle(arg0 + ' is ' + arg1 + ' except that it is read-only'); +}; + +var done = false; + +var doogle = function () { + if (!done) + setTimeout(doogle, 10); + + bagnoogle('The bfs command', '(almost) like ed(1)'); +}; + +var spawn = require('child_process').spawn; +var prefix = '/var/tmp/node'; +var corefile = prefix + '.' + process.pid; +var args = [ corefile ]; + +if (process.env.MDB_LIBRARY_PATH && process.env.MDB_LIBRARY_PATH != '') + args = args.concat([ '-L', process.env.MDB_LIBRARY_PATH ]); + +/* + * We're going to use DTrace to stop us, gcore us, and set us running again + * when we call getloadavg() -- with the implicit assumption that our + * deepest function is the only caller of os.loadavg(). + */ +var dtrace = spawn('dtrace', [ '-qwn', 'syscall::getloadavg:entry/pid == ' + + process.pid + '/{stop(); system("gcore -o ' + + prefix + ' %d", pid); system("prun %d", pid); exit(0); }' ]); + +var output = ''; +var unlinkSync = require('fs').unlinkSync; + +dtrace.stderr.on('data', function (data) { + console.log('dtrace: ' + data); +}); + +dtrace.on('exit', function (code) { + if (code != 0) { + console.error('dtrace exited with code ' + code); + process.exit(code); + } + + done = true; + + /* + * We have our core file. Now we need to fire up mdb to analyze it... + */ + var mdb = spawn('mdb', args, { stdio: 'pipe' }); + + mdb.on('exit', function (code) { + var retained = '; core retained as ' + corefile; + + if (code != 0) { + console.error('mdb exited with code ' + code + retained); + process.exit(code); + } + + var sentinel = '<anonymous> (as '; + var arg1 = ' arg1: '; + var lines = output.split('\n'); + var matched = 0; + var straddr = undefined; + + for (var i = 0; i < lines.length; i++) { + var line = lines[i]; + + if (matched == 1 && line.indexOf(arg1) === 0) { + straddr = line.substr(arg1.length).split(' ')[0]; + } + + if (line.indexOf(sentinel) == -1 || frames.length === 0) + continue; + + var frame = line.substr(line.indexOf(sentinel) + sentinel.length); + var top = frames.shift(); + + assert.equal(frame.indexOf(top), 0, 'unexpected frame where ' + + top + ' was expected' + retained); + + matched++; + } + + assert.equal(frames.length, 0, 'did not find expected frame ' + + frames[0] + retained); + + assert.notEqual(straddr, undefined, + 'did not find arg1 for top frame' + retained); + + /* + * Now we're going to take one more swing at the core file to print out + * the argument string that we found. + */ + output = ''; + mdb = spawn('mdb', args, { stdio: 'pipe' }); + + mdb.on('exit', function (code) { + if (code != 0) { + console.error('mdb (second) exited with code ' + code + retained); + process.exit(code); + } + + assert.notEqual(output.indexOf(expected), -1, 'did not find arg1 (' + + straddr + ') to contain expected string' + retained); + + unlinkSync(corefile); + process.exit(0); + }); + + mdb.stdout.on('data', function (data) { + output += data; + }); + + mdb.stderr.on('data', function (data) { + console.log('mdb (second) stderr: ' + data); + }); + + mdb.stdin.write('::load v8.so\n'); + mdb.stdin.write(straddr + '::v8str\n'); + mdb.stdin.end(); + }); + + mdb.stdout.on('data', function (data) { + output += data; + }); + + mdb.stderr.on('data', function (data) { + console.log('mdb stderr: ' + data); + }); + + mdb.stdin.write('::load v8.so\n'); + mdb.stdin.write('::jsstack -v\n'); + mdb.stdin.end(); +}); + +setTimeout(doogle, 10); + |