Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 100
test: update travis config, handle errors properly, add TEST_LLNODE_DEBUG#144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
2155954b36fbc0ecd9eecf7a4ed3ae83fe8File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -8,27 +8,39 @@ const spawn = require('child_process').spawn; | ||
| const EventEmitter = require('events').EventEmitter; | ||
| exports.fixturesDir = path.join(__dirname, 'fixtures'); | ||
| exports.buildDir = path.join(__dirname, '..', 'out', 'Release'); | ||
| exports.projectDir = path.join(__dirname, '..'); | ||
| exports.core = path.join(os.tmpdir(), 'core'); | ||
| exports.ranges = exports.core + '.ranges'; | ||
| exports.promptDelay = 200; | ||
| function llnodeDebug() { | ||
| // Node v4.x does not support rest | ||
| const args = Array.prototype.slice.call(arguments); | ||
| console.error.apply(console, [`[TEST][${process.pid}]`].concat(args)); | ||
| } | ||
| const debug = exports.debug = | ||
| process.env.TEST_LLNODE_DEBUG ? llnodeDebug : () => { }; | ||
| let pluginName; | ||
| if (process.platform === 'darwin') | ||
| pluginName = 'llnode.dylib'; | ||
| else if (process.platform === 'windows') | ||
| pluginName = 'llnode.dll'; | ||
| else | ||
| pluginName = path.join('lib.target', 'llnode.so'); | ||
| pluginName = 'llnode.so'; | ||
| exports.llnodePath = path.join(exports.buildDir, pluginName); | ||
| exports.llnodePath = path.join(exports.projectDir, pluginName); | ||
| exports.saveCoreTimeout = 180 * 1000; | ||
| exports.loadCoreTimeout = 20 * 1000; | ||
| function SessionOutput(session, stream) { | ||
| function SessionOutput(session, stream, timeout) { | ||
| EventEmitter.call(this); | ||
| this.waiting = false; | ||
| this.waitQueue = []; | ||
| let buf = ''; | ||
| this.timeout = timeout || 10000; | ||
| this.session = session; | ||
| stream.on('data', (data) => { | ||
| buf += data; | ||
| @@ -44,15 +56,15 @@ function SessionOutput(session, stream) { | ||
| if (/process \d+ exited/i.test(line)) | ||
| session.kill(); | ||
| else if (session.initialized) | ||
| else | ||
| this.emit('line', line); | ||
| else if (/process \d+ launched/i.test(line)) | ||
| session.initialized = true; | ||
| } | ||
| }); | ||
| // Ignore errors | ||
| stream.on('error', () => {}); | ||
| stream.on('error', (err) => { | ||
| debug('[stream error]', err); | ||
| }); | ||
| } | ||
| util.inherits(SessionOutput, EventEmitter); | ||
| @@ -72,109 +84,171 @@ SessionOutput.prototype._unqueueWait = function _unqueueWait() { | ||
| this.waitQueue.shift()(); | ||
| }; | ||
| SessionOutput.prototype.wait = function wait(regexp, callback) { | ||
| if (!this._queueWait(() => { this.wait(regexp, callback); })) | ||
| SessionOutput.prototype.timeoutAfter = function timeoutAfter(timeout) { | ||
| this.timeout = timeout; | ||
| }; | ||
| SessionOutput.prototype.wait = function wait(regexp, callback, allLines) { | ||
| if (!this._queueWait(() => { this.wait(regexp, callback, allLines); })) | ||
| return; | ||
| const self = this; | ||
| this.on('line', function onLine(line) { | ||
| const lines = []; | ||
| function onLine(line) { | ||
| lines.push(line); | ||
| debug('[LINE]', line); | ||
| if (!regexp.test(line)) | ||
| return; | ||
| self.removeListener('line', onLine); | ||
| self._unqueueWait(); | ||
| done = true; | ||
| callback(line); | ||
| }); | ||
| }; | ||
| SessionOutput.prototype.waitBreak = function waitBreak(callback) { | ||
| this.wait(/Process \d+ stopped/i, callback); | ||
| }; | ||
| SessionOutput.prototype.linesUntil = function linesUntil(regexp, callback) { | ||
| if (!this._queueWait(() => { this.linesUntil(regexp, callback); })) | ||
| return; | ||
| const lines = []; | ||
| const self = this; | ||
| this.on('line', function onLine(line) { | ||
| lines.push(line); | ||
| callback(null, allLines ? lines : line); | ||
| } | ||
| if (!regexp.test(line)) | ||
| let done = false; | ||
| const check = setTimeout(() => { | ||
| if (done) | ||
| return; | ||
| self.removeListener('line', onLine); | ||
| self._unqueueWait(); | ||
| console.error(`${'='.repeat(10)} lldb output ${'='.repeat(10)}`); | ||
This comment was marked as off-topic.Sorry, something went wrong. Uh oh!There was an error while loading. Please reload this page.
This comment was marked as off-topic.Sorry, something went wrong. Uh oh!There was an error while loading. Please reload this page. | ||
| console.error(lines.join('\n')); | ||
| console.error('='.repeat(33)); | ||
| const message = `Test timeout in ${this.timeout} ` + | ||
| `waiting for ${regexp}`; | ||
| callback(new Error(message)); | ||
| }, this.timeout).unref(); | ||
| this.on('line', onLine); | ||
| }; | ||
| callback(lines); | ||
| SessionOutput.prototype.waitBreak = function waitBreak(callback) { | ||
| this.wait(/Process \d+ stopped/i, (err) => { | ||
| if (err) | ||
| return callback(err); | ||
| // Do not resume immediately since the process would print | ||
| // the instructions out and input sent before the stdout finish | ||
| // could be lost | ||
| setTimeout(callback, exports.promptDelay); | ||
| }); | ||
| }; | ||
| SessionOutput.prototype.linesUntil = function linesUntil(regexp, callback) { | ||
| this.wait(regexp, callback, true); | ||
| }; | ||
| function Session(scenario) { | ||
| function Session(options) { | ||
| EventEmitter.call(this); | ||
| const timeout = parseInt(process.env.TEST_TIMEOUT) || 10000; | ||
| const lldbBin = process.env.TEST_LLDB_BINARY || 'lldb'; | ||
| const env = Object.assign({}, process.env); | ||
| if (options.ranges) | ||
| env.LLNODE_RANGESFILE = options.ranges; | ||
| debug('lldb binary:', lldbBin); | ||
| if (options.scenario) { | ||
| this.needToKill = true; | ||
| // lldb -- node scenario.js | ||
| const args = [ | ||
| '--', | ||
| process.execPath, | ||
| '--abort_on_uncaught_exception', | ||
| '--expose_externalize_string', | ||
| path.join(exports.fixturesDir, options.scenario) | ||
| ]; | ||
| debug('lldb args:', args); | ||
| this.lldb = spawn(lldbBin, args, { | ||
| stdio: ['pipe', 'pipe', 'pipe'], | ||
| env: env | ||
| }); | ||
| this.lldb.stdin.write(`plugin load "${exports.llnodePath}"\n`); | ||
| this.lldb.stdin.write('run\n'); | ||
| } else if (options.core) { | ||
| this.needToKill = false; | ||
| debug('loading core', options.core); | ||
| // lldb node -c core | ||
| this.lldb = spawn(lldbBin, [], { | ||
| stdio: ['pipe', 'pipe', 'pipe'], | ||
| env: env | ||
| }); | ||
| this.lldb.stdin.write(`plugin load "${exports.llnodePath}"\n`); | ||
| this.lldb.stdin.write(`target create "${options.executable}"` + | ||
| ` --core "${options.core}"\n`); | ||
| } | ||
| this.stdout = new SessionOutput(this, this.lldb.stdout, timeout); | ||
| this.stderr = new SessionOutput(this, this.lldb.stderr, timeout); | ||
| // lldb -- node scenario.js | ||
| this.lldb = spawn(process.env.TEST_LLDB_BINARY || 'lldb', [ | ||
| '--', | ||
| process.execPath, | ||
| '--abort_on_uncaught_exception', | ||
| '--expose_externalize_string', | ||
| path.join(exports.fixturesDir, scenario) | ||
| ], { | ||
| stdio: [ 'pipe', 'pipe', 'pipe' ], | ||
| env: util._extend(util._extend({}, process.env), { | ||
| LLNODE_RANGESFILE: exports.ranges | ||
| }) | ||
| this.stderr.on('line', (line) => { | ||
| debug('[stderr]', line); | ||
| }); | ||
| this.lldb.stdin.write(`plugin load "${exports.llnodePath}"\n`); | ||
| this.lldb.stdin.write('run\n'); | ||
| this.initialized = false; | ||
| this.stdout = new SessionOutput(this, this.lldb.stdout); | ||
| this.stderr = new SessionOutput(this, this.lldb.stderr); | ||
| // Map these methods to stdout for compatibility with legacy tests. | ||
| this.wait = SessionOutput.prototype.wait.bind(this.stdout); | ||
| this.waitBreak = SessionOutput.prototype.waitBreak.bind(this.stdout); | ||
| this.linesUntil = SessionOutput.prototype.linesUntil.bind(this.stdout); | ||
| this.timeoutAfter = SessionOutput.prototype.timeoutAfter.bind(this.stdout); | ||
| } | ||
| util.inherits(Session, EventEmitter); | ||
| exports.Session = Session; | ||
| Session.create = function create(scenario) { | ||
| return new Session(scenario); | ||
| return new Session({ scenario: scenario }); | ||
| }; | ||
| Session.loadCore = function loadCore(executable, core, ranges) { | ||
| return new Session({ | ||
| executable: executable, | ||
| core: core, | ||
| ranges: ranges | ||
| }); | ||
| }; | ||
| Session.prototype.waitCoreLoad = function waitCoreLoad(callback) { | ||
| this.wait(/Core file[^\n]+was loaded/, callback); | ||
| }; | ||
| Session.prototype.kill = function kill() { | ||
| this.lldb.kill(); | ||
| this.lldb = null; | ||
| // if a 'quit' has been sent to lldb, killing it could result in ECONNRESET | ||
| if (this.lldb.channel) { | ||
| debug('kill lldb'); | ||
| this.lldb.kill(); | ||
| this.lldb = null; | ||
| } | ||
| }; | ||
| Session.prototype.quit = function quit() { | ||
| this.send('kill'); | ||
| if (this.needToKill) | ||
| this.send('kill'); // kill the process launched in lldb | ||
| this.send('quit'); | ||
| }; | ||
| Session.prototype.send = function send(line, callback) { | ||
| debug('[SEND]', line); | ||
| this.lldb.stdin.write(line + '\n', callback); | ||
| }; | ||
| exports.generateRanges = function generateRanges(cb) { | ||
| exports.generateRanges = function generateRanges(core, dest, cb) { | ||
| let script; | ||
| if (process.platform === 'darwin') | ||
| script = path.join(__dirname, '..', 'scripts', 'otool2segments.py'); | ||
| else | ||
| script = path.join(__dirname, '..', 'scripts', 'readelf2segments.py'); | ||
| const proc = spawn(script, [ exports.core ], { | ||
| stdio: [ null, 'pipe', 'inherit' ] | ||
| debug('[RANGES]', `${script}, ${core}, ${dest}`); | ||
| const proc = spawn(script, [core], { | ||
| stdio: [null, 'pipe', 'inherit'] | ||
| }); | ||
| proc.stdout.pipe(fs.createWriteStream(exports.ranges)); | ||
| proc.stdout.pipe(fs.createWriteStream(dest)); | ||
| proc.on('exit', (status) => { | ||
| cb(status === 0 ? null : new Error('Failed to generate ranges')); | ||
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as off-topic.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as off-topic.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.