From dc469af25ce971747ce6f32f46eda08d5bff387f Mon Sep 17 00:00:00 2001 From: Jeffrey Morgan Date: Thu, 12 Feb 2015 22:51:26 -0800 Subject: [PATCH 1/5] Install docker & boot2docker binaries with Kitematic --- __tests__/SetupStore-test.js | 35 ++------------ src/ContainerStore.js | 2 +- src/Main.js | 3 +- src/Setup.react.js | 2 +- src/SetupStore.js | 94 +++++++++++++++++++++--------------- src/SetupUtil.js | 50 +++++++++---------- src/Util.js | 35 ++++++++++++++ src/VirtualBox.js | 5 +- 8 files changed, 125 insertions(+), 101 deletions(-) diff --git a/__tests__/SetupStore-test.js b/__tests__/SetupStore-test.js index bc44bb4bae..4134db3fb2 100644 --- a/__tests__/SetupStore-test.js +++ b/__tests__/SetupStore-test.js @@ -27,17 +27,6 @@ describe('SetupStore', function () { expect(setupUtil.download).toBeCalled(); }); }); - - pit('skips download if virtualbox is already installed', function () { - virtualBox.installed.mockReturnValue(true); - virtualBox.version.mockReturnValue(Promise.resolve('4.3.20')); - setupUtil.download.mockClear(); - setupUtil.download.mockReturnValue(Promise.resolve()); - setupUtil.compareVersions.mockReturnValue(1); - return setupStore.steps().downloadVirtualBox.run().then(() => { - expect(setupUtil.download).not.toBeCalled(); - }); - }); }); describe('install step', function () { @@ -46,7 +35,7 @@ describe('SetupStore', function () { virtualBox.killall.mockReturnValue(Promise.resolve()); setupUtil.isSudo.mockReturnValue(Promise.resolve(false)); util.exec.mockReturnValue(Promise.resolve()); - return setupStore.steps().installVirtualBox.run().then(() => { + return setupStore.steps().install.run().then(() => { // TODO: make sure that the right install command was executed expect(util.exec).toBeCalled(); }); @@ -59,26 +48,12 @@ describe('SetupStore', function () { setupUtil.isSudo.mockReturnValue(Promise.resolve(false)); setupUtil.compareVersions.mockReturnValue(-1); util.exec.mockReturnValue(Promise.resolve()); - return setupStore.steps().installVirtualBox.run().then(() => { + return setupStore.steps().install.run().then(() => { // TODO: make sure the right install command was executed expect(virtualBox.killall).toBeCalled(); expect(util.exec).toBeCalled(); }); }); - - pit('skips install if virtualbox is already installed', function () { - virtualBox.installed.mockReturnValue(true); - virtualBox.version.mockReturnValue(Promise.resolve('4.3.20')); - setupUtil.isSudo.mockReturnValue(Promise.resolve(false)); - setupUtil.compareVersions.mockReturnValue(-1); - util.exec.mockReturnValue(Promise.resolve()); - return setupStore.steps().installVirtualBox.run().then(() => { - virtualBox.killall.mockClear(); - util.exec.mockClear(); - expect(virtualBox.killall).not.toBeCalled(); - expect(util.exec).not.toBeCalled(); - }); - }); }); describe('init step', function () { @@ -86,7 +61,7 @@ describe('SetupStore', function () { pit('inintializes the boot2docker vm if it does not exist', function () { boot2docker.exists.mockReturnValue(Promise.resolve(false)); boot2docker.init.mockReturnValue(Promise.resolve()); - return setupStore.steps().initBoot2Docker.run().then(() => { + return setupStore.steps().init.run().then(() => { expect(boot2docker.init).toBeCalled(); }); }); @@ -98,7 +73,7 @@ describe('SetupStore', function () { boot2docker.stop.mockReturnValue(Promise.resolve()); boot2docker.upgrade.mockReturnValue(Promise.resolve()); setupUtil.compareVersions.mockReturnValue(-1); - return setupStore.steps().initBoot2Docker.run().then(() => { + return setupStore.steps().init.run().then(() => { boot2docker.init.mockClear(); expect(boot2docker.init).not.toBeCalled(); expect(boot2docker.upgrade).toBeCalled(); @@ -111,7 +86,7 @@ describe('SetupStore', function () { boot2docker.status.mockReturnValue(false); boot2docker.waitstatus.mockReturnValue(Promise.resolve()); boot2docker.start.mockReturnValue(Promise.resolve()); - return setupStore.steps().startBoot2Docker.run().then(() => { + return setupStore.steps().start.run().then(() => { expect(boot2docker.start).toBeCalled(); }); }); diff --git a/src/ContainerStore.js b/src/ContainerStore.js index 865ab765c6..1ec6b04b87 100644 --- a/src/ContainerStore.js +++ b/src/ContainerStore.js @@ -17,7 +17,7 @@ var _logs = {}; var _streams = {}; var _muted = {}; -var ContainerStore = assign(EventEmitter.prototype, { +var ContainerStore = assign(Object.create(EventEmitter.prototype), { CLIENT_CONTAINER_EVENT: 'client_container_event', CLIENT_RECOMMENDED_EVENT: 'client_recommended_event', SERVER_CONTAINER_EVENT: 'server_container_event', diff --git a/src/Main.js b/src/Main.js index 87919ac609..204a9877d3 100644 --- a/src/Main.js +++ b/src/Main.js @@ -8,7 +8,7 @@ var docker = require('./Docker'); var router = require('./router'); var boot2docker = require('./boot2docker'); var ContainerStore = require('./ContainerStore'); -var SetupStore = require('./ContainerStore'); +var SetupStore = require('./SetupStore'); var settingsjson; try { settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'settings.json'), 'utf8')); @@ -34,6 +34,7 @@ bugsnag.appVersion = app.getVersion(); router.run(Handler => React.render(, document.body)); if (!window.location.hash.length || window.location.hash === '#/') { SetupStore.run().then(boot2docker.ip).then(ip => { + console.log(ip); docker.setHost(ip); ContainerStore.init(function (err) { if (err) { console.log(err); } diff --git a/src/Setup.react.js b/src/Setup.react.js index b94e7766dd..bf8b430f64 100644 --- a/src/Setup.react.js +++ b/src/Setup.react.js @@ -83,7 +83,7 @@ var Setup = React.createClass({

Installation Cancelled

Couldn't Install VirtualBox

-

Kitematic did not receive the administrative privileges required to install VirtualBox.

+

Kitematic did not receive the administrative privileges required to install VirtualBox & Docker.

Please retry or download & install VirutalBox manually from the official Oracle website.

diff --git a/src/SetupStore.js b/src/SetupStore.js index 2489fcb35c..d5af39b9d4 100644 --- a/src/SetupStore.js +++ b/src/SetupStore.js @@ -1,5 +1,4 @@ var EventEmitter = require('events').EventEmitter; -var assign = require('object-assign'); var _ = require('underscore'); var path = require('path'); var Promise = require('bluebird'); @@ -7,70 +6,60 @@ var boot2docker = require('./Boot2Docker'); var virtualBox = require('./VirtualBox'); var setupUtil = require('./SetupUtil'); var util = require('./Util'); +var assign = require('object-assign'); -var SUDO_PROMPT = 'Kitematic requires administrative privileges to install VirtualBox.'; var _currentStep = null; var _error = null; var _cancelled = false; var _retryPromise = null; +var _requiredSteps = []; var _steps = [{ - name: 'downloadVirtualBox', + name: 'download', title: 'Downloading VirtualBox', message: 'VirtualBox is being downloaded. Kitematic requires VirtualBox to run containers.', totalPercent: 35, percent: 0, run: Promise.coroutine(function* (progressCallback) { var packagejson = util.packagejson(); - if (virtualBox.installed()) { - var version = yield virtualBox.version(); - if (setupUtil.compareVersions(version, packagejson['virtualbox-required-version']) >= 0) { - return; - } - } var virtualBoxFile = `https://github.com/kitematic/virtualbox/releases/download/${packagejson['virtualbox-version']}/${packagejson['virtualbox-filename']}`; - yield setupUtil.download(virtualBoxFile, path.join(setupUtil.supportDir(), packagejson['virtualbox-filename']), packagejson['virtualbox-checksum'], percent => { + yield setupUtil.download(virtualBoxFile, path.join(util.supportDir(), packagejson['virtualbox-filename']), packagejson['virtualbox-checksum'], percent => { progressCallback(percent); }); }) }, { - name: 'installVirtualBox', - title: 'Installing VirtualBox', - message: "VirtualBox is being installed in the background. We may need you to type in your password to continue.", + name: 'install', + title: 'Installing Docker & VirtualBox', + message: 'VirtualBox is being installed in the background. We may need you to type in your password to continue.', totalPercent: 5, percent: 0, seconds: 5, run: Promise.coroutine(function* () { var packagejson = util.packagejson(); - if (virtualBox.installed()) { - var version = yield virtualBox.version(); - if (setupUtil.compareVersions(version, packagejson['virtualbox-required-version']) >= 0) { - return; - } + var base = util.copyBinariesCmd() + ' && ' + util.fixBinariesCmd(); + if (!virtualBox.installed() || setupUtil.compareVersions(yield virtualBox.version(), packagejson['virtualbox-required-version']) < 0) { yield virtualBox.killall(); + base += ` && installer -pkg ${path.join(util.supportDir(), packagejson['virtualbox-filename'])} -target /`; } - var isSudo = yield setupUtil.isSudo(); - var iconPath = path.join(setupUtil.resourceDir(), 'kitematic.icns'); - var sudoCmd = isSudo ? ['sudo'] : [path.join(setupUtil.resourceDir(), 'cocoasudo'), '--icon=' + iconPath, `--prompt=${SUDO_PROMPT}`]; - sudoCmd.push.apply(sudoCmd, ['installer', '-pkg', path.join(setupUtil.supportDir(), packagejson['virtualbox-filename']), '-target', '/']); + var cmd = `${util.escapePath(path.join(util.resourceDir(), 'cocoasudo'))} --prompt="Kitematic requires administrative privileges to install VirtualBox." bash -c \"${base}\"`; try { - yield util.exec(sudoCmd); + yield util.exec(cmd); } catch (err) { throw null; } }) }, { - name: 'initBoot2Docker', + name: 'init', title: 'Setting up Docker VM', - message: "To run Docker containers on your computer, we are setting up a Linux virtual machine provided by boot2docker.", + message: 'To run Docker containers on your computer, we are setting up a Linux virtual machine provided by boot2docker.', totalPercent: 15, percent: 0, seconds: 11, run: Promise.coroutine(function* (progressCallback) { + setupUtil.simulateProgress(this.seconds, progressCallback); yield virtualBox.vmdestroy('kitematic-vm'); var exists = yield boot2docker.exists(); if (!exists) { - setupUtil.simulateProgress(this.seconds, progressCallback); yield boot2docker.init(); return; } @@ -81,21 +70,20 @@ var _steps = [{ var isoversion = boot2docker.isoversion(); if (!isoversion || setupUtil.compareVersions(isoversion, boot2docker.version()) < 0) { - setupUtil.simulateProgress(this.seconds, progressCallback); yield boot2docker.stop(); yield boot2docker.upgrade(); } }) }, { - name: 'startBoot2Docker', + name: 'start', title: 'Starting Docker VM', message: "Kitematic is starting the boot2docker VM. This may take about a minute.", totalPercent: 45, percent: 0, seconds: 35, run: function (progressCallback) { + setupUtil.simulateProgress(this.seconds, progressCallback); return boot2docker.waitstatus('saving').then(boot2docker.status).then(status => { - setupUtil.simulateProgress(this.seconds, progressCallback); if (status !== 'running') { return boot2docker.start(); } @@ -103,28 +91,29 @@ var _steps = [{ } }]; -var SetupStore = assign(EventEmitter.prototype, { +var SetupStore = assign(Object.create(EventEmitter.prototype), { PROGRESS_EVENT: 'setup_progress', STEP_EVENT: 'setup_step', ERROR_EVENT: 'setup_error', step: function () { - return _currentStep || _steps[0]; + return _currentStep; }, steps: function () { return _.indexBy(_steps, 'name'); }, stepCount: function () { - return _steps.length; + return _requiredSteps.length; }, number: function () { - return _.indexOf(_steps, _currentStep) + 1; + return _.indexOf(_requiredSteps, _currentStep) + 1; }, percent: function () { - var total = 0; - _.each(_steps, step => { - total += step.totalPercent * step.percent / 100; + var sofar = 0; + var totalPercent = _requiredSteps.reduce((prev, step) => prev + step.totalPercent, 0); + _.each(_requiredSteps, step => { + sofar += step.totalPercent * step.percent / 100; }); - return Math.min(Math.round(total), 99); + return Math.min(Math.round(100 * sofar / totalPercent), 99); }, error: function () { return _error; @@ -141,13 +130,37 @@ var SetupStore = assign(EventEmitter.prototype, { _retryPromise = Promise.defer(); return _retryPromise.promise; }, - run: Promise.coroutine(function* () { + init: Promise.coroutine(function* () { + var packagejson = util.packagejson(); + var isoversion = boot2docker.isoversion(); + var required = {}; + required.download = !virtualBox.installed() || setupUtil.compareVersions(yield virtualBox.version(), packagejson['virtualbox-required-version']) < 0; + required.install = required.download || setupUtil.needsBinaryFix(); + required.init = !(yield boot2docker.exists()) || !isoversion || setupUtil.compareVersions(isoversion, boot2docker.version()) < 0; + required.start = required.init || (yield boot2docker.status()) !== 'running'; + var exists = yield boot2docker.exists(); if (exists) { - this.steps().startBoot2Docker.seconds = 13; + this.steps().start.seconds = 13; } - for (let step of _steps) { + _requiredSteps = _steps.filter(function (step) { + return required[step.name]; + }); + }), + updateBinaries: function () { + if (setupUtil.needsBinaryFix()) { + return Promise.resolve(); + } + if (setupUtil.shouldUpdateBinaries()) { + return util.exec(util.copyBinariesCmd()); + } + return Promise.resolve(); + }, + run: Promise.coroutine(function* () { + yield this.init(); + yield this.updateBinaries(); + for (let step of _requiredSteps) { _currentStep = step; step.percent = 0; while (true) { @@ -163,6 +176,7 @@ var SetupStore = assign(EventEmitter.prototype, { break; } catch (err) { if (err) { + console.log(err.stack); _error = err; this.emit(this.ERROR_EVENT); } else { diff --git a/src/SetupUtil.js b/src/SetupUtil.js index 31931d99b6..c18b0cab99 100644 --- a/src/SetupUtil.js +++ b/src/SetupUtil.js @@ -1,36 +1,33 @@ var _ = require('underscore'); var crypto = require('crypto'); -var exec = require('exec'); var fs = require('fs'); +var path = require('path'); var request = require('request'); var progress = require('request-progress'); -var path = require('path'); var Promise = require('bluebird'); +var util = require('./Util'); var SetupUtil = { - supportDir: function () { - var dirs = ['Library', 'Application\ Support', 'Kitematic']; - var acc = process.env.HOME; - dirs.forEach(function (d) { - acc = path.join(acc, d); - if (!fs.existsSync(acc)) { - fs.mkdirSync(acc); - } - }); - return acc; + needsBinaryFix: function () { + if (!fs.existsSync('/usr/local/bin/docker') && !fs.existsSync('/usr/local/bin/boot2docker')) { + return fs.statSync('/usr/local/bin').gid !== 80 || fs.statSync('/usr/local/bin').uid !== process.getuid(); + } + + if (fs.existsSync('/usr/local/bin/docker') && (fs.statSync('/usr/local/bin/docker').gid !== 80 || fs.statSync('/usr/local/bin/docker').uid !== process.getuid())) { + return true; + } + + if (fs.existsSync('/usr/local/bin/boot2docker') && (fs.statSync('/usr/local/bin/boot2docker').gid !== 80 || fs.statSync('/usr/local/bin/boot2docker').uid !== process.getuid())) { + return true; + } + return false; }, - resourceDir: function () { - return process.env.RESOURCES_PATH; - }, - isSudo: function () { - return new Promise((resolve, reject) => { - exec(['sudo', '-n', '-u', 'root', 'true'], (stderr, stdout, code) => { - if (code) { - reject(stderr); - } - resolve(stderr.indexOf('a password is required') === -1); - }); - }); + shouldUpdateBinaries: function () { + var packagejson = util.packagejson(); + return !fs.existsSync('/usr/local/bin/docker') || + !fs.existsSync('/usr/local/bin/boot2docker') || + this.checksum('/usr/local/bin/boot2docker') !== this.checksum(path.join(util.resourceDir(), 'boot2docker-' + packagejson['boot2docker-version'])) || + this.checksum('/usr/local/bin/docker') !== this.checksum(path.join(util.resourceDir(), 'docker-' + packagejson['docker-version'])); }, simulateProgress: function (estimateSeconds, progress) { var times = _.range(0, estimateSeconds * 1000, 200); @@ -42,10 +39,13 @@ var SetupUtil = { timers.push(timer); }); }, + checksum: function (filename) { + return crypto.createHash('sha256').update(fs.readFileSync(filename), 'utf8').digest('hex'); + }, download: function (url, filename, checksum, percentCallback) { return new Promise((resolve, reject) => { if (fs.existsSync(filename)) { - var existingChecksum = crypto.createHash('sha256').update(fs.readFileSync(filename), 'utf8').digest('hex'); + var existingChecksum = this.checksum(filename); if (existingChecksum === checksum) { resolve(); return; diff --git a/src/Util.js b/src/Util.js index d83cc2fa01..bfe0514fde 100644 --- a/src/Util.js +++ b/src/Util.js @@ -17,7 +17,42 @@ module.exports = { home: function () { return process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME']; }, + supportDir: function () { + var dirs = ['Library', 'Application\ Support', 'Kitematic']; + var acc = process.env.HOME; + dirs.forEach(function (d) { + acc = path.join(acc, d); + if (!fs.existsSync(acc)) { + fs.mkdirSync(acc); + } + }); + return acc; + }, + resourceDir: function () { + return process.env.RESOURCES_PATH; + }, packagejson: function () { return JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8')); + }, + copycmd: function (src, dest) { + return ['rm', '-f', dest, '&&', 'cp', src, dest]; + }, + copyBinariesCmd: function () { + var packagejson = this.packagejson(); + var cmd = []; + cmd.push.apply(cmd, this.copycmd(this.escapePath(path.join(this.resourceDir(), 'boot2docker-' + packagejson['boot2docker-version'])), '/usr/local/bin/boot2docker')); + cmd.push('&&'); + cmd.push.apply(cmd, this.copycmd(this.escapePath(path.join(this.resourceDir(), 'docker-' + packagejson['docker-version'])), '/usr/local/bin/docker')); + return cmd.join(' '); + }, + fixBinariesCmd: function () { + var cmd = []; + cmd.push.apply(cmd, ['chown', `${process.getuid()}:${80}`, this.escapePath(path.join('/usr/local/bin', 'boot2docker'))]); + cmd.push('&&'); + cmd.push.apply(cmd, ['chown', `${process.getuid()}:${80}`, this.escapePath(path.join('/usr/local/bin', 'docker'))]); + return cmd.join(' '); + }, + escapePath: function (str) { + return str.replace(/ /g, '\\ ').replace(/\(/g, '\\(').replace(/\)/g, '\\)'); } }; diff --git a/src/VirtualBox.js b/src/VirtualBox.js index a1d20bb427..4831870280 100644 --- a/src/VirtualBox.js +++ b/src/VirtualBox.js @@ -27,13 +27,12 @@ var VirtualBox = { return util.exec(this.command() + ' list runningvms | sed -E \'s/.*\\{(.*)\\}/\\1/\' | xargs -L1 -I {} ' + this.command() + ' controlvm {} poweroff'); }, killall: function () { - if (!this.installed()) { - return Promise.reject('VirtualBox not installed.'); - } return this.poweroffall().then(() => { return util.exec(['pkill', 'VirtualBox']); }).then(() => { return util.exec(['pkill', 'VBox']); + }).catch(err => { + }); }, vmstate: function (name) { From f3d719756bf88be4618d875aab33e1bd62eb38fd Mon Sep 17 00:00:00 2001 From: Jeffrey Morgan Date: Fri, 13 Feb 2015 00:03:25 -0800 Subject: [PATCH 2/5] Fixing menu, adding Docker terminal --- src/Main.js | 2 ++ src/Menu.js | 28 ++++++++++++++++++++++++++++ src/Util.js | 6 ++++-- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/Main.js b/src/Main.js index 204a9877d3..69beea6499 100644 --- a/src/Main.js +++ b/src/Main.js @@ -10,6 +10,8 @@ var boot2docker = require('./boot2docker'); var ContainerStore = require('./ContainerStore'); var SetupStore = require('./SetupStore'); var settingsjson; +var Menu = require('./Menu'); + try { settingsjson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'settings.json'), 'utf8')); } catch (err) { diff --git a/src/Menu.js b/src/Menu.js index 7f1a85569e..a643a39f58 100644 --- a/src/Menu.js +++ b/src/Menu.js @@ -1,8 +1,14 @@ var remote = require('remote'); var app = remote.require('app'); +var path = require('path'); +var docker = require('./Docker'); +var boot2docker = require('./Boot2Docker'); +var _ = require('underscore'); var Menu = remote.require('menu'); var BrowserWindow = remote.require('browser-window'); var router = require('./Router'); +var util = require('./Util'); +var assign = require('object-assign'); // main.js var template = [ @@ -59,6 +65,28 @@ var template = [ }, ] }, +{ + label: 'File', + submenu: [ + { + label: 'New Container', + accelerator: 'Command+N', + selector: 'undo:' + }, + { + type: 'separator' + }, + { + label: 'Open Docker Terminal', + accelerator: 'Command+Shift+T', + click: function() { + var terminal = path.join(process.cwd(), 'resources', 'terminal'); + var cmd = [terminal, `DOCKER_HOST=${'tcp://' + docker.host + ':2376'} DOCKER_CERT_PATH=${path.join(process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME'], '.boot2docker/certs/boot2docker-vm')} DOCKER_TLS_VERIFY=1 $SHELL`]; + util.exec(cmd).then(() => {}); + } + }, + ] +}, { label: 'Edit', submenu: [ diff --git a/src/Util.js b/src/Util.js index bfe0514fde..8bc3b88458 100644 --- a/src/Util.js +++ b/src/Util.js @@ -4,9 +4,11 @@ var fs = require('fs'); var path = require('path'); module.exports = { - exec: function (args) { + exec: function (args, options) { + options = options || {}; return new Promise((resolve, reject) => { - exec(args, (stderr, stdout, code) => { + console.log(options); + exec(args, options, (stderr, stdout, code) => { if (code) { reject(stderr); } From 205a12041f06f2d40d8b91eef414c92371a07f81 Mon Sep 17 00:00:00 2001 From: Jeffrey Morgan Date: Fri, 13 Feb 2015 10:03:23 -0800 Subject: [PATCH 3/5] removing unused requires --- src/Menu.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Menu.js b/src/Menu.js index a643a39f58..2249087873 100644 --- a/src/Menu.js +++ b/src/Menu.js @@ -2,13 +2,10 @@ var remote = require('remote'); var app = remote.require('app'); var path = require('path'); var docker = require('./Docker'); -var boot2docker = require('./Boot2Docker'); -var _ = require('underscore'); var Menu = remote.require('menu'); var BrowserWindow = remote.require('browser-window'); var router = require('./Router'); var util = require('./Util'); -var assign = require('object-assign'); // main.js var template = [ From bb3e6e6e1b81edfc94956013f7c522f9141a600a Mon Sep 17 00:00:00 2001 From: Jeffrey Morgan Date: Fri, 13 Feb 2015 10:25:27 -0800 Subject: [PATCH 4/5] Fix tests --- __tests__/SetupStore-test.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/__tests__/SetupStore-test.js b/__tests__/SetupStore-test.js index 4134db3fb2..ee4fc5f071 100644 --- a/__tests__/SetupStore-test.js +++ b/__tests__/SetupStore-test.js @@ -12,7 +12,7 @@ describe('SetupStore', function () { pit('downloads virtualbox if it is not installed', function () { virtualBox.installed.mockReturnValue(false); setupUtil.download.mockReturnValue(Promise.resolve()); - return setupStore.steps().downloadVirtualBox.run().then(() => { + return setupStore.steps().download.run().then(() => { // TODO: make sure download was called with the right args expect(setupUtil.download).toBeCalled(); }); @@ -23,7 +23,7 @@ describe('SetupStore', function () { virtualBox.version.mockReturnValue(Promise.resolve('4.3.16')); setupUtil.compareVersions.mockReturnValue(-1); setupUtil.download.mockReturnValue(Promise.resolve()); - return setupStore.steps().downloadVirtualBox.run().then(() => { + return setupStore.steps().download.run().then(() => { expect(setupUtil.download).toBeCalled(); }); }); @@ -33,7 +33,6 @@ describe('SetupStore', function () { pit('installs virtualbox if it is not installed', function () { virtualBox.installed.mockReturnValue(false); virtualBox.killall.mockReturnValue(Promise.resolve()); - setupUtil.isSudo.mockReturnValue(Promise.resolve(false)); util.exec.mockReturnValue(Promise.resolve()); return setupStore.steps().install.run().then(() => { // TODO: make sure that the right install command was executed @@ -45,7 +44,6 @@ describe('SetupStore', function () { virtualBox.installed.mockReturnValue(true); virtualBox.version.mockReturnValue(Promise.resolve('4.3.16')); virtualBox.killall.mockReturnValue(Promise.resolve()); - setupUtil.isSudo.mockReturnValue(Promise.resolve(false)); setupUtil.compareVersions.mockReturnValue(-1); util.exec.mockReturnValue(Promise.resolve()); return setupStore.steps().install.run().then(() => { From 4e3190c42c03de91be2370dab8d8a9c6f3315765 Mon Sep 17 00:00:00 2001 From: Jeffrey Morgan Date: Fri, 13 Feb 2015 10:28:23 -0800 Subject: [PATCH 5/5] Cache dependencies --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 20fd86b6a5..fed1f6b39e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,7 @@ language: node_js node_js: - 0.10 +cache: + directories: + - node_modules + - resources