diff options
author | Jeremiah Senkpiel <fishrock123@rocketmail.com> | 2015-12-11 17:45:53 -0500 |
---|---|---|
committer | Jeremiah Senkpiel <fishrock123@rocketmail.com> | 2015-12-14 13:42:46 -0500 |
commit | 7598ed6cc06603c87925a17e8aa7027806bf2457 (patch) | |
tree | d33f51848f85e6779a99b59300b006a2ca52cf19 /test/parallel/test-repl-persistent-history.js | |
parent | 668449ad1442645c0657a75d190bd791d0a59532 (diff) | |
download | android-node-v8-7598ed6cc06603c87925a17e8aa7027806bf2457.tar.gz android-node-v8-7598ed6cc06603c87925a17e8aa7027806bf2457.tar.bz2 android-node-v8-7598ed6cc06603c87925a17e8aa7027806bf2457.zip |
test: parallelize test-repl-persistent-history
Refs: https://github.com/nodejs/node/pull/2224#issuecomment-127356413
PR-URL: https://github.com/nodejs/node/pull/4247
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'test/parallel/test-repl-persistent-history.js')
-rw-r--r-- | test/parallel/test-repl-persistent-history.js | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/test/parallel/test-repl-persistent-history.js b/test/parallel/test-repl-persistent-history.js new file mode 100644 index 0000000000..10e0dedf53 --- /dev/null +++ b/test/parallel/test-repl-persistent-history.js @@ -0,0 +1,274 @@ +'use strict'; + +// Flags: --expose-internals + +const common = require('../common'); +const stream = require('stream'); +const REPL = require('internal/repl'); +const assert = require('assert'); +const fs = require('fs'); +const util = require('util'); +const path = require('path'); +const os = require('os'); + +common.refreshTmpDir(); + +// Mock os.homedir() +os.homedir = function() { + return common.tmpDir; +}; + +// Create an input stream specialized for testing an array of actions +class ActionStream extends stream.Stream { + run(data) { + const _iter = data[Symbol.iterator](); + const self = this; + + function doAction() { + const next = _iter.next(); + if (next.done) { + // Close the repl. Note that it must have a clean prompt to do so. + setImmediate(function() { + self.emit('keypress', '', { ctrl: true, name: 'd' }); + }); + return; + } + const action = next.value; + + if (typeof action === 'object') { + self.emit('keypress', '', action); + } else { + self.emit('data', action + '\n'); + } + setImmediate(doAction); + } + setImmediate(doAction); + } + resume() {} + pause() {} +} +ActionStream.prototype.readable = true; + + +// Mock keys +const UP = { name: 'up' }; +const ENTER = { name: 'enter' }; +const CLEAR = { ctrl: true, name: 'u' }; +// Common message bits +const prompt = '> '; +const replDisabled = '\nPersistent history support disabled. Set the ' + + 'NODE_REPL_HISTORY environment\nvariable to a valid, ' + + 'user-writable path to enable.\n'; +const convertMsg = '\nConverting old JSON repl history to line-separated ' + + 'history.\nThe new repl history file can be found at ' + + path.join(common.tmpDir, '.node_repl_history') + '.\n'; +const homedirErr = '\nError: Could not get the home directory.\n' + + 'REPL session history will not be persisted.\n'; +const replFailedRead = '\nError: Could not open history file.\n' + + 'REPL session history will not be persisted.\n'; +// File paths +const fixtures = path.join(common.testDir, 'fixtures'); +const historyFixturePath = path.join(fixtures, '.node_repl_history'); +const historyPath = path.join(common.tmpDir, '.fixture_copy_repl_history'); +const historyPathFail = path.join(common.tmpDir, '.node_repl\u0000_history'); +const oldHistoryPath = path.join(fixtures, 'old-repl-history-file.json'); +const enoentHistoryPath = path.join(fixtures, 'enoent-repl-history-file.json'); +const defaultHistoryPath = path.join(common.tmpDir, '.node_repl_history'); + + +const tests = [{ + env: { NODE_REPL_HISTORY: '' }, + test: [UP], + expected: [prompt, replDisabled, prompt] +}, +{ + env: { NODE_REPL_HISTORY: '', + NODE_REPL_HISTORY_FILE: enoentHistoryPath }, + test: [UP], + expected: [prompt, replDisabled, prompt] +}, +{ + env: { NODE_REPL_HISTORY: '', + NODE_REPL_HISTORY_FILE: oldHistoryPath }, + test: [UP], + expected: [prompt, replDisabled, prompt] +}, +{ + env: { NODE_REPL_HISTORY: historyPath }, + test: [UP, CLEAR], + expected: [prompt, prompt + '\'you look fabulous today\'', prompt] +}, +{ + env: { NODE_REPL_HISTORY: historyPath, + NODE_REPL_HISTORY_FILE: oldHistoryPath }, + test: [UP, CLEAR], + expected: [prompt, prompt + '\'you look fabulous today\'', prompt] +}, +{ + env: { NODE_REPL_HISTORY: historyPath, + NODE_REPL_HISTORY_FILE: '' }, + test: [UP, CLEAR], + expected: [prompt, prompt + '\'you look fabulous today\'', prompt] +}, +{ + env: {}, + test: [UP], + expected: [prompt] +}, +{ + env: { NODE_REPL_HISTORY_FILE: oldHistoryPath }, + test: [UP, CLEAR, '\'42\'', ENTER], + expected: [prompt, convertMsg, prompt, prompt + '\'=^.^=\'', prompt, '\'', + '4', '2', '\'', '\'42\'\n', prompt, prompt], + after: function ensureHistoryFixture() { + // XXX(Fishrock123) Make sure nothing weird happened to our fixture + // or it's temporary copy. + // Sometimes this test used to erase the fixture and I'm not sure why. + const history = fs.readFileSync(historyFixturePath, 'utf8'); + assert.strictEqual(history, + '\'you look fabulous today\'\n\'Stay Fresh~\'\n'); + const historyCopy = fs.readFileSync(historyPath, 'utf8'); + assert.strictEqual(historyCopy, '\'you look fabulous today\'' + os.EOL + + '\'Stay Fresh~\'' + os.EOL); + } +}, +{ // Requires the above testcase + env: {}, + test: [UP, UP, ENTER], + expected: [prompt, prompt + '\'42\'', prompt + '\'=^.^=\'', '\'=^.^=\'\n', + prompt] +}, +{ + env: { NODE_REPL_HISTORY: historyPath, + NODE_REPL_HISTORY_SIZE: 1 }, + test: [UP, UP, CLEAR], + expected: [prompt, prompt + '\'you look fabulous today\'', prompt] +}, +{ + env: { NODE_REPL_HISTORY_FILE: oldHistoryPath, + NODE_REPL_HISTORY_SIZE: 1 }, + test: [UP, UP, UP, CLEAR], + expected: [prompt, convertMsg, prompt, prompt + '\'=^.^=\'', prompt] +}, +{ + env: { NODE_REPL_HISTORY: historyPathFail, + NODE_REPL_HISTORY_SIZE: 1 }, + test: [UP], + expected: [prompt, replFailedRead, prompt, replDisabled, prompt] +}, +{ // Make sure this is always the last test, since we change os.homedir() + before: function mockHomedirFailure() { + // Mock os.homedir() failure + os.homedir = function() { + throw new Error('os.homedir() failure'); + }; + }, + env: {}, + test: [UP], + expected: [prompt, homedirErr, prompt, replDisabled, prompt] +}]; +const numtests = tests.length; + + +var testsNotRan = tests.length; + +process.on('beforeExit', () => + assert.strictEqual(testsNotRan, 0) +); + +function cleanupTmpFile() { + try { + // Write over the file, clearing any history + fs.writeFileSync(defaultHistoryPath, ''); + } catch (err) { + if (err.code === 'ENOENT') return true; + throw err; + } + return true; +} + +// Copy our fixture to the tmp directory +fs.createReadStream(historyFixturePath) + .pipe(fs.createWriteStream(historyPath)).on('unpipe', () => runTest()); + +function runTest(assertCleaned) { + const opts = tests.shift(); + if (!opts) return; // All done + + if (assertCleaned) { + try { + assert.strictEqual(fs.readFileSync(defaultHistoryPath, 'utf8'), ''); + } catch (e) { + if (e.code !== 'ENOENT') { + console.error(`Failed test # ${numtests - tests.length}`); + throw e; + } + } + } + + const env = opts.env; + const test = opts.test; + const expected = opts.expected; + const after = opts.after; + const before = opts.before; + + if (before) before(); + + REPL.createInternalRepl(env, { + input: new ActionStream(), + output: new stream.Writable({ + write(chunk, _, next) { + const output = chunk.toString(); + + // Ignore escapes and blank lines + if (output.charCodeAt(0) === 27 || /^[\r\n]+$/.test(output)) + return next(); + + try { + assert.strictEqual(output, expected.shift()); + } catch (err) { + console.error(`Failed test # ${numtests - tests.length}`); + throw err; + } + next(); + } + }), + prompt: prompt, + useColors: false, + terminal: true + }, function(err, repl) { + if (err) { + console.error(`Failed test # ${numtests - tests.length}`); + throw err; + } + + repl.once('close', () => { + if (repl._flushing) { + repl.once('flushHistory', onClose); + return; + } + + onClose(); + }); + + function onClose() { + if (after) { + var cleaned = after(); + } else { + var cleaned = cleanupTmpFile(); + } + + try { + // Ensure everything that we expected was output + assert.strictEqual(expected.length, 0); + testsNotRan--; + setImmediate(runTest, cleaned); + } catch (err) { + console.error(`Failed test # ${numtests - tests.length}`); + throw err; + } + } + + repl.inputStream.run(test); + }); +} |