diff --git a/package.json b/package.json index 1c1df6bc..dee73442 100644 --- a/package.json +++ b/package.json @@ -46,8 +46,8 @@ } }, "dependencies": { - "bunyan": "^1.8.5", - "date-fns": "^1.28.0", + "bunyan": "^1.8.9", + "date-fns": "^1.28.2", "lodash": "^4.17.4", "minimist-string": "^1.0.2", "uuid": "^3.0.1", @@ -71,8 +71,7 @@ "npm-run-all": "4.0.1", "rimraf": "2.5.4", "semantic-release": "^6.3.2", - "sinon": "^1.17.7", - "sinon-as-promised": "^4.0.2" + "sinon": "^2.1.0" }, "engines": { "node": ">=6.x", diff --git a/src/commands/registration/appe.js b/src/commands/registration/appe.js index 01fced53..afeb3297 100644 --- a/src/commands/registration/appe.js +++ b/src/commands/registration/appe.js @@ -7,4 +7,4 @@ module.exports = { }, syntax: '{{cmd}} [path]', description: 'Append to a file' -} +}; diff --git a/src/commands/registration/auth.js b/src/commands/registration/auth.js index 4d570ca1..4ad9ec68 100644 --- a/src/commands/registration/auth.js +++ b/src/commands/registration/auth.js @@ -16,7 +16,7 @@ module.exports = { flags: { no_auth: true } -} +}; function handleTLS() { return this.reply(504); diff --git a/src/commands/registration/cdup.js b/src/commands/registration/cdup.js index a37a6e7b..ac72f8d8 100644 --- a/src/commands/registration/cdup.js +++ b/src/commands/registration/cdup.js @@ -2,10 +2,10 @@ const cwd = require('./cwd').handler; module.exports = { directive: ['CDUP', 'XCUP'], - handler: function(args) { + handler: function (args) { args.command._ = [args.command._[0], '..']; return cwd.call(this, args); }, syntax: '{{cmd}}', description: 'Change to Parent Directory' -} +}; diff --git a/src/commands/registration/cwd.js b/src/commands/registration/cwd.js index d8dfa577..1977ce9b 100644 --- a/src/commands/registration/cwd.js +++ b/src/commands/registration/cwd.js @@ -7,7 +7,7 @@ module.exports = { if (!this.fs) return this.reply(550, 'File system not instantiated'); if (!this.fs.chdir) return this.reply(402, 'Not supported by file system'); - return when(this.fs.chdir(command._[1])) + return when.try(this.fs.chdir.bind(this.fs), command._[1]) .then(cwd => { const path = cwd ? `"${escapePath(cwd)}"` : undefined; return this.reply(250, path); @@ -19,4 +19,4 @@ module.exports = { }, syntax: '{{cmd}}[path]', description: 'Change working directory' -} +}; diff --git a/src/commands/registration/dele.js b/src/commands/registration/dele.js index ca06ba3b..e843c280 100644 --- a/src/commands/registration/dele.js +++ b/src/commands/registration/dele.js @@ -6,7 +6,7 @@ module.exports = { if (!this.fs) return this.reply(550, 'File system not instantiated'); if (!this.fs.delete) return this.reply(402, 'Not supported by file system'); - return when(this.fs.delete(command._[1])) + return when.try(this.fs.delete.bind(this.fs), command._[1]) .then(() => { return this.reply(250); }) @@ -17,4 +17,4 @@ module.exports = { }, syntax: '{{cmd}} [path]', description: 'Delete file' -} +}; diff --git a/src/commands/registration/feat.js b/src/commands/registration/feat.js index 2135e5d1..56ea0f02 100644 --- a/src/commands/registration/feat.js +++ b/src/commands/registration/feat.js @@ -18,4 +18,4 @@ module.exports = { flags: { no_auth: true } -} +}; diff --git a/src/commands/registration/help.js b/src/commands/registration/help.js index 450023dd..a6d8ba40 100644 --- a/src/commands/registration/help.js +++ b/src/commands/registration/help.js @@ -21,4 +21,4 @@ module.exports = { flags: { no_auth: true } -} +}; diff --git a/src/commands/registration/list.js b/src/commands/registration/list.js index 4c54f4ab..8952d4de 100644 --- a/src/commands/registration/list.js +++ b/src/commands/registration/list.js @@ -6,7 +6,7 @@ const getFileStat = require('../../helpers/file-stat'); // http://cr.yp.to/ftp/list/eplf.html module.exports = { directive: 'LIST', - handler: function ({log, command, previous_command} = {}) { + handler: function ({log, command} = {}) { if (!this.fs) return this.reply(550, 'File system not instantiated'); if (!this.fs.list) return this.reply(402, 'Not supported by file system'); @@ -19,9 +19,9 @@ module.exports = { this.commandSocket.pause(); dataSocket = socket; }) - .then(() => when(this.fs.list(directory))) + .then(() => when.try(this.fs.list.bind(this.fs), directory)) .then(files => { - const getFileMessage = (file) => { + const getFileMessage = file => { if (simple) return file.name; return getFileStat(file, _.get(this, 'server.options.file_format', 'ls')); }; @@ -33,7 +33,7 @@ module.exports = { message, socket: dataSocket }; - }) + }); return this.reply(150) .then(() => { if (fileList.length) return this.reply({}, ...fileList); @@ -57,4 +57,4 @@ module.exports = { }, syntax: '{{cmd}} [path(optional)]', description: 'Returns information of a file or directory if specified, else information of the current working directory is returned' -} +}; diff --git a/src/commands/registration/mdtm.js b/src/commands/registration/mdtm.js index af01a689..9e59c709 100644 --- a/src/commands/registration/mdtm.js +++ b/src/commands/registration/mdtm.js @@ -7,10 +7,10 @@ module.exports = { if (!this.fs) return this.reply(550, 'File system not instantiated'); if (!this.fs.get) return this.reply(402, 'Not supported by file system'); - return when(this.fs.get(command._[1])) + return when.try(this.fs.get.bind(this.fs), command._[1]) .then(fileStat => { const modificationTime = format(fileStat.mtime, 'YYYYMMDDHHmmss.SSS'); - return this.reply(213, modificationTime) + return this.reply(213, modificationTime); }) .catch(err => { log.error(err); @@ -22,4 +22,4 @@ module.exports = { flags: { feat: 'MDTM' } -} +}; diff --git a/src/commands/registration/mkd.js b/src/commands/registration/mkd.js index 38989056..2b48c850 100644 --- a/src/commands/registration/mkd.js +++ b/src/commands/registration/mkd.js @@ -7,7 +7,7 @@ module.exports = { if (!this.fs) return this.reply(550, 'File system not instantiated'); if (!this.fs.mkdir) return this.reply(402, 'Not supported by file system'); - return when(this.fs.mkdir(command._[1])) + return when.try(this.fs.mkdir.bind(this.fs), command._[1]) .then(dir => { const path = dir ? `"${escapePath(dir)}"` : undefined; return this.reply(257, path); @@ -19,4 +19,4 @@ module.exports = { }, syntax: '{{cmd}}[path]', description: 'Make directory' -} +}; diff --git a/src/commands/registration/mode.js b/src/commands/registration/mode.js index 994a6ad0..3b896725 100644 --- a/src/commands/registration/mode.js +++ b/src/commands/registration/mode.js @@ -8,4 +8,4 @@ module.exports = { flags: { obsolete: true } -} +}; diff --git a/src/commands/registration/nlst.js b/src/commands/registration/nlst.js index 7cea9461..65e1f898 100644 --- a/src/commands/registration/nlst.js +++ b/src/commands/registration/nlst.js @@ -7,4 +7,4 @@ module.exports = { }, syntax: '{{cmd}} [path(optional)]', description: 'Returns a list of file names in a specified directory' -} +}; diff --git a/src/commands/registration/noop.js b/src/commands/registration/noop.js index b462a3d7..a6cbe6fb 100644 --- a/src/commands/registration/noop.js +++ b/src/commands/registration/noop.js @@ -8,4 +8,4 @@ module.exports = { flags: { no_auth: true } -} +}; diff --git a/src/commands/registration/opts.js b/src/commands/registration/opts.js index 10ac98db..1f271555 100644 --- a/src/commands/registration/opts.js +++ b/src/commands/registration/opts.js @@ -5,4 +5,4 @@ module.exports = { }, syntax: '{{cmd}}', description: 'Select options for a feature' -} +}; diff --git a/src/commands/registration/pass.js b/src/commands/registration/pass.js index a774a8aa..d52af503 100644 --- a/src/commands/registration/pass.js +++ b/src/commands/registration/pass.js @@ -24,4 +24,4 @@ module.exports = { flags: { no_auth: true } -} +}; diff --git a/src/commands/registration/pasv.js b/src/commands/registration/pasv.js index d2eeb1c4..3687eea3 100644 --- a/src/commands/registration/pasv.js +++ b/src/commands/registration/pasv.js @@ -2,7 +2,7 @@ const PassiveConnector = require('../../connector/passive'); module.exports = { directive: 'PASV', - handler: function ({command} = {}) { + handler: function () { this.connector = new PassiveConnector(this); return this.connector.setupServer() .then(server => { @@ -17,4 +17,4 @@ module.exports = { }, syntax: '{{cmd}}', description: 'Initiate passive mode' -} +}; diff --git a/src/commands/registration/port.js b/src/commands/registration/port.js index d3d2556e..ded315ee 100644 --- a/src/commands/registration/port.js +++ b/src/commands/registration/port.js @@ -1,10 +1,11 @@ +const _ = require('lodash'); const ActiveConnector = require('../../connector/active'); module.exports = { directive: 'PORT', handler: function ({command} = {}) { this.connector = new ActiveConnector(this); - const rawConnection = command._[1].split(','); + const rawConnection = _.get(command, '_[1]', '').split(','); if (rawConnection.length !== 6) return this.reply(425); const ip = rawConnection.slice(0, 4).join('.'); @@ -12,10 +13,8 @@ module.exports = { const port = portBytes[0] * 256 + portBytes[1]; return this.connector.setupConnection(ip, port) - .then(socket => { - return this.reply(200); - }) + .then(() => this.reply(200)); }, - syntax: '{{cmd}} [x,x,x,x,y,y]', + syntax: '{{cmd}} x,x,x,x,y,y', description: 'Specifies an address and port to which the server should connect' -} +}; diff --git a/src/commands/registration/pwd.js b/src/commands/registration/pwd.js index dce520e6..def35dbc 100644 --- a/src/commands/registration/pwd.js +++ b/src/commands/registration/pwd.js @@ -3,11 +3,11 @@ const escapePath = require('../../helpers/escape-path'); module.exports = { directive: ['PWD', 'XPWD'], - handler: function ({log, command} = {}) { + handler: function ({log} = {}) { if (!this.fs) return this.reply(550, 'File system not instantiated'); if (!this.fs.currentDirectory) return this.reply(402, 'Not supported by file system'); - return when(this.fs.currentDirectory()) + return when.try(this.fs.currentDirectory.bind(this.fs)) .then(cwd => { const path = cwd ? `"${escapePath(cwd)}"` : undefined; return this.reply(257, path); @@ -15,8 +15,8 @@ module.exports = { .catch(err => { log.error(err); return this.reply(550, err.message); - }) + }); }, syntax: '{{cmd}}', description: 'Print current working directory' -} +}; diff --git a/src/commands/registration/quit.js b/src/commands/registration/quit.js index d3350fa9..82141467 100644 --- a/src/commands/registration/quit.js +++ b/src/commands/registration/quit.js @@ -8,4 +8,4 @@ module.exports = { flags: { no_auth: true } -} +}; diff --git a/src/commands/registration/retr.js b/src/commands/registration/retr.js index e557b1c6..1e8f4b81 100644 --- a/src/commands/registration/retr.js +++ b/src/commands/registration/retr.js @@ -12,7 +12,7 @@ module.exports = { this.commandSocket.pause(); dataSocket = socket; }) - .then(() => when(this.fs.read(command._[1]))) + .then(() => when.try(this.fs.read.bind(this.fs), command._[1])) .then(stream => { return when.promise((resolve, reject) => { dataSocket.on('error', err => stream.emit('error', err)); @@ -34,8 +34,8 @@ module.exports = { .finally(() => { this.connector.end(); this.commandSocket.resume(); - }) + }); }, syntax: '{{cmd}} [path]', description: 'Retrieve a copy of the file' -} +}; diff --git a/src/commands/registration/rmd.js b/src/commands/registration/rmd.js index 3bdaf447..65f5f9a1 100644 --- a/src/commands/registration/rmd.js +++ b/src/commands/registration/rmd.js @@ -7,4 +7,4 @@ module.exports = { }, syntax: '{{cmd}} [path]', description: 'Remove a directory' -} +}; diff --git a/src/commands/registration/rnfr.js b/src/commands/registration/rnfr.js index 020b93a7..c84e59f2 100644 --- a/src/commands/registration/rnfr.js +++ b/src/commands/registration/rnfr.js @@ -7,7 +7,7 @@ module.exports = { if (!this.fs.get) return this.reply(402, 'Not supported by file system'); const fileName = command._[1]; - return when(this.fs.get(fileName)) + return when.try(this.fs.get.bind(this.fs), fileName) .then(() => { this.renameFrom = fileName; return this.reply(350); diff --git a/src/commands/registration/rnto.js b/src/commands/registration/rnto.js index dcfb4b3b..755c7145 100644 --- a/src/commands/registration/rnto.js +++ b/src/commands/registration/rnto.js @@ -11,7 +11,7 @@ module.exports = { const from = this.renameFrom; const to = command._[1]; - return when(this.fs.rename(from, to)) + return when.try(this.fs.rename.bind(this.fs), from, to) .then(() => { return this.reply(250); }) @@ -21,8 +21,8 @@ module.exports = { }) .finally(() => { delete this.renameFrom; - }) + }); }, syntax: '{{cmd}} [name]', description: 'Rename to' -} +}; diff --git a/src/commands/registration/site/chmod.js b/src/commands/registration/site/chmod.js index 9210a951..e0954c04 100644 --- a/src/commands/registration/site/chmod.js +++ b/src/commands/registration/site/chmod.js @@ -1,14 +1,16 @@ +const when = require('when'); + module.exports = function ({log, command} = {}) { if (!this.fs) return this.reply(550, 'File system not instantiated'); if (!this.fs.chmod) return this.reply(402, 'Not supported by file system'); const [, mode, fileName] = command._; - return this.fs.chmod(fileName, parseInt(mode, 8)) + return when.try(this.fs.chmod.bind(this.fs), fileName, parseInt(mode, 8)) .then(() => { return this.reply(200); }) .catch(err => { log.error(err); return this.reply(500); - }) + }); }; diff --git a/src/commands/registration/site/index.js b/src/commands/registration/site/index.js index bc3b0be3..ee1a04ab 100644 --- a/src/commands/registration/site/index.js +++ b/src/commands/registration/site/index.js @@ -14,10 +14,10 @@ module.exports = { const subCommand = { _: [subverb, ...subparameters], directive: subverb - } + }; const handler = registry[subverb].handler.bind(this); return when.try(handler, { log: subLog, command: subCommand }); }, syntax: '{{cmd}} [subVerb] [subParams]', description: 'Sends site specific commands to remote server' -} +}; diff --git a/src/commands/registration/size.js b/src/commands/registration/size.js index d9fc6609..2f1a6258 100644 --- a/src/commands/registration/size.js +++ b/src/commands/registration/size.js @@ -6,7 +6,7 @@ module.exports = { if (!this.fs) return this.reply(550, 'File system not instantiated'); if (!this.fs.get) return this.reply(402, 'Not supported by file system'); - return when(this.fs.get(command._[1])) + return when.try(this.fs.get.bind(this.fs), command._[1]) .then(fileStat => { return this.reply(213, {message: fileStat.size}); }) @@ -20,4 +20,4 @@ module.exports = { flags: { feat: 'SIZE' } -} +}; diff --git a/src/commands/registration/stat.js b/src/commands/registration/stat.js index ab236c5f..4aa18434 100644 --- a/src/commands/registration/stat.js +++ b/src/commands/registration/stat.js @@ -6,15 +6,17 @@ module.exports = { directive: 'STAT', handler: function (args = {}) { const {log, command} = args; - const path = command._[1]; + const path = _.get(command, '_[1]'); if (path) { if (!this.fs) return this.reply(550, 'File system not instantiated'); if (!this.fs.get) return this.reply(402, 'Not supported by file system'); - return when(this.fs.get(path)) + return when.try(this.fs.get.bind(this.fs), path) .then(stat => { if (stat.isDirectory()) { - return when(this.fs.list(path)) + if (!this.fs.list) return this.reply(402, 'Not supported by file system'); + + return when.try(this.fs.list.bind(this.fs), path) .then(files => { const fileList = files.map(file => { const message = getFileStat(file, _.get(this, 'server.options.file_format', 'ls')); @@ -22,21 +24,21 @@ module.exports = { raw: true, message }; - }) + }); return this.reply(213, 'Status begin', ...fileList, 'Status end'); - }) + }); } else { - return this.reply(212, getFileStat(stat, _.get(this, 'server.options.file_format', 'ls'))) + return this.reply(212, getFileStat(stat, _.get(this, 'server.options.file_format', 'ls'))); } }) .catch(err => { log.error(err); return this.reply(450); - }) + }); } else { return this.reply(211, 'Status OK'); } }, syntax: '{{cmd}} [path(optional)]', description: 'Returns the current status' -} +}; diff --git a/src/commands/registration/stor.js b/src/commands/registration/stor.js index cc8d910b..2575d67b 100644 --- a/src/commands/registration/stor.js +++ b/src/commands/registration/stor.js @@ -15,7 +15,7 @@ module.exports = { this.commandSocket.pause(); dataSocket = socket; }) - .then(() => when(this.fs.write(fileName, {append}))) + .then(() => when.try(this.fs.write.bind(this.fs), fileName, {append})) .then(stream => { return when.promise((resolve, reject) => { stream.on('error', err => dataSocket.emit('error', err)); @@ -41,4 +41,4 @@ module.exports = { }, syntax: '{{cmd}} [path]', description: 'Store data as a file at the server site' -} +}; diff --git a/src/commands/registration/stou.js b/src/commands/registration/stou.js index 9582315f..6720bb61 100644 --- a/src/commands/registration/stou.js +++ b/src/commands/registration/stou.js @@ -1,3 +1,5 @@ +const when = require('when'); + const stor = require('./stor').handler; module.exports = { @@ -7,9 +9,11 @@ module.exports = { if (!this.fs.get || !this.fs.getUniqueName) return this.reply(402, 'Not supported by file system'); const fileName = args.command._[1]; - return this.fs.get(fileName) - .catch(() => fileName) // does not exist, name is unique - .then(() => this.fs.getUniqueName()) // exists, must create new unique name + return when.try(() => { + return when.try(this.fs.get.bind(this.fs), fileName) + .then(() => when.try(this.fs.getUniqueName.bind(this.fs))) + .catch(() => when.resolve(fileName)); + }) .then(name => { args.command._[1] = name; return stor.call(this, args); diff --git a/src/commands/registration/stru.js b/src/commands/registration/stru.js index 68470c15..cb4484dd 100644 --- a/src/commands/registration/stru.js +++ b/src/commands/registration/stru.js @@ -8,4 +8,4 @@ module.exports = { flags: { obsolete: true } -} +}; diff --git a/src/commands/registration/syst.js b/src/commands/registration/syst.js index 1b1e1552..5e65d817 100644 --- a/src/commands/registration/syst.js +++ b/src/commands/registration/syst.js @@ -8,4 +8,4 @@ module.exports = { flags: { no_auth: true } -} +}; diff --git a/src/commands/registration/type.js b/src/commands/registration/type.js index b139fbdd..81b622a9 100644 --- a/src/commands/registration/type.js +++ b/src/commands/registration/type.js @@ -1,20 +1,20 @@ const _ = require('lodash'); +const ENCODING_TYPES = { + A: 'utf-8', + I: 'binary', + L: 'binary' +}; + module.exports = { directive: 'TYPE', handler: function ({command} = {}) { const encoding = _.upperCase(command._[1]); - switch (encoding) { - case 'A': - this.encoding = 'utf-8'; - case 'I': - case 'L': - this.encoding = 'binary'; - return this.reply(200); - default: - return this.reply(501); - } + if (!ENCODING_TYPES.hasOwnProperty(encoding)) return this.reply(501); + + this.encoding = ENCODING_TYPES[encoding]; + return this.reply(200); }, syntax: '{{cmd}} [mode]', description: 'Set the transfer mode, binary (I) or utf-8 (A)' -} +}; diff --git a/src/commands/registration/user.js b/src/commands/registration/user.js index b8a26081..b7cb8ff3 100644 --- a/src/commands/registration/user.js +++ b/src/commands/registration/user.js @@ -2,7 +2,10 @@ module.exports = { directive: 'USER', handler: function ({log, command} = {}) { if (this.username) return this.reply(530, 'Username already set'); + this.username = command._[1]; + if (!this.username) return this.reply(501, 'Must send username requirement'); + if (this.server.options.anonymous === true) { return this.login(this.username, '@anonymous') .then(() => { @@ -20,4 +23,4 @@ module.exports = { flags: { no_auth: true } -} +}; diff --git a/src/commands/registry.js b/src/commands/registry.js index 12ab5726..86f19e39 100644 --- a/src/commands/registry.js +++ b/src/commands/registry.js @@ -1,3 +1,4 @@ +/* eslint no-return-assign: 0 */ const commands = [ require('./registration/abor'), require('./registration/allo'), diff --git a/src/connection.js b/src/connection.js index 3fa7fdc1..bda0d03c 100644 --- a/src/connection.js +++ b/src/connection.js @@ -3,7 +3,6 @@ const uuid = require('uuid'); const when = require('when'); const sequence = require('when/sequence'); const parseCommandString = require('minimist-string'); -const net = require('net'); const BaseConnector = require('./connector/base'); const FileSystem = require('./fs'); @@ -27,7 +26,7 @@ class FtpConnection { }); this.commandSocket.on('data', data => { const messages = _.compact(data.toString('utf-8').split('\r\n')); - const handleMessage = (message) => { + const handleMessage = message => { const command = parseCommandString(message); command.directive = _.upperCase(command._[0]); return this.commands.handle(command); @@ -60,11 +59,11 @@ class FtpConnection { return this.server.emit('login', {connection: this, username, password}); } }) - .then(({fs, cwd, blacklist = [], whitelist = []} = {}) => { + .then(({root = '/', cwd = '/', fs, blacklist = [], whitelist = []} = {}) => { this.authenticated = true; this.commands.blacklist = _.concat(this.commands.blacklist, blacklist); this.commands.whitelist = _.concat(this.commands.whitelist, whitelist); - this.fs = fs || new FileSystem(this, {cwd}); + this.fs = fs || new FileSystem(this, {root, cwd}); }); } @@ -73,7 +72,7 @@ class FtpConnection { if (typeof options === 'number') options = {code: options}; // allow passing in code as first param if (!Array.isArray(letters)) letters = [letters]; if (!letters.length) letters = [{}]; - return when.map(letters, (promise, index) => { + return when.map(letters, promise => { return when(promise) .then(letter => { if (!letter) letter = {}; @@ -86,16 +85,16 @@ class FtpConnection { .then(message => { letter.message = message; return letter; - }) + }); }); }); - } + }; const processLetter = (letter, index) => { return when.promise((resolve, reject) => { const seperator = !options.hasOwnProperty('eol') ? - (letters.length - 1 === index ? ' ' : '-') : - (options.eol ? ' ' : '-'); + letters.length - 1 === index ? ' ' : '-' : + options.eol ? ' ' : '-'; const packet = !letter.raw ? _.compact([letter.code || options.code, letter.message]).join(seperator) : letter.message; if (letter.socket && letter.socket.writable) { @@ -109,10 +108,10 @@ class FtpConnection { }); } else reject(new errors.SocketError('Socket not writable')); }); - } + }; return satisfyParameters() - .then(letters => sequence(letters.map((letter, index) => processLetter.bind(this, letter, index)))) + .then(satisfiedLetters => sequence(satisfiedLetters.map((letter, index) => processLetter.bind(this, letter, index)))) .catch(err => { this.log.error(err); }); diff --git a/src/connector/active.js b/src/connector/active.js index b4dde230..9aceabbd 100644 --- a/src/connector/active.js +++ b/src/connector/active.js @@ -1,4 +1,4 @@ -const net = require('net'); +const {Socket} = require('net'); const when = require('when'); const Connector = require('./base'); @@ -20,11 +20,11 @@ class Active extends Connector { setupConnection(host, port) { const closeExistingServer = () => this.dataSocket ? when(this.dataSocket.destroy()) : - when.resolve() + when.resolve(); return closeExistingServer() .then(() => { - this.dataSocket = new net.Socket(); + this.dataSocket = new Socket(); this.dataSocket.setEncoding(this.encoding); this.dataSocket.connect({ host, port }, () => { this.dataSocket.pause(); diff --git a/src/connector/passive.js b/src/connector/passive.js index 8ed2662a..42c3c05f 100644 --- a/src/connector/passive.js +++ b/src/connector/passive.js @@ -25,7 +25,7 @@ class Passive extends Connector { setupServer() { const closeExistingServer = () => this.dataServer ? when.promise(resolve => this.dataServer.close(() => resolve())) : - when.resolve() + when.resolve(); return closeExistingServer() .then(() => this.getPort()) @@ -78,7 +78,7 @@ class Passive extends Connector { [this.server.options.pasv_range]; return findPort(min, max); } else return undefined; - }; + } } module.exports = Passive; diff --git a/src/fs.js b/src/fs.js index c0a6a881..f54936eb 100644 --- a/src/fs.js +++ b/src/fs.js @@ -9,10 +9,21 @@ const errors = require('./errors'); class FileSystem { constructor(connection, { + root = '/', cwd = '/' } = {}) { this.connection = connection; this.cwd = cwd; + this.root = root; + } + + _resolvePath(path) { + const pathParts = { + root: this.root, + base: nodePath.resolve(this.cwd, path) + }; + path = nodePath.format(pathParts); + return path; } currentDirectory() { @@ -20,13 +31,13 @@ class FileSystem { } get(fileName) { - const path = nodePath.resolve(this.cwd, fileName); + const path = this._resolvePath(fileName); return fs.stat(path) .then(stat => _.set(stat, 'name', fileName)); } list(path = '.') { - path = nodePath.resolve(this.cwd, path); + path = this._resolvePath(path); return fs.readdir(path) .then(fileNames => { return when.map(fileNames, fileName => { @@ -43,26 +54,26 @@ class FileSystem { } chdir(path = '.') { - path = nodePath.resolve(this.cwd, path); + path = this._resolvePath(path); return fs.stat(path) .tap(stat => { if (!stat.isDirectory()) throw new errors.FileSystemError('Not a valid directory'); }) .then(() => { - this.cwd = path; - return this.cwd; + this.cwd = path.replace(new RegExp(`^${this.root}`), '') || '/'; + return this.currentDirectory(); }); } write(fileName, {append = false} = {}) { - const path = nodePath.resolve(this.cwd, fileName); + const path = this._resolvePath(fileName); const stream = syncFs.createWriteStream(path, {flags: !append ? 'w+' : 'a+'}); stream.on('error', () => fs.unlink(path)); return stream; } read(fileName) { - const path = nodePath.resolve(this.cwd, fileName); + const path = this._resolvePath(fileName); return fs.stat(path) .tap(stat => { if (stat.isDirectory()) throw new errors.FileSystemError('Cannot read a directory'); @@ -74,28 +85,28 @@ class FileSystem { } delete(path) { - path = nodePath.resolve(this.cwd, path); + path = this._resolvePath(path); return fs.stat(path) .then(stat => { if (stat.isDirectory()) return fs.rmdir(path); else return fs.unlink(path); - }) + }); } mkdir(path) { - path = nodePath.resolve(this.cwd, path); + path = this._resolvePath(path); return fs.mkdir(path) .then(() => path); } rename(from, to) { - const fromPath = nodePath.resolve(this.cwd, from); - const toPath = nodePath.resolve(this.cwd, to); + const fromPath = this._resolvePath(from); + const toPath = this._resolvePath(to); return fs.rename(fromPath, toPath); } chmod(path, mode) { - path = nodePath.resolve(this.cwd, path); + path = this._resolvePath(path); return fs.chmod(path, mode); } diff --git a/src/helpers/escape-path.js b/src/helpers/escape-path.js index 6c4f4ef0..b3916f58 100644 --- a/src/helpers/escape-path.js +++ b/src/helpers/escape-path.js @@ -1,4 +1,4 @@ module.exports = function (path) { return path .replace(/"/g, '""'); -} +}; diff --git a/src/helpers/file-stat.js b/src/helpers/file-stat.js index 49e5e9ad..fb2f6551 100644 --- a/src/helpers/file-stat.js +++ b/src/helpers/file-stat.js @@ -1,19 +1,19 @@ const _ = require('lodash'); -const format = require('date-fns/format'); +const dateFns = require('date-fns'); const errors = require('../errors'); module.exports = function (fileStat, format = 'ls') { if (typeof format === 'function') return format(fileStat); const formats = { - 'ls': ls, - 'ep': ep + ls: ls, + ep: ep }; if (!formats.hasOwnProperty(format)) { throw new errors.FileSystemError('Bad file stat formatter'); } return formats[format](fileStat); -} +}; function ls(fileStat) { return [ @@ -35,7 +35,7 @@ function ls(fileStat) { fileStat.uid, fileStat.gid, _.padStart(fileStat.size, 12), - _.padStart(format(fileStat.mtime, 'MMM DD HH:mm'), 12), + _.padStart(dateFns.format(fileStat.mtime, 'MMM DD HH:mm'), 12), fileStat.name ].join(' '); } @@ -44,7 +44,7 @@ function ep(fileStat) { const facts = [ fileStat.dev && fileStat.ino ? `i${fileStat.dev.toString(16)}.${fileStat.ino.toString(16)}` : null, fileStat.size ? `s${fileStat.size}` : null, - fileStat.mtime ? `m${format(fileStat.mtime, 'X')}` : null, + fileStat.mtime ? `m${dateFns.format(dateFns.parse(fileStat.mtime), 'X')}` : null, fileStat.mode ? `up${fileStat.mode.toString(8).substr(fileStat.mode.toString(8).length - 3)}` : null, fileStat.isDirectory() ? 'r' : '/' ].join(','); diff --git a/src/helpers/find-port.js b/src/helpers/find-port.js index 750469b1..2df83b3b 100644 --- a/src/helpers/find-port.js +++ b/src/helpers/find-port.js @@ -14,7 +14,7 @@ module.exports = function (min = 22, max = undefined) { } else { reject(new errors.GeneralError('Unable to find open port', 500)); } - }) + }); portCheckServer.on('listening', () => { const {port} = portCheckServer.address(); portCheckServer.close(() => { diff --git a/src/helpers/resolve-host.js b/src/helpers/resolve-host.js index 1889f9b7..d3ccf9c3 100644 --- a/src/helpers/resolve-host.js +++ b/src/helpers/resolve-host.js @@ -21,5 +21,5 @@ module.exports = function (hostname) { }); }); } else resolve(hostname); - }) -} + }); +}; diff --git a/src/index.js b/src/index.js index 3fecd267..171ffb54 100644 --- a/src/index.js +++ b/src/index.js @@ -70,27 +70,28 @@ class FtpServer { if (features.length) { features.unshift('Features:'); - features.push('.') + features.push('.'); } return features.length ? features.join(' ') : 'Ready'; } - setGreeting(gretting) { + setGreeting(greeting) { if (typeof greeting === 'string') { this.options.greeting = greeting; } else { - gretting.then(greeting => { - this.options.gretting = greeting; - }) + greeting.then(greet => { + this.options.greeting = greet; + }); } } disconnectClient(id) { - return when.promise((resolve, reject) => { + return when.promise(resolve => { const client = this.connections[id]; if (!client) return resolve(); delete this.connections[id]; - return client.close(0); + client.close(0); + resolve(); }); } diff --git a/test/commands/abor.spec.js b/test/commands/abor.spec.js new file mode 100644 index 00000000..89f50bfb --- /dev/null +++ b/test/commands/abor.spec.js @@ -0,0 +1,53 @@ +const when = require('when'); +const {expect} = require('chai'); +const sinon = require('sinon'); + +const CMD = 'ABOR'; +describe(CMD, function () { + let sandbox; + const mockClient = { + reply: () => when.resolve(), + connector: { + waitForConnection: () => when.resolve(), + end: () => when.resolve() + } + }; + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + + sandbox.spy(mockClient, 'reply'); + sandbox.spy(mockClient.connector, 'waitForConnection'); + sandbox.spy(mockClient.connector, 'end'); + }); + afterEach(() => { + sandbox.restore(); + }); + + it('// successful | no active connection', done => { + mockClient.connector.waitForConnection.restore(); + sandbox.stub(mockClient.connector, 'waitForConnection').rejects(); + + cmdFn() + .then(() => { + expect(mockClient.connector.waitForConnection.callCount).to.equal(1); + expect(mockClient.connector.end.callCount).to.equal(0); + expect(mockClient.reply.args[0][0]).to.equal(226); + done(); + }) + .catch(done); + }); + + it('// successful | active connection', done => { + cmdFn() + .then(() => { + expect(mockClient.connector.waitForConnection.callCount).to.equal(1); + expect(mockClient.connector.end.callCount).to.equal(1); + expect(mockClient.reply.args[0][0]).to.equal(426); + expect(mockClient.reply.args[1][0]).to.equal(226); + done(); + }) + .catch(done); + }); +}); diff --git a/test/commands/allo.spec.js b/test/commands/allo.spec.js index 5ee192a9..327e5ae1 100644 --- a/test/commands/allo.spec.js +++ b/test/commands/allo.spec.js @@ -1,14 +1,14 @@ const when = require('when'); const {expect} = require('chai'); -const sinon = require('sinon') +const sinon = require('sinon'); const CMD = 'ALLO'; -describe(CMD, done => { +describe(CMD, function () { let sandbox; const mockClient = { reply: () => when.resolve() }; - const CMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); beforeEach(() => { sandbox = sinon.sandbox.create(); @@ -20,11 +20,11 @@ describe(CMD, done => { }); it('// successful', done => { - CMDFN() + cmdFn() .then(() => { - expect(mockClient.reply.args[0][0]).to.equal(202) + expect(mockClient.reply.args[0][0]).to.equal(202); done(); }) .catch(done); - }) + }); }); diff --git a/test/commands/auth.spec.js b/test/commands/auth.spec.js index adcf6765..e7541425 100644 --- a/test/commands/auth.spec.js +++ b/test/commands/auth.spec.js @@ -1,14 +1,14 @@ const when = require('when'); const {expect} = require('chai'); -const sinon = require('sinon') +const sinon = require('sinon'); const CMD = 'AUTH'; -describe(CMD, done => { +describe(CMD, function () { let sandbox; const mockClient = { reply: () => when.resolve() }; - const CMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); beforeEach(() => { sandbox = sinon.sandbox.create(); @@ -20,27 +20,27 @@ describe(CMD, done => { }); it('TLS // not supported', done => { - CMDFN({command: {_: [CMD, 'TLS'], directive: CMD}}) + cmdFn({command: {_: [CMD, 'TLS'], directive: CMD}}) .then(() => { - expect(mockClient.reply.args[0][0]).to.equal(504) + expect(mockClient.reply.args[0][0]).to.equal(504); done(); }) .catch(done); }); it('SSL // not supported', done => { - CMDFN({command: {_: [CMD, 'SSL'], directive: CMD}}) + cmdFn({command: {_: [CMD, 'SSL'], directive: CMD}}) .then(() => { - expect(mockClient.reply.args[0][0]).to.equal(504) + expect(mockClient.reply.args[0][0]).to.equal(504); done(); }) .catch(done); }); it('bad // bad', done => { - CMDFN({command: {_: [CMD, 'bad'], directive: CMD}}) + cmdFn({command: {_: [CMD, 'bad'], directive: CMD}}) .then(() => { - expect(mockClient.reply.args[0][0]).to.equal(504) + expect(mockClient.reply.args[0][0]).to.equal(504); done(); }) .catch(done); diff --git a/test/commands/cdup.spec.js b/test/commands/cdup.spec.js index 06f0a79f..60d2d9c6 100644 --- a/test/commands/cdup.spec.js +++ b/test/commands/cdup.spec.js @@ -4,7 +4,7 @@ const {expect} = require('chai'); const sinon = require('sinon'); const CMD = 'CDUP'; -describe(CMD, done => { +describe(CMD, function () { let sandbox; let log = bunyan.createLogger({name: CMD}); const mockClient = { @@ -13,7 +13,7 @@ describe(CMD, done => { chdir: () => when.resolve() } }; - const CMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); beforeEach(() => { sandbox = sinon.sandbox.create(); @@ -26,7 +26,7 @@ describe(CMD, done => { }); it('.. // successful', done => { - CMDFN({log, command: {_: [CMD], directive: CMD}}) + cmdFn({log, command: {_: [CMD], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(250); expect(mockClient.fs.chdir.args[0][0]).to.equal('..'); diff --git a/test/commands/cwd.spec.js b/test/commands/cwd.spec.js index 44fc9a5a..522003a6 100644 --- a/test/commands/cwd.spec.js +++ b/test/commands/cwd.spec.js @@ -1,23 +1,21 @@ -const when = require('when'); const bunyan = require('bunyan'); const {expect} = require('chai'); const sinon = require('sinon'); -require('sinon-as-promised'); const CMD = 'CWD'; -describe(CMD, done => { +describe(CMD, function () { let sandbox; let log = bunyan.createLogger({name: CMD}); const mockClient = { reply: () => {}, fs: { chdir: () => {} } }; - const CMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); beforeEach(() => { sandbox = sinon.sandbox.create(); - sandbox.stub(mockClient, 'reply').resolves() + sandbox.stub(mockClient, 'reply').resolves(); sandbox.stub(mockClient.fs, 'chdir').resolves(); }); afterEach(() => { @@ -27,9 +25,9 @@ describe(CMD, done => { describe('// check', function () { it('fails on no fs', done => { const badMockClient = { reply: () => {} }; - const BADCMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); + const badCmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); sandbox.stub(badMockClient, 'reply').resolves(); - BADCMDFN() + badCmdFn() .then(() => { expect(badMockClient.reply.args[0][0]).to.equal(550); done(); @@ -39,9 +37,9 @@ describe(CMD, done => { it('fails on no fs chdir command', done => { const badMockClient = { reply: () => {}, fs: {} }; - const BADCMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); + const badCmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); sandbox.stub(badMockClient, 'reply').resolves(); - BADCMDFN() + badCmdFn() .then(() => { expect(badMockClient.reply.args[0][0]).to.equal(402); done(); @@ -51,7 +49,7 @@ describe(CMD, done => { }); it('test // successful', done => { - CMDFN({log, command: {_: [CMD, 'test'], directive: CMD}}) + cmdFn({log, command: {_: [CMD, 'test'], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(250); expect(mockClient.fs.chdir.args[0][0]).to.equal('test'); @@ -63,7 +61,7 @@ describe(CMD, done => { it('test // successful', done => { mockClient.fs.chdir.restore(); sandbox.stub(mockClient.fs, 'chdir').resolves('/test'); - CMDFN({log, command: {_: [CMD, 'test'], directive: CMD}}) + cmdFn({log, command: {_: [CMD, 'test'], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(250); expect(mockClient.fs.chdir.args[0][0]).to.equal('test'); @@ -74,9 +72,9 @@ describe(CMD, done => { it('bad // unsuccessful', done => { mockClient.fs.chdir.restore(); - sandbox.stub(mockClient.fs, 'chdir').rejects(new Error('Bad')) + sandbox.stub(mockClient.fs, 'chdir').rejects(new Error('Bad')); - CMDFN({log, command: {_: [CMD, 'bad'], directive: CMD}}) + cmdFn({log, command: {_: [CMD, 'bad'], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(550); expect(mockClient.fs.chdir.args[0][0]).to.equal('bad'); diff --git a/test/commands/dele.spec.js b/test/commands/dele.spec.js index 92e32916..f356a7fe 100644 --- a/test/commands/dele.spec.js +++ b/test/commands/dele.spec.js @@ -1,18 +1,16 @@ -const when = require('when'); const bunyan = require('bunyan'); const {expect} = require('chai'); const sinon = require('sinon'); -require('sinon-as-promised'); const CMD = 'DELE'; -describe(CMD, done => { +describe(CMD, function () { let sandbox; let log = bunyan.createLogger({name: CMD}); const mockClient = { reply: () => {}, fs: { delete: () => {} } }; - const CMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); beforeEach(() => { sandbox = sinon.sandbox.create(); @@ -27,9 +25,9 @@ describe(CMD, done => { describe('// check', function () { it('fails on no fs', done => { const badMockClient = { reply: () => {} }; - const BADCMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); + const badCmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); sandbox.stub(badMockClient, 'reply').resolves(); - BADCMDFN() + badCmdFn() .then(() => { expect(badMockClient.reply.args[0][0]).to.equal(550); done(); @@ -39,9 +37,9 @@ describe(CMD, done => { it('fails on no fs delete command', done => { const badMockClient = { reply: () => {}, fs: {} }; - const BADCMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); + const badCmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); sandbox.stub(badMockClient, 'reply').resolves(); - BADCMDFN() + badCmdFn() .then(() => { expect(badMockClient.reply.args[0][0]).to.equal(402); done(); @@ -51,7 +49,7 @@ describe(CMD, done => { }); it('test // successful', done => { - CMDFN({log, command: {_: [CMD, 'test'], directive: CMD}}) + cmdFn({log, command: {_: [CMD, 'test'], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(250); expect(mockClient.fs.delete.args[0][0]).to.equal('test'); @@ -62,9 +60,9 @@ describe(CMD, done => { it('bad // unsuccessful', done => { mockClient.fs.delete.restore(); - sandbox.stub(mockClient.fs, 'delete').rejects(new Error('Bad')) + sandbox.stub(mockClient.fs, 'delete').rejects(new Error('Bad')); - CMDFN({log, command: {_: [CMD, 'bad'], directive: CMD}}) + cmdFn({log, command: {_: [CMD, 'bad'], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(550); expect(mockClient.fs.delete.args[0][0]).to.equal('bad'); diff --git a/test/commands/help.spec.js b/test/commands/help.spec.js index 53095744..7410e78c 100644 --- a/test/commands/help.spec.js +++ b/test/commands/help.spec.js @@ -1,14 +1,14 @@ const when = require('when'); const {expect} = require('chai'); -const sinon = require('sinon') +const sinon = require('sinon'); const CMD = 'HELP'; -describe(CMD, done => { +describe(CMD, function () { let sandbox; const mockClient = { reply: () => when.resolve() }; - const CMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); beforeEach(() => { sandbox = sinon.sandbox.create(); @@ -20,7 +20,7 @@ describe(CMD, done => { }); it('// successful', done => { - CMDFN({command: {_: [CMD], directive: CMD}}) + cmdFn({command: {_: [CMD], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(211); done(); @@ -29,7 +29,7 @@ describe(CMD, done => { }); it('help // successful', done => { - CMDFN({command: {_: [CMD, 'help'], directive: CMD}}) + cmdFn({command: {_: [CMD, 'help'], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(214); done(); @@ -38,7 +38,7 @@ describe(CMD, done => { }); it('help // successful', done => { - CMDFN({command: {_: [CMD, 'allo'], directive: CMD}}) + cmdFn({command: {_: [CMD, 'allo'], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(214); done(); @@ -47,7 +47,7 @@ describe(CMD, done => { }); it('bad // unsuccessful', done => { - CMDFN({command: {_: [CMD, 'bad'], directive: CMD}}) + cmdFn({command: {_: [CMD, 'bad'], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(502); done(); diff --git a/test/commands/list.spec.js b/test/commands/list.spec.js index eaa49347..f9f0fa14 100644 --- a/test/commands/list.spec.js +++ b/test/commands/list.spec.js @@ -2,17 +2,16 @@ const when = require('when'); const bunyan = require('bunyan'); const {expect} = require('chai'); const sinon = require('sinon'); -require('sinon-as-promised')(when.Promise); const CMD = 'LIST'; -describe(CMD, done => { +describe(CMD, function () { let sandbox; let log = bunyan.createLogger({name: CMD}); const mockClient = { reply: () => {}, fs: { list: () => {} }, connector: { - waitForConnection: () => {}, + waitForConnection: () => when({}), end: () => {} }, commandSocket: { @@ -20,14 +19,12 @@ describe(CMD, done => { pause: () => {} } }; - const mockSocket = {}; - const CMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); beforeEach(() => { sandbox = sinon.sandbox.create(); sandbox.stub(mockClient, 'reply').resolves(); - sandbox.stub(mockClient.connector, 'waitForConnection').resolves(mockSocket); sandbox.stub(mockClient.fs, 'list').resolves([{ name: 'test1', dev: 2114, @@ -54,9 +51,9 @@ describe(CMD, done => { describe('// check', function () { it('fails on no fs', done => { const badMockClient = { reply: () => {} }; - const BADCMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); + const badCmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); sandbox.stub(badMockClient, 'reply').resolves(); - BADCMDFN() + badCmdFn() .then(() => { expect(badMockClient.reply.args[0][0]).to.equal(550); done(); @@ -66,9 +63,9 @@ describe(CMD, done => { it('fails on no fs list command', done => { const badMockClient = { reply: () => {}, fs: {} }; - const BADCMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); + const badCmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); sandbox.stub(badMockClient, 'reply').resolves(); - BADCMDFN() + badCmdFn() .then(() => { expect(badMockClient.reply.args[0][0]).to.equal(402); done(); @@ -78,7 +75,7 @@ describe(CMD, done => { }); it('. // successful', done => { - CMDFN({log, command: {_: [CMD], directive: CMD}}) + cmdFn({log, command: {_: [CMD], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(150); expect(mockClient.reply.args[1][1]).to.have.property('raw'); @@ -94,7 +91,7 @@ describe(CMD, done => { mockClient.fs.list.restore(); sandbox.stub(mockClient.fs, 'list').rejects(new Error()); - CMDFN({log, command: {_: [CMD], directive: CMD}}) + cmdFn({log, command: {_: [CMD], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(451); done(); @@ -103,10 +100,9 @@ describe(CMD, done => { }); it('. // unsuccessful (timeout)', done => { - mockClient.connector.waitForConnection.restore(); - sandbox.stub(mockClient.connector, 'waitForConnection').rejects(new when.TimeoutError()); + sandbox.stub(mockClient.connector, 'waitForConnection').returns(when.reject(new when.TimeoutError())); - CMDFN({log, command: {_: [CMD], directive: CMD}}) + cmdFn({log, command: {_: [CMD], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(425); done(); diff --git a/test/commands/mdtm.spec.js b/test/commands/mdtm.spec.js index 2e9c43e6..7bcb721d 100644 --- a/test/commands/mdtm.spec.js +++ b/test/commands/mdtm.spec.js @@ -1,19 +1,16 @@ -const when = require('when'); const bunyan = require('bunyan'); const {expect} = require('chai'); const sinon = require('sinon'); -require('sinon-as-promised')(when.Promise); const CMD = 'MDTM'; -describe(CMD, done => { +describe(CMD, function () { let sandbox; let log = bunyan.createLogger({name: CMD}); const mockClient = { reply: () => {}, fs: { get: () => {} } }; - const mockSocket = {}; - const CMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); beforeEach(() => { sandbox = sinon.sandbox.create(); @@ -28,9 +25,9 @@ describe(CMD, done => { describe('// check', function () { it('fails on no fs', done => { const badMockClient = { reply: () => {} }; - const BADCMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); + const badCmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); sandbox.stub(badMockClient, 'reply').resolves(); - BADCMDFN() + badCmdFn() .then(() => { expect(badMockClient.reply.args[0][0]).to.equal(550); done(); @@ -40,9 +37,9 @@ describe(CMD, done => { it('fails on no fs get command', done => { const badMockClient = { reply: () => {}, fs: {} }; - const BADCMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); + const badCmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); sandbox.stub(badMockClient, 'reply').resolves(); - BADCMDFN() + badCmdFn() .then(() => { expect(badMockClient.reply.args[0][0]).to.equal(402); done(); @@ -52,7 +49,7 @@ describe(CMD, done => { }); it('. // successful', done => { - CMDFN({log, command: {_: [CMD], directive: CMD}}) + cmdFn({log, command: {_: [CMD], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(213); //expect(mockClient.reply.args[0][1]).to.equal('20111010172411.000'); @@ -65,7 +62,7 @@ describe(CMD, done => { mockClient.fs.get.restore(); sandbox.stub(mockClient.fs, 'get').rejects(new Error()); - CMDFN({log, command: {_: [CMD], directive: CMD}}) + cmdFn({log, command: {_: [CMD], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(550); done(); diff --git a/test/commands/mkd.spec.js b/test/commands/mkd.spec.js index 1b91077e..8f4863d9 100644 --- a/test/commands/mkd.spec.js +++ b/test/commands/mkd.spec.js @@ -1,18 +1,16 @@ -const when = require('when'); const bunyan = require('bunyan'); const {expect} = require('chai'); const sinon = require('sinon'); -require('sinon-as-promised'); const CMD = 'MKD'; -describe(CMD, done => { +describe(CMD, function () { let sandbox; let log = bunyan.createLogger({name: CMD}); const mockClient = { reply: () => {}, fs: { mkdir: () => {} } }; - const CMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); beforeEach(() => { sandbox = sinon.sandbox.create(); @@ -27,9 +25,9 @@ describe(CMD, done => { describe('// check', function () { it('fails on no fs', done => { const badMockClient = { reply: () => {} }; - const BADCMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); + const badCmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); sandbox.stub(badMockClient, 'reply').resolves(); - BADCMDFN() + badCmdFn() .then(() => { expect(badMockClient.reply.args[0][0]).to.equal(550); done(); @@ -39,9 +37,9 @@ describe(CMD, done => { it('fails on no fs mkdir command', done => { const badMockClient = { reply: () => {}, fs: {} }; - const BADCMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); + const badCmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); sandbox.stub(badMockClient, 'reply').resolves(); - BADCMDFN() + badCmdFn() .then(() => { expect(badMockClient.reply.args[0][0]).to.equal(402); done(); @@ -51,7 +49,7 @@ describe(CMD, done => { }); it('test // successful', done => { - CMDFN({log, command: {_: [CMD, 'test'], directive: CMD}}) + cmdFn({log, command: {_: [CMD, 'test'], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(257); expect(mockClient.fs.mkdir.args[0][0]).to.equal('test'); @@ -63,7 +61,7 @@ describe(CMD, done => { it('test // successful', done => { mockClient.fs.mkdir.restore(); sandbox.stub(mockClient.fs, 'mkdir').resolves('test'); - CMDFN({log, command: {_: [CMD, 'test'], directive: CMD}}) + cmdFn({log, command: {_: [CMD, 'test'], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(257); expect(mockClient.fs.mkdir.args[0][0]).to.equal('test'); @@ -74,9 +72,9 @@ describe(CMD, done => { it('bad // unsuccessful', done => { mockClient.fs.mkdir.restore(); - sandbox.stub(mockClient.fs, 'mkdir').rejects(new Error('Bad')) + sandbox.stub(mockClient.fs, 'mkdir').rejects(new Error('Bad')); - CMDFN({log, command: {_: [CMD, 'bad'], directive: CMD}}) + cmdFn({log, command: {_: [CMD, 'bad'], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(550); expect(mockClient.fs.mkdir.args[0][0]).to.equal('bad'); diff --git a/test/commands/mode.spec.js b/test/commands/mode.spec.js index 87f7239b..7054f12a 100644 --- a/test/commands/mode.spec.js +++ b/test/commands/mode.spec.js @@ -1,14 +1,14 @@ const when = require('when'); const {expect} = require('chai'); -const sinon = require('sinon') +const sinon = require('sinon'); const CMD = 'MODE'; -describe(CMD, done => { +describe(CMD, function () { let sandbox; const mockClient = { reply: () => when.resolve() }; - const CMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); beforeEach(() => { sandbox = sinon.sandbox.create(); @@ -20,18 +20,18 @@ describe(CMD, done => { }); it('S // successful', done => { - CMDFN({command: {_: [CMD, 'S']}}) + cmdFn({command: {_: [CMD, 'S']}}) .then(() => { - expect(mockClient.reply.args[0][0]).to.equal(200) + expect(mockClient.reply.args[0][0]).to.equal(200); done(); }) .catch(done); }); it('Q // unsuccessful', done => { - CMDFN({command: {_: [CMD, 'Q']}}) + cmdFn({command: {_: [CMD, 'Q']}}) .then(() => { - expect(mockClient.reply.args[0][0]).to.equal(504) + expect(mockClient.reply.args[0][0]).to.equal(504); done(); }) .catch(done); diff --git a/test/commands/nlst.spec.js b/test/commands/nlst.spec.js index 4b6bfb13..09d089f4 100644 --- a/test/commands/nlst.spec.js +++ b/test/commands/nlst.spec.js @@ -2,17 +2,16 @@ const when = require('when'); const bunyan = require('bunyan'); const {expect} = require('chai'); const sinon = require('sinon'); -require('sinon-as-promised')(when.Promise); const CMD = 'NLST'; -describe(CMD, done => { +describe(CMD, function () { let sandbox; let log = bunyan.createLogger({name: CMD}); const mockClient = { reply: () => {}, fs: { list: () => {} }, connector: { - waitForConnection: () => {}, + waitForConnection: () => when({}), end: () => {} }, commandSocket: { @@ -20,14 +19,12 @@ describe(CMD, done => { pause: () => {} } }; - const mockSocket = {}; - const CMDFN = require(`../../src/commands/registration/list`).handler.bind(mockClient); + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); beforeEach(() => { sandbox = sinon.sandbox.create(); sandbox.stub(mockClient, 'reply').resolves(); - sandbox.stub(mockClient.connector, 'waitForConnection').resolves(mockSocket); sandbox.stub(mockClient.fs, 'list').resolves([{ name: 'test1', dev: 2114, @@ -52,7 +49,7 @@ describe(CMD, done => { }); it('. // successful', done => { - CMDFN({log, command: {_: [CMD], directive: CMD}}) + cmdFn({log, command: {_: [CMD], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(150); expect(mockClient.reply.args[1][1]).to.have.property('raw'); diff --git a/test/commands/noop.spec.js b/test/commands/noop.spec.js index bb34ae5d..34bc52a0 100644 --- a/test/commands/noop.spec.js +++ b/test/commands/noop.spec.js @@ -1,14 +1,14 @@ const when = require('when'); const {expect} = require('chai'); -const sinon = require('sinon') +const sinon = require('sinon'); const CMD = 'NOOP'; -describe(CMD, done => { +describe(CMD, function () { let sandbox; const mockClient = { reply: () => when.resolve() }; - const CMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); beforeEach(() => { sandbox = sinon.sandbox.create(); @@ -20,11 +20,11 @@ describe(CMD, done => { }); it('// successful', done => { - CMDFN() + cmdFn() .then(() => { - expect(mockClient.reply.args[0][0]).to.equal(200) + expect(mockClient.reply.args[0][0]).to.equal(200); done(); }) .catch(done); - }) + }); }); diff --git a/test/commands/opts.spec.js b/test/commands/opts.spec.js index 548cc2dc..a079e8c0 100644 --- a/test/commands/opts.spec.js +++ b/test/commands/opts.spec.js @@ -1,14 +1,14 @@ const when = require('when'); const {expect} = require('chai'); -const sinon = require('sinon') +const sinon = require('sinon'); const CMD = 'OPTS'; -describe(CMD, done => { +describe(CMD, function () { let sandbox; const mockClient = { reply: () => when.resolve() }; - const CMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); beforeEach(() => { sandbox = sinon.sandbox.create(); @@ -20,11 +20,11 @@ describe(CMD, done => { }); it('// successful', done => { - CMDFN() + cmdFn() .then(() => { - expect(mockClient.reply.args[0][0]).to.equal(501) + expect(mockClient.reply.args[0][0]).to.equal(501); done(); }) .catch(done); - }) + }); }); diff --git a/test/commands/pass.spec.js b/test/commands/pass.spec.js index 6ccecbd6..33dccd74 100644 --- a/test/commands/pass.spec.js +++ b/test/commands/pass.spec.js @@ -1,11 +1,9 @@ -const when = require('when'); const bunyan = require('bunyan'); const {expect} = require('chai'); const sinon = require('sinon'); -require('sinon-as-promised'); const CMD = 'PASS'; -describe(CMD, done => { +describe(CMD, function () { let sandbox; let log = bunyan.createLogger({name: CMD}); const mockClient = { @@ -14,7 +12,7 @@ describe(CMD, done => { server: { options: { anonymous: false } }, username: 'user' }; - const CMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); beforeEach(() => { sandbox = sinon.sandbox.create(); @@ -27,7 +25,7 @@ describe(CMD, done => { }); it('pass // successful', done => { - CMDFN({log, command: {_: [CMD, 'pass'], directive: CMD}}) + cmdFn({log, command: {_: [CMD, 'pass'], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(230); expect(mockClient.login.args[0]).to.eql(['user', 'pass']); @@ -39,7 +37,7 @@ describe(CMD, done => { it('// successful (anonymous)', done => { mockClient.server.options.anonymous = true; mockClient.authenticated = true; - CMDFN({log, command: {_: [CMD], directive: CMD}}) + cmdFn({log, command: {_: [CMD], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(230); expect(mockClient.login.callCount).to.equal(0); @@ -54,7 +52,7 @@ describe(CMD, done => { mockClient.login.restore(); sandbox.stub(mockClient, 'login').rejects('bad'); - CMDFN({log, command: {_: [CMD, 'bad'], directive: CMD}}) + cmdFn({log, command: {_: [CMD, 'bad'], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(530); done(); @@ -64,9 +62,9 @@ describe(CMD, done => { it('bad // unsuccessful', done => { mockClient.login.restore(); - sandbox.stub(mockClient, 'login').rejects({}) + sandbox.stub(mockClient, 'login').rejects({}); - CMDFN({log, command: {_: [CMD, 'bad'], directive: CMD}}) + cmdFn({log, command: {_: [CMD, 'bad'], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(530); done(); @@ -76,7 +74,7 @@ describe(CMD, done => { it('bad // unsuccessful', done => { delete mockClient.username; - CMDFN({log, command: {_: [CMD, 'bad'], directive: CMD}}) + cmdFn({log, command: {_: [CMD, 'bad'], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(503); done(); diff --git a/test/commands/port.spec.js b/test/commands/port.spec.js new file mode 100644 index 00000000..af02e05a --- /dev/null +++ b/test/commands/port.spec.js @@ -0,0 +1,54 @@ +const when = require('when'); +const {expect} = require('chai'); +const sinon = require('sinon'); + +const ActiveConnector = require('../../src/connector/active'); + +const CMD = 'PORT'; +describe(CMD, function () { + let sandbox; + const mockClient = { + reply: () => when.resolve() + }; + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + + sandbox.spy(mockClient, 'reply'); + sandbox.stub(ActiveConnector.prototype, 'setupConnection').resolves(); + }); + afterEach(() => { + sandbox.restore(); + }); + + it('// unsuccessful | no argument', done => { + cmdFn() + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(425); + done(); + }) + .catch(done); + }); + + it('// unsuccessful | invalid argument', done => { + cmdFn({ command: { _: [CMD, '1,2,3,4,5'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(425); + done(); + }) + .catch(done); + }); + + it('// successful', done => { + cmdFn({ command: { _: [CMD, '192,168,0,100,137,214'] } }) + .then(() => { + const [ip, port] = ActiveConnector.prototype.setupConnection.args[0]; + expect(mockClient.reply.args[0][0]).to.equal(200); + expect(ip).to.equal('192.168.0.100'); + expect(port).to.equal(35286); + done(); + }) + .catch(done); + }); +}); diff --git a/test/commands/pwd.spec.js b/test/commands/pwd.spec.js index 59291d10..457b8ccd 100644 --- a/test/commands/pwd.spec.js +++ b/test/commands/pwd.spec.js @@ -1,23 +1,21 @@ -const when = require('when'); const bunyan = require('bunyan'); const {expect} = require('chai'); const sinon = require('sinon'); -require('sinon-as-promised'); const CMD = 'PWD'; -describe(CMD, done => { +describe(CMD, function () { let sandbox; let log = bunyan.createLogger({name: CMD}); const mockClient = { reply: () => {}, fs: { currentDirectory: () => {} } }; - const CMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); beforeEach(() => { sandbox = sinon.sandbox.create(); - sandbox.stub(mockClient, 'reply').resolves() + sandbox.stub(mockClient, 'reply').resolves(); sandbox.stub(mockClient.fs, 'currentDirectory').resolves(); }); afterEach(() => { @@ -27,9 +25,9 @@ describe(CMD, done => { describe('// check', function () { it('fails on no fs', done => { const badMockClient = { reply: () => {} }; - const BADCMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); + const badCmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); sandbox.stub(badMockClient, 'reply').resolves(); - BADCMDFN() + badCmdFn() .then(() => { expect(badMockClient.reply.args[0][0]).to.equal(550); done(); @@ -39,9 +37,9 @@ describe(CMD, done => { it('fails on no fs currentDirectory command', done => { const badMockClient = { reply: () => {}, fs: {} }; - const BADCMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); + const badCmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(badMockClient); sandbox.stub(badMockClient, 'reply').resolves(); - BADCMDFN() + badCmdFn() .then(() => { expect(badMockClient.reply.args[0][0]).to.equal(402); done(); @@ -51,7 +49,7 @@ describe(CMD, done => { }); it('// successful', done => { - CMDFN({log, command: {_: [CMD, 'test'], directive: CMD}}) + cmdFn({log, command: {_: [CMD, 'test'], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(257); done(); @@ -61,9 +59,9 @@ describe(CMD, done => { it('// successful', done => { mockClient.fs.currentDirectory.restore(); - sandbox.stub(mockClient.fs, 'currentDirectory').resolves('/test') + sandbox.stub(mockClient.fs, 'currentDirectory').resolves('/test'); - CMDFN({log, command: {_: [CMD, 'test'], directive: CMD}}) + cmdFn({log, command: {_: [CMD, 'test'], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(257); done(); @@ -73,9 +71,9 @@ describe(CMD, done => { it('// unsuccessful', done => { mockClient.fs.currentDirectory.restore(); - sandbox.stub(mockClient.fs, 'currentDirectory').rejects(new Error('Bad')) + sandbox.stub(mockClient.fs, 'currentDirectory').rejects(new Error('Bad')); - CMDFN({log, command: {_: [CMD, 'bad'], directive: CMD}}) + cmdFn({log, command: {_: [CMD, 'bad'], directive: CMD}}) .then(() => { expect(mockClient.reply.args[0][0]).to.equal(550); done(); diff --git a/test/commands/quit.spec.js b/test/commands/quit.spec.js index dbf0ae3e..a35b45f0 100644 --- a/test/commands/quit.spec.js +++ b/test/commands/quit.spec.js @@ -1,17 +1,13 @@ -const when = require('when'); -const bunyan = require('bunyan'); const {expect} = require('chai'); const sinon = require('sinon'); -require('sinon-as-promised'); const CMD = 'QUIT'; -describe(CMD, done => { +describe(CMD, function () { let sandbox; - let log = bunyan.createLogger({name: CMD}); const mockClient = { close: () => {} }; - const CMDFN = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); beforeEach(() => { sandbox = sinon.sandbox.create(); @@ -23,7 +19,7 @@ describe(CMD, done => { }); it('// successful', done => { - CMDFN() + cmdFn() .then(() => { expect(mockClient.close.callCount).to.equal(1); done(); diff --git a/test/commands/rnfr.spec.js b/test/commands/rnfr.spec.js new file mode 100644 index 00000000..44fa5153 --- /dev/null +++ b/test/commands/rnfr.spec.js @@ -0,0 +1,70 @@ +const when = require('when'); +const {expect} = require('chai'); +const sinon = require('sinon'); + +const CMD = 'RNFR'; +describe(CMD, function () { + let sandbox; + const mockLog = { error: () => {} }; + const mockClient = { reply: () => when.resolve() }; + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + + mockClient.renameFrom = 'test'; + mockClient.fs = { + get: () => when.resolve() + }; + + sandbox.spy(mockClient, 'reply'); + sandbox.spy(mockClient.fs, 'get'); + }); + afterEach(() => { + sandbox.restore(); + }); + + it('// unsuccessful | no file system', done => { + delete mockClient.fs; + + cmdFn() + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(550); + done(); + }) + .catch(done); + }); + + it('// unsuccessful | file system does not have functions', done => { + mockClient.fs = {}; + + cmdFn() + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(402); + done(); + }) + .catch(done); + }); + + it('test // unsuccessful | file get fails', done => { + mockClient.fs.get.restore(); + sandbox.stub(mockClient.fs, 'get').rejects(new Error('test')); + + cmdFn({ log: mockLog, command: { _: [CMD, 'test'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(550); + done(); + }) + .catch(done); + }); + + it('test // successful', done => { + cmdFn({ log: mockLog, command: { _: [CMD, 'test'] } }) + .then(() => { + expect(mockClient.fs.get.args[0][0]).to.equal('test'); + expect(mockClient.reply.args[0][0]).to.equal(350); + done(); + }) + .catch(done); + }); +}); diff --git a/test/commands/rnto.spec.js b/test/commands/rnto.spec.js new file mode 100644 index 00000000..587671cd --- /dev/null +++ b/test/commands/rnto.spec.js @@ -0,0 +1,82 @@ +const when = require('when'); +const {expect} = require('chai'); +const sinon = require('sinon'); + +const CMD = 'RNTO'; +describe(CMD, function () { + let sandbox; + const mockLog = { error: () => {} }; + const mockClient = { reply: () => when.resolve() }; + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + + mockClient.renameFrom = 'test'; + mockClient.fs = { + get: () => when.resolve(), + rename: () => when.resolve() + }; + + sandbox.spy(mockClient, 'reply'); + sandbox.spy(mockClient.fs, 'rename'); + }); + afterEach(() => { + sandbox.restore(); + }); + + it('// unsuccessful | no renameFrom set', done => { + delete mockClient.renameFrom; + + cmdFn() + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(503); + done(); + }) + .catch(done); + }); + + it('// unsuccessful | no file system', done => { + delete mockClient.fs; + + cmdFn() + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(550); + done(); + }) + .catch(done); + }); + + it('// unsuccessful | file system does not have functions', done => { + mockClient.fs = {}; + + cmdFn() + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(402); + done(); + }) + .catch(done); + }); + + it('new // unsuccessful | rename fails', done => { + mockClient.fs.rename.restore(); + sandbox.stub(mockClient.fs, 'rename').rejects(new Error('test')); + + cmdFn({ log: mockLog, command: { _: [CMD, 'new'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(550); + done(); + }) + .catch(done); + }); + + it('new // successful', done => { + cmdFn({ command: { _: [CMD, 'new'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(250); + expect(mockClient.fs.rename.args[0]).to.eql(['test', 'new']); + done(); + }) + .catch(done); + }); +}); diff --git a/test/commands/site/chmod.spec.js b/test/commands/site/chmod.spec.js new file mode 100644 index 00000000..56d92064 --- /dev/null +++ b/test/commands/site/chmod.spec.js @@ -0,0 +1,69 @@ +const when = require('when'); +const {expect} = require('chai'); +const sinon = require('sinon'); + +const CMD = 'CHMOD'; +describe(CMD, function () { + let sandbox; + const mockLog = { error: () => {} }; + const mockClient = { reply: () => when.resolve() }; + const cmdFn = require(`../../../src/commands/registration/site/${CMD.toLowerCase()}`).bind(mockClient); + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + + mockClient.fs = { + chmod: () => when.resolve() + }; + + sandbox.spy(mockClient, 'reply'); + sandbox.spy(mockClient.fs, 'chmod'); + }); + afterEach(() => { + sandbox.restore(); + }); + + it('// unsuccessful | no file system', done => { + delete mockClient.fs; + + cmdFn() + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(550); + done(); + }) + .catch(done); + }); + + it('// unsuccessful | file system does not have functions', done => { + mockClient.fs = {}; + + cmdFn() + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(402); + done(); + }) + .catch(done); + }); + + it('777 test // unsuccessful | file chmod fails', done => { + mockClient.fs.chmod.restore(); + sandbox.stub(mockClient.fs, 'chmod').rejects(new Error('test')); + + cmdFn({ log: mockLog, command: { _: [CMD, '777', 'test'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(500); + done(); + }) + .catch(done); + }); + + it('777 test // successful', done => { + cmdFn({ log: mockLog, command: { _: [CMD, '777', 'test'] } }) + .then(() => { + expect(mockClient.fs.chmod.args[0]).to.eql(['test', 511]); + expect(mockClient.reply.args[0][0]).to.equal(200); + done(); + }) + .catch(done); + }); +}); diff --git a/test/commands/size.spec.js b/test/commands/size.spec.js new file mode 100644 index 00000000..1cfa9bfd --- /dev/null +++ b/test/commands/size.spec.js @@ -0,0 +1,66 @@ +const when = require('when'); +const {expect} = require('chai'); +const sinon = require('sinon'); + +const CMD = 'SIZE'; +describe(CMD, function () { + let sandbox; + const mockLog = { error: () => {} }; + const mockClient = { reply: () => when.resolve() }; + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + + mockClient.fs = { + get: () => when.resolve({size: 1}) + }; + + sandbox.spy(mockClient, 'reply'); + }); + afterEach(() => { + sandbox.restore(); + }); + + it('// unsuccessful | no file system', done => { + delete mockClient.fs; + + cmdFn() + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(550); + done(); + }) + .catch(done); + }); + + it('// unsuccessful | file system does not have functions', done => { + mockClient.fs = {}; + + cmdFn() + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(402); + done(); + }) + .catch(done); + }); + + it('// unsuccessful | file get fails', done => { + sandbox.stub(mockClient.fs, 'get').rejects(new Error('test')); + + cmdFn({ log: mockLog, command: { _: [CMD, 'test'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(550); + done(); + }) + .catch(done); + }); + + it('// successful', done => { + cmdFn({ command: { _: [CMD, 'test'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(213); + done(); + }) + .catch(done); + }); +}); diff --git a/test/commands/stat.spec.js b/test/commands/stat.spec.js new file mode 100644 index 00000000..4a699262 --- /dev/null +++ b/test/commands/stat.spec.js @@ -0,0 +1,142 @@ +const when = require('when'); +const {expect} = require('chai'); +const sinon = require('sinon'); + +const CMD = 'STAT'; +describe(CMD, function () { + let sandbox; + const mockLog = { error: () => {} }; + const mockClient = { reply: () => when.resolve() }; + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + + mockClient.fs = { + get: () => when.resolve({}), + list: () => when.resolve([]) + }; + + sandbox.spy(mockClient, 'reply'); + }); + afterEach(() => { + sandbox.restore(); + }); + + it('// successful', done => { + cmdFn() + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(211); + done(); + }) + .catch(done); + }); + + it('// unsuccessful | no file system', done => { + delete mockClient.fs; + + cmdFn({ command: { _: [CMD, 'test'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(550); + done(); + }) + .catch(done); + }); + + it('// unsuccessful | file system does not have functions', done => { + mockClient.fs = {}; + + cmdFn({ command: { _: [CMD, 'test'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(402); + done(); + }) + .catch(done); + }); + + it('// unsuccessful | file get fails', done => { + sandbox.stub(mockClient.fs, 'get').rejects(new Error('test')); + + cmdFn({ log: mockLog, command: { _: [CMD, 'test'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(450); + done(); + }) + .catch(done); + }); + + it('// successful | file', done => { + sandbox.stub(mockClient.fs, 'get').returns({ + name: 'test_file', + dev: 2114, + ino: 48064969, + mode: 33188, + nlink: 1, + uid: 85, + gid: 100, + rdev: 0, + size: 527, + blksize: 4096, + blocks: 8, + atime: 'Mon, 10 Oct 2011 23:24:11 GMT', + mtime: 'Mon, 10 Oct 2011 23:24:11 GMT', + ctime: 'Mon, 10 Oct 2011 23:24:11 GMT', + birthtime: 'Mon, 10 Oct 2011 23:24:11 GMT', + isDirectory: () => false + }); + + cmdFn({ command: { _: [CMD, 'test'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(212); + done(); + }) + .catch(done); + }); + + it('// successful | directory', done => { + sandbox.stub(mockClient.fs, 'list').returns([{ + name: 'test_file', + dev: 2114, + ino: 48064969, + mode: 33188, + nlink: 1, + uid: 85, + gid: 100, + rdev: 0, + size: 527, + blksize: 4096, + blocks: 8, + atime: 'Mon, 10 Oct 2011 23:24:11 GMT', + mtime: 'Mon, 10 Oct 2011 23:24:11 GMT', + ctime: 'Mon, 10 Oct 2011 23:24:11 GMT', + birthtime: 'Mon, 10 Oct 2011 23:24:11 GMT', + isDirectory: () => false + }]); + + sandbox.stub(mockClient.fs, 'get').returns({ + name: 'test_directory', + dev: 2114, + ino: 48064969, + mode: 33188, + nlink: 1, + uid: 85, + gid: 100, + rdev: 0, + size: 527, + blksize: 4096, + blocks: 8, + atime: 'Mon, 10 Oct 2011 23:24:11 GMT', + mtime: 'Mon, 10 Oct 2011 23:24:11 GMT', + ctime: 'Mon, 10 Oct 2011 23:24:11 GMT', + birthtime: 'Mon, 10 Oct 2011 23:24:11 GMT', + isDirectory: () => true + }); + + cmdFn({ command: { _: [CMD, 'test'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(213); + done(); + }) + .catch(done); + }); +}); diff --git a/test/commands/stou.spec.js b/test/commands/stou.spec.js new file mode 100644 index 00000000..fae5943d --- /dev/null +++ b/test/commands/stou.spec.js @@ -0,0 +1,83 @@ +const when = require('when'); +const {expect} = require('chai'); +const sinon = require('sinon'); + +const stor = require('../../src/commands/registration/stor'); + +const CMD = 'STOU'; +describe(CMD, function () { + let sandbox; + const mockClient = { + reply: () => when.resolve() + }; + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + + mockClient.fs = { + get: () => when.resolve(), + getUniqueName: () => when.resolve('4') + }; + + sandbox.spy(mockClient, 'reply'); + sandbox.spy(mockClient.fs, 'get'); + sandbox.spy(mockClient.fs, 'getUniqueName'); + + sandbox.stub(stor.handler, 'call').resolves({}); + }); + afterEach(() => { + sandbox.restore(); + }); + + it('// unsuccessful | no file system', done => { + delete mockClient.fs; + + cmdFn() + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(550); + done(); + }) + .catch(done); + }); + + it('// unsuccessful | file system does not have functions', done => { + mockClient.fs = {}; + + cmdFn() + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(402); + done(); + }) + .catch(done); + }); + + it('// successful | given name is unique', done => { + mockClient.fs.get.restore(); + sandbox.stub(mockClient.fs, 'get').rejects({}); + + cmdFn({ command: { _: [CMD, 'good'] } }) + .then(() => { + const call = stor.handler.call.args[0][1]; + expect(call).to.have.property('command'); + expect(call.command).to.have.property('_'); + expect(call.command._).to.eql([CMD, 'good']); + expect(mockClient.fs.getUniqueName.callCount).to.equal(0); + done(); + }) + .catch(done); + }); + + it('// successful | generates unique name', done => { + cmdFn({ command: { _: [CMD, 'bad'] } }) + .then(() => { + const call = stor.handler.call.args[0][1]; + expect(call).to.have.property('command'); + expect(call.command).to.have.property('_'); + expect(call.command._).to.eql([CMD, '4']); + expect(mockClient.fs.getUniqueName.callCount).to.equal(1); + done(); + }) + .catch(done); + }); +}); diff --git a/test/commands/stru.spec.js b/test/commands/stru.spec.js new file mode 100644 index 00000000..6d03cd85 --- /dev/null +++ b/test/commands/stru.spec.js @@ -0,0 +1,39 @@ +const when = require('when'); +const {expect} = require('chai'); +const sinon = require('sinon'); + +const CMD = 'STRU'; +describe(CMD, function () { + let sandbox; + const mockClient = { + reply: () => when.resolve() + }; + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + + sandbox.spy(mockClient, 'reply'); + }); + afterEach(() => { + sandbox.restore(); + }); + + it('// successful', done => { + cmdFn({command: { _: [CMD, 'F'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(200); + done(); + }) + .catch(done); + }); + + it('// unsuccessful', done => { + cmdFn({command: { _: [CMD, 'X'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(504); + done(); + }) + .catch(done); + }); +}); diff --git a/test/commands/syst.spec.js b/test/commands/syst.spec.js new file mode 100644 index 00000000..449e3b8f --- /dev/null +++ b/test/commands/syst.spec.js @@ -0,0 +1,30 @@ +const when = require('when'); +const {expect} = require('chai'); +const sinon = require('sinon'); + +const CMD = 'SYST'; +describe(CMD, function () { + let sandbox; + const mockClient = { + reply: () => when.resolve() + }; + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + + sandbox.spy(mockClient, 'reply'); + }); + afterEach(() => { + sandbox.restore(); + }); + + it('// successful', done => { + cmdFn() + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(215); + done(); + }) + .catch(done); + }); +}); diff --git a/test/commands/type.spec.js b/test/commands/type.spec.js new file mode 100644 index 00000000..53f5a0a7 --- /dev/null +++ b/test/commands/type.spec.js @@ -0,0 +1,62 @@ +const when = require('when'); +const {expect} = require('chai'); +const sinon = require('sinon'); + +const CMD = 'TYPE'; +describe(CMD, function () { + let sandbox; + const mockClient = { + reply: () => when.resolve() + }; + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + + mockClient.encoding = null; + sandbox.spy(mockClient, 'reply'); + }); + afterEach(() => { + sandbox.restore(); + }); + + it('A // successful', done => { + cmdFn({ command: { _: [CMD, 'A'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(200); + expect(mockClient.encoding).to.equal('utf-8'); + done(); + }) + .catch(done); + }); + + it('I // successful', done => { + cmdFn({ command: { _: [CMD, 'I'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(200); + expect(mockClient.encoding).to.equal('binary'); + done(); + }) + .catch(done); + }); + + it('L // successful', done => { + cmdFn({ command: { _: [CMD, 'L'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(200); + expect(mockClient.encoding).to.equal('binary'); + done(); + }) + .catch(done); + }); + + it('X // successful', done => { + cmdFn({ command: { _: [CMD, 'X'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(501); + expect(mockClient.encoding).to.equal(null); + done(); + }) + .catch(done); + }); +}); diff --git a/test/commands/user.spec.js b/test/commands/user.spec.js new file mode 100644 index 00000000..860f65a1 --- /dev/null +++ b/test/commands/user.spec.js @@ -0,0 +1,88 @@ +const when = require('when'); +const {expect} = require('chai'); +const sinon = require('sinon'); + +const CMD = 'USER'; +describe(CMD, function () { + let sandbox; + const mockLog = { + error: () => {} + }; + const mockClient = { + reply: () => when.resolve(), + server: { options: {} }, + login: () => when.resolve() + }; + const cmdFn = require(`../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient); + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + + delete mockClient.username; + mockClient.server.options = {}; + + sandbox.spy(mockClient, 'reply'); + sandbox.spy(mockClient, 'login'); + }); + afterEach(() => { + sandbox.restore(); + }); + + it('test // successful | prompt for password', done => { + cmdFn({ command: { _: [CMD, 'test'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(331); + done(); + }) + .catch(done); + }); + + it('test // successful | anonymous login', done => { + mockClient.server.options = {anonymous: true}; + + cmdFn({ command: { _: [CMD, 'test'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(230); + expect(mockClient.login.callCount).to.equal(1); + done(); + }) + .catch(done); + }); + + it('test // unsuccessful | no username provided', done => { + cmdFn({ command: { _: [CMD] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(501); + expect(mockClient.login.callCount).to.equal(0); + done(); + }) + .catch(done); + }); + + it('test // unsuccessful | already set username', done => { + mockClient.username = 'test'; + + cmdFn({ command: { _: [CMD, 'test'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(530); + expect(mockClient.login.callCount).to.equal(0); + done(); + }) + .catch(done); + }); + + it('test // unsuccessful | login function rejects', done => { + mockClient.server.options = {anonymous: true}; + + mockClient.login.restore(); + sandbox.stub(mockClient, 'login').rejects(new Error('test')); + + cmdFn({ log: mockLog, command: { _: [CMD, 'test'] } }) + .then(() => { + expect(mockClient.reply.args[0][0]).to.equal(530); + expect(mockClient.login.callCount).to.equal(1); + done(); + }) + .catch(done); + }); +}); diff --git a/test/connector/active.spec.js b/test/connector/active.spec.js new file mode 100644 index 00000000..4fa2913b --- /dev/null +++ b/test/connector/active.spec.js @@ -0,0 +1,66 @@ +/* eslint no-unused-expressions: 0 */ +const {expect} = require('chai'); +const sinon = require('sinon'); + +const net = require('net'); + +const ActiveConnector = require('../../src/connector/active'); +const findPort = require('../../src/helpers/find-port'); + +describe('Connector - Active //', function () { + let PORT; + let active; + let mockConnection = {}; + let sandbox; + let server; + + before(() => { + active = new ActiveConnector(mockConnection); + }); + beforeEach(done => { + sandbox = sinon.sandbox.create(); + + findPort() + .then(port => { + PORT = port; + server = net.createServer() + .on('connection', socket => socket.destroy()) + .listen(PORT, () => done()); + }); + }); + afterEach(done => { + sandbox.restore(); + server.close(done); + }); + + it('sets up a connection', function (done) { + active.setupConnection('127.0.0.1', PORT) + .then(() => { + expect(active.dataSocket).to.exist; + done(); + }) + .catch(done); + }); + + it('destroys existing connection, then sets up a connection', function (done) { + const destroyFnSpy = sandbox.spy(active.dataSocket, 'destroy'); + + active.setupConnection('127.0.0.1', PORT) + .then(() => { + expect(destroyFnSpy.callCount).to.equal(1); + expect(active.dataSocket).to.exist; + done(); + }) + .catch(done); + }); + + it('waits for connection', function (done) { + active.setupConnection('127.0.0.1', PORT) + .then(() => { + expect(active.dataSocket).to.exist; + return active.waitForConnection(); + }) + .then(() => done()) + .catch(done); + }); +}); diff --git a/test/connector/passive.spec.js b/test/connector/passive.spec.js new file mode 100644 index 00000000..2c22dffe --- /dev/null +++ b/test/connector/passive.spec.js @@ -0,0 +1,112 @@ +/* eslint no-unused-expressions: 0 */ +const {expect} = require('chai'); +const sinon = require('sinon'); + +const when = require('when'); +const net = require('net'); +const bunyan = require('bunyan'); + +const PassiveConnector = require('../../src/connector/passive'); + +describe('Connector - Passive //', function () { + let passive; + let mockConnection = { + reply: () => when.resolve({}), + close: () => when.resolve({}), + encoding: 'utf8', + log: bunyan.createLogger({name: 'passive-test'}), + commandSocket: {}, + server: { options: {} } + }; + let sandbox; + + before(() => { + passive = new PassiveConnector(mockConnection); + }); + beforeEach(() => { + sandbox = sinon.sandbox.create(); + + sandbox.spy(mockConnection, 'reply'); + + mockConnection.commandSocket.remoteAddress = '::ffff:127.0.0.1'; + mockConnection.server.options.pasv_range = '8000'; + }); + afterEach(() => { + sandbox.restore(); + }); + + it('cannot wait for connection with no server', function (done) { + passive.waitForConnection() + .then(() => done('should not happen')) + .catch(err => { + expect(err.name).to.equal('ConnectorError'); + done(); + }); + }); + + it('has invalid pasv range', function (done) { + delete mockConnection.server.options.pasv_range; + + passive.setupServer() + .then(() => done('should not happen')) + .catch(err => { + expect(err.name).to.equal('RangeError'); + done(); + }); + }); + + it('sets up a server', function (done) { + passive.setupServer() + .then(() => { + expect(passive.dataServer).to.exist; + done(); + }) + .catch(done); + }); + + it('destroys existing server, then sets up a server', function (done) { + const closeFnSpy = sandbox.spy(passive.dataServer, 'close'); + + passive.setupServer() + .then(() => { + expect(closeFnSpy.callCount).to.equal(1); + expect(passive.dataServer).to.exist; + done(); + }) + .catch(done); + }); + + it('refuses connection with different remote address', function (done) { + mockConnection.commandSocket.remoteAddress = 'bad'; + + passive.setupServer() + .then(() => { + expect(passive.dataServer).to.exist; + + const {port} = passive.dataServer.address(); + net.createConnection(port, () => { + expect(mockConnection.reply.callCount).to.equal(1); + expect(mockConnection.reply.args[0][0]).to.equal(550); + done(); + }); + }) + .catch(done); + }); + + it('accepts connection', function (done) { + passive.setupServer() + .then(() => { + expect(passive.dataServer).to.exist; + + const {port} = passive.dataServer.address(); + net.createConnection(port); + return passive.waitForConnection(); + }) + .then(() => { + expect(passive.dataSocket).to.exist; + passive.end(); + done(); + }) + .catch(done); + }); +}); diff --git a/test/helpers/file-stat.spec.js b/test/helpers/file-stat.spec.js index 8b65e00e..e5136a1c 100644 --- a/test/helpers/file-stat.spec.js +++ b/test/helpers/file-stat.spec.js @@ -1,8 +1,10 @@ const {expect} = require('chai'); +const dateFns = require('date-fns'); + const fileStat = require('../../src/helpers/file-stat'); const errors = require('../../src/errors'); -describe.skip('helpers // file-stat', function () { +describe('helpers // file-stat', function () { const STAT = { name: 'test1', dev: 2114, @@ -22,14 +24,14 @@ describe.skip('helpers // file-stat', function () { isDirectory: () => false }; - describe('format - ls //', function () { + describe.skip('format - ls //', function () { it('formats correctly', () => { const format = fileStat(STAT, 'ls'); expect(format).to.equal('-rwxrw-r-- 1 85 100 527 Oct 10 17:24 test1'); }); }); - describe('format - ep //', function () { + describe.skip('format - ep //', function () { it('formats correctly', () => { const format = fileStat(STAT, 'ep'); expect(format).to.equal('+i842.2dd69c9,s527,m1318289051,up644,/ test1'); @@ -43,11 +45,11 @@ describe.skip('helpers // file-stat', function () { }); it('formats correctly', () => { - function customerFormater(fileStat) { - return [fileStat.gid, fileStat.name, fileStat.size].join('\t'); + function customerFormater(stat) { + return [stat.gid, stat.name, stat.size].join('\t'); } const format = fileStat(STAT, customerFormater); expect(format).to.equal('100\ttest1\t527'); - }) + }); }); }); diff --git a/test/helpers/find-port.spec.js b/test/helpers/find-port.spec.js index 86a0019d..cc894db6 100644 --- a/test/helpers/find-port.spec.js +++ b/test/helpers/find-port.spec.js @@ -1,3 +1,4 @@ +/* eslint no-unused-expressions: 0 */ const {expect} = require('chai'); const {Server} = require('net'); const sinon = require('sinon'); @@ -10,7 +11,7 @@ describe('helpers // find-port', function () { beforeEach(() => { sandbox = sinon.sandbox.create(); - sandbox.spy(Server.prototype, 'listen') + sandbox.spy(Server.prototype, 'listen'); }); afterEach(() => { sandbox.restore(); @@ -30,6 +31,7 @@ describe('helpers // find-port', function () { findPort(1, 2) .then(() => done('no')) .catch(err => { + expect(err).to.exist; done(); }); }); diff --git a/test/index.spec.js b/test/index.spec.js index 388e4f35..12ad80f6 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -1,9 +1,8 @@ +/* eslint no-unused-expressions: 0 */ require('dotenv').load(); -const _ = require('lodash'); const {expect} = require('chai'); const bunyan = require('bunyan'); const fs = require('fs'); -const sinon = require('sinon'); const FtpServer = require('../src'); const FtpClient = require('ftp'); @@ -19,10 +18,10 @@ describe('FtpServer', function () { log, pasv_range: process.env.PASV_RANGE }); - server.on('login', (data, resolve, reject) => { - resolve(); + server.on('login', (data, resolve) => { + resolve({root: process.cwd()}); }); - process.on('SIGINT', function() { + process.on('SIGINT', function () { server.close(); }); @@ -63,8 +62,17 @@ describe('FtpServer', function () { }); }); - it('CWD process.cwd()', done => { - const dir = require('path').resolve(process.cwd(), 'test'); + it('CWD ..', done => { + const dir = '..'; + client.cwd(`${dir}`, (err, data) => { + expect(err).to.not.exist; + expect(data).to.be.a('string'); + done(); + }); + }); + + it('CWD test', done => { + const dir = 'test'; client.cwd(`${dir}`, (err, data) => { expect(err).to.not.exist; expect(data).to.be.a('string'); @@ -100,7 +108,7 @@ describe('FtpServer', function () { done(); }); }); - }) + }); it('APPE test.txt', done => { const buffer = Buffer.from(', awesome!'); @@ -150,14 +158,14 @@ describe('FtpServer', function () { }); it('MDTM awesome.txt', done => { - client.lastMod('awesome.txt', (err, date) => { + client.lastMod('awesome.txt', err => { expect(err).to.not.exist; done(); }); }); it('SITE CHMOD 700 awesome.txt', done => { - client.site('CHMOD 600 awesome.txt', (err) => { + client.site('CHMOD 600 awesome.txt', err => { expect(err).to.not.exist; fs.stat('./test/awesome.txt', (fserr, stats) => { expect(fserr).to.not.exist; @@ -175,7 +183,7 @@ describe('FtpServer', function () { done(); }); }); - } + }; it('TYPE A', done => { client.ascii(err => { diff --git a/test/start.js b/test/start.js index be638a67..5c9a0a42 100644 --- a/test/start.js +++ b/test/start.js @@ -10,7 +10,7 @@ const server = new FtpServer(process.env.FTP_URL, { pasv_range: process.env.PASV_RANGE }); server.on('login', ({username, password}, resolve, reject) => { - if (username === 'test' && password === 'test') resolve(); + if (username === 'test' && password === 'test') resolve({ root: require('os').homedir() }); else reject('Bad username or password'); }); server.listen();