Fixed problems with boot2docker integration, cleaned up tests.

This commit is contained in:
Jeffrey Morgan 2015-02-02 12:05:56 -05:00
parent 204b5b3f19
commit eff2b0fd73
11 changed files with 56 additions and 49 deletions

View File

@ -25,6 +25,16 @@ To run the app in development:
- `npm run release` - `npm run release`
### Unit Tests
- `npm test`
### Integration Tests
Note that integration tests need to be run a Mac and _will_ remove your existing Boot2Docker VM, containers etc.
- `npm run test:integration`
## Uninstalling ## Uninstalling
- Remove Kitematic.app - Remove Kitematic.app

View File

@ -13,7 +13,7 @@
"scripts": { "scripts": {
"start": "gulp", "start": "gulp",
"test": "gulp test --silent", "test": "gulp test --silent",
"integration-tests": "gulp test --silent --integration", "test:integration": "gulp test --silent --integration",
"all-tests": "npm test && npm run integration-tests", "all-tests": "npm test && npm run integration-tests",
"release": "gulp run release", "release": "gulp run release",
"preinstall": "./deps" "preinstall": "./deps"

View File

@ -1,26 +0,0 @@
window.jasmineRequire = require('./jasmine-2.1.3/jasmine');
require('./jasmine-2.1.3/jasmine-html');
require('./jasmine-2.1.3/boot');
var consoleReporter = require('./jasmine-2.1.3/console');
var app = require('remote').require('app');
jasmine.getEnv().addReporter(new consoleReporter.ConsoleReporter()({
showColors: true,
timer: new jasmine.Timer(),
print: function() {
process.stdout.write.apply(process.stdout, arguments);
},
onComplete: function () {
app.quit();
}
}));
console.log('hi');
var fs = require('fs');
var tests = fs.readdirSync('./tests').filter(function (f) {
return f.indexOf('-' + process.env.TEST_TYPE) !== -1;
});
tests.forEach(function (t) {
require('./' + t);
});

View File

@ -84,7 +84,13 @@ var Boot2Docker = {
cmdExec([Boot2Docker.command(), 'upgrade'], callback); cmdExec([Boot2Docker.command(), 'upgrade'], callback);
}, },
ip: function (callback) { ip: function (callback) {
cmdExec([Boot2Docker.command(), 'ip'], callback); exec([Boot2Docker.command(), 'ip'], function (stderr, stdout, code) {
if (code) {
callback(stderr);
} else {
callback(null, stdout.trim().replace('\n', ''));
}
});
}, },
erase: function (callback) { erase: function (callback) {
var VMFileLocation = path.join(homeDir(), 'VirtualBox\\ VMs/boot2docker-vm'); var VMFileLocation = path.join(homeDir(), 'VirtualBox\\ VMs/boot2docker-vm');

View File

@ -76,7 +76,7 @@ var ContainerDetails = React.createClass({
var $viewPopover = $(this.getDOMNode()).find('.popover-view'); var $viewPopover = $(this.getDOMNode()).find('.popover-view');
var $volumePopover = $(this.getDOMNode()).find('.popover-volume'); var $volumePopover = $(this.getDOMNode()).find('.popover-volume');
if ($viewDropdown && $volumeDropdown && $viewPopover && $volumePopover) { if ($viewDropdown.offset() && $volumeDropdown.offset()) {
$viewPopover.offset({ $viewPopover.offset({
top: $viewDropdown.offset().top + 32, top: $viewDropdown.offset().top + 32,
left: $viewDropdown.offset().left - ($viewPopover.outerWidth() / 2) + 14 left: $viewDropdown.offset().left - ($viewPopover.outerWidth() / 2) + 14
@ -94,16 +94,19 @@ var ContainerDetails = React.createClass({
return; return;
} }
this.setState({ this.setState({
progress: ContainerStore.progress(this.getParams().name),
env: ContainerUtil.env(container), env: ContainerUtil.env(container),
}); });
var ports = ContainerUtil.ports(container); var ports = ContainerUtil.ports(container);
var webPorts = ['80', '8000', '8080', '3000', '5000', '2368']; var webPorts = ['80', '8000', '8080', '3000', '5000', '2368'];
console.log(ports);
this.setState({ this.setState({
ports: ports, ports: ports,
defaultPort: _.find(_.keys(ports), function (port) { defaultPort: _.find(_.keys(ports), function (port) {
return webPorts.indexOf(port) !== -1; return webPorts.indexOf(port) !== -1;
}) })
}); });
console.log(this.state);
this.updateLogs(); this.updateLogs();
}, },
updateLogs: function (name) { updateLogs: function (name) {
@ -134,6 +137,7 @@ var ContainerDetails = React.createClass({
handleView: function () { handleView: function () {
if (this.state.defaultPort) { if (this.state.defaultPort) {
console.log(this.state.defaultPort); console.log(this.state.defaultPort);
console.log(this.state.ports[this.state.defaultPort].url);
exec(['open', this.state.ports[this.state.defaultPort].url], function (err) { exec(['open', this.state.ports[this.state.defaultPort].url], function (err) {
if (err) { throw err; } if (err) { throw err; }
}); });
@ -159,11 +163,6 @@ var ContainerDetails = React.createClass({
console.log(err); console.log(err);
}); });
}, },
handleRestart: function () {
ContainerStore.restart(this.props.container.Name, function (err) {
console.log(err);
});
},
handleTerminal: function () { handleTerminal: function () {
var container = this.props.container; var container = this.props.container;
var terminal = path.join(process.cwd(), 'resources', 'terminal').replace(/ /g, '\\\\ '); var terminal = path.join(process.cwd(), 'resources', 'terminal').replace(/ /g, '\\\\ ');
@ -310,6 +309,13 @@ var ContainerDetails = React.createClass({
disabled: !this.props.container.State.Running disabled: !this.props.container.State.Running
}); });
var restartButtonClass = React.addons.classSet({
btn: true,
'btn-action': true,
'with-icon': true,
disabled: this.props.container.State.Restarting
});
var viewButtonClass = React.addons.classSet({ var viewButtonClass = React.addons.classSet({
btn: true, btn: true,
'btn-action': true, 'btn-action': true,
@ -444,7 +450,7 @@ var ContainerDetails = React.createClass({
<a className={dropdownVolumeButtonClass} onClick={this.handleVolumeDropdown}><span className="icon icon-folder-1"></span> <span className="content">Volumes</span> <span className="icon-dropdown icon icon-arrow-37"></span></a> <a className={dropdownVolumeButtonClass} onClick={this.handleVolumeDropdown}><span className="icon icon-folder-1"></span> <span className="content">Volumes</span> <span className="icon-dropdown icon icon-arrow-37"></span></a>
</div> </div>
<div className="action"> <div className="action">
<a className={buttonClass} onClick={this.handleRestart}><span className="icon icon-refresh"></span> <span className="content">Restart</span></a> <a className={restartButtonClass} onClick={this.handleRestart}><span className="icon icon-refresh"></span> <span className="content">Restart</span></a>
</div> </div>
<div className="action"> <div className="action">
<a className={buttonClass} onClick={this.handleTerminal}><span className="icon icon-window-code-3"></span> <span className="content">Terminal</span></a> <a className={buttonClass} onClick={this.handleTerminal}><span className="icon icon-window-code-3"></span> <span className="content">Terminal</span></a>

View File

@ -83,6 +83,9 @@ var ContainerModal = React.createClass({
}, },
handleClick: function (name, event) { handleClick: function (name, event) {
ContainerStore.create(name, 'latest', function (err, containerName) { ContainerStore.create(name, 'latest', function (err, containerName) {
if (err) {
throw err;
}
this.props.onRequestHide(); this.props.onRequestHide();
}.bind(this)); }.bind(this));
}, },

View File

@ -18,7 +18,6 @@ var _progress = {};
var _logs = {}; var _logs = {};
var _streams = {}; var _streams = {};
var _muted = {}; var _muted = {};
var _config = {};
var ContainerStore = assign(EventEmitter.prototype, { var ContainerStore = assign(EventEmitter.prototype, {
CLIENT_CONTAINER_EVENT: 'client_container', CLIENT_CONTAINER_EVENT: 'client_container',
@ -250,7 +249,12 @@ var ContainerStore = assign(EventEmitter.prototype, {
init: function (callback) { init: function (callback) {
// TODO: Load cached data from db on loading // TODO: Load cached data from db on loading
this.fetchAllContainers(function (err) { this.fetchAllContainers(function (err) {
if (err) {
callback(err);
return;
} else {
callback(); callback();
}
this.emit(this.CLIENT_CONTAINER_EVENT); this.emit(this.CLIENT_CONTAINER_EVENT);
this._resumePulling(); this._resumePulling();
this._startListeningToEvents(); this._startListeningToEvents();
@ -366,7 +370,6 @@ var ContainerStore = assign(EventEmitter.prototype, {
}); });
stream.on('end', function () { stream.on('end', function () {
delete _streams[name]; delete _streams[name];
console.log('end', name);
}); });
}); });
}, },
@ -381,6 +384,10 @@ var ContainerStore = assign(EventEmitter.prototype, {
if (!data) { if (!data) {
// Pull image // Pull image
self._createPlaceholderContainer(imageName, containerName, function (err, container) { self._createPlaceholderContainer(imageName, containerName, function (err, container) {
if (err) {
callback(err);
return;
}
_containers[containerName] = container; _containers[containerName] = container;
self.emit(self.CLIENT_CONTAINER_EVENT, containerName, 'create'); self.emit(self.CLIENT_CONTAINER_EVENT, containerName, 'create');
_muted[containerName] = true; _muted[containerName] = true;

View File

@ -15,9 +15,8 @@ var ContainerUtil = {
ports: function (container, callback) { ports: function (container, callback) {
var res = {}; var res = {};
var ip = docker.host; var ip = docker.host;
console.log(container);
_.each(container.NetworkSettings.Ports, function (value, key) { _.each(container.NetworkSettings.Ports, function (value, key) {
var dockerPort = key; var dockerPort = key.split('/')[0];
var localUrl = null; var localUrl = null;
var localUrlDisplay = null; var localUrlDisplay = null;
if (value && value.length) { if (value && value.length) {

View File

@ -12,8 +12,7 @@ var Docker = {
return; return;
} }
this._client = new dockerode({ this._client = new dockerode({
protocol: 'https', host: '192.168.59.103',
host: this.host,
port: 2376, port: 2376,
ca: fs.readFileSync(path.join(certDir, 'ca.pem')), ca: fs.readFileSync(path.join(certDir, 'ca.pem')),
cert: fs.readFileSync(path.join(certDir, 'cert.pem')), cert: fs.readFileSync(path.join(certDir, 'cert.pem')),

View File

@ -2,7 +2,7 @@ var React = require('react');
var Router = require('react-router'); var Router = require('react-router');
var RetinaImage = require('react-retina-image'); var RetinaImage = require('react-retina-image');
var async = require('async'); var async = require('async');
var docker = require('./docker'); var docker = require('./Docker');
var router = require('./router'); var router = require('./router');
var boot2docker = require('./boot2docker'); var boot2docker = require('./boot2docker');
var ContainerStore = require('./ContainerStore'); var ContainerStore = require('./ContainerStore');
@ -29,9 +29,11 @@ if (process.env.NODE_ENV === 'development') {
if (!window.location.hash.length || window.location.hash === '#/') { if (!window.location.hash.length || window.location.hash === '#/') {
SetupStore.run(function (err) { SetupStore.run(function (err) {
boot2docker.ip(function (err, ip) { boot2docker.ip(function (err, ip) {
if (err) console.log(err);
docker.setHost(ip); docker.setHost(ip);
router.transitionTo('containers'); router.transitionTo('containers');
ContainerStore.init(function () { ContainerStore.init(function (err) {
if (err) console.log(err);
router.run(function (Handler) { router.run(function (Handler) {
React.render(<Handler/>, document.body); React.render(<Handler/>, document.body);
}); });
@ -40,8 +42,10 @@ if (!window.location.hash.length || window.location.hash === '#/') {
}); });
} else { } else {
boot2docker.ip(function (err, ip) { boot2docker.ip(function (err, ip) {
if (err) console.log(err);
docker.setHost(ip); docker.setHost(ip);
ContainerStore.init(function () { ContainerStore.init(function (err) {
if (err) console.log(err);
router.run(function (Handler) { router.run(function (Handler) {
React.render(<Handler/>, document.body); React.render(<Handler/>, document.body);
}); });

View File

@ -17,12 +17,10 @@ describe('Setup', function () {
if (fs.existsSync(virtualboxFile)) { if (fs.existsSync(virtualboxFile)) {
fs.unlinkSync(virtualboxFile); fs.unlinkSync(virtualboxFile);
} }
spyOn(virtualbox, 'installed').andCallFake(function (callback) { spyOn(virtualbox, 'installed').and.returnValue(false);
callback(false);
});
}); });
it('downloads virtualbox', function (done) { it('downloads virtualbox from the official website', function (done) {
SetupStore.downloadVirtualboxStep.run(function (err) { SetupStore.downloadVirtualboxStep.run(function (err) {
expect(err).toBeFalsy(); expect(err).toBeFalsy();
expect(fs.existsSync(virtualboxFile)).toBe(true); expect(fs.existsSync(virtualboxFile)).toBe(true);
@ -51,6 +49,7 @@ describe('Setup', function () {
it('does install virtualbox', function (done) { it('does install virtualbox', function (done) {
SetupStore.installVirtualboxStep.run(function (err) { SetupStore.installVirtualboxStep.run(function (err) {
expect(err).toBeFalsy(); expect(err).toBeFalsy();
expect(fs.existsSync(virtualbox.command())).toBe(true);
done(); done();
}); });
}); });