UNPKG

guvnor

Version:

A node process manager that isn't spanners all the way down

1,041 lines (835 loc) 32 kB
var expect = require('chai').expect, sinon = require('sinon'), posix = require('posix'), shortid = require('shortid'), os = require('os'), continueProcess = require('./fixtures/continueProcess'), fs = require('fs'), async = require('async'), exec = require('./fixtures/exec'), child_process = require('child_process'), logDaemonMessages = require('./fixtures/log-daemon-messages') process.setMaxListeners(0) var user = posix.getpwnam(process.getuid()) var group = posix.getgrnam(process.getgid()) var config = { guvnor: { user: user.name, group: group.name, timeout: 5000, autoresume: false, rpctimeout: 0 }, remote: { enabled: false, inspector: { enabled: false } }, debug: { daemon: false, cluster: false } } var logger = { info: console.info, warn: console.info, error: console.info, debug: console.info } if (process.env.npm_package_version) { logger = { info: sinon.stub(), warn: sinon.stub(), error: sinon.stub(), debug: sinon.stub() } } var remote = require('../../lib/local').connectOrStart, remote = remote.bind(null, config, logger) var guvnor var tmpdir describe('Guvnor', function () { // integration tests are slow this.timeout(60000) beforeEach(function (done) { tmpdir = os.tmpdir() + '/' + shortid.generate() tmpdir = tmpdir.replace(/\/\//g, '/') config.guvnor.logdir = tmpdir + '/logs' config.guvnor.rundir = tmpdir + '/run' config.guvnor.confdir = tmpdir + '/conf' config.guvnor.appdir = tmpdir + '/apps' remote(function (error, b) { if (error) throw error guvnor = b logDaemonMessages(guvnor) done() }) }) afterEach(function (done) { guvnor.callbacks = {} guvnor.kill(guvnor.disconnect.bind(guvnor, done)) }) it('should have npm available', function (done) { child_process.exec('which npm', function (error, stdout, stderr) { console.info('which npm') console.info('error', error) console.info('stdout', stdout) console.info('stderr', stderr) done() }) }) it('should have git available', function (done) { child_process.exec('which git', function (error, stdout, stderr) { console.info('which git') console.info('error', error) console.info('stdout', stdout) console.info('stderr', stderr) done() }) }) it('should start a process', function (done) { guvnor.startProcess(__dirname + '/fixtures/hello-world.js', {}, function (error, managedProcess) { expect(error).to.not.exist expect(managedProcess.id).to.be.ok managedProcess.once('process:ready', function () { expect(managedProcess.socket).to.include(managedProcess.pid) done() }) }) }) it('should start the same process twice with different names', function (done) { guvnor.startProcess(__dirname + '/fixtures/hello-world.js', { name: 'foo' }, function (error, managedProcess) { managedProcess.once('process:ready', function () { guvnor.startProcess(__dirname + '/fixtures/hello-world.js', { name: 'bar' }, function (error, managedProcess) { expect(error).to.not.exist done() }) }) }) }) it('should not start the same process twice', function (done) { guvnor.startProcess(__dirname + '/fixtures/hello-world.js', {}, function (error, managedProcess) { managedProcess.once('process:ready', function () { guvnor.startProcess(__dirname + '/fixtures/hello-world.js', {}, function (error, managedProcess) { expect(error).to.be.ok done() }) }) }) }) it('should not start the same named process twice', function (done) { guvnor.startProcess(__dirname + '/fixtures/hello-world.js', { name: 'foo' }, function (error, managedProcess) { managedProcess.once('process:ready', function () { guvnor.startProcess(__dirname + '/fixtures/hello-world.js', { name: 'foo' }, function (error, managedProcess) { expect(error).to.be.ok done() }) }) }) }) it('should not start processes with the same name', function (done) { guvnor.startProcess(__dirname + '/fixtures/hello-world.js', { name: 'foo' }, function (error, managedProcess) { managedProcess.once('process:ready', function () { guvnor.startProcess(__dirname + '/fixtures/crash-on-message.js', { name: 'foo' }, function (error, managedProcess) { expect(error).to.be.ok done() }) }) }) }) it('should start a coffeescript process', function (done) { guvnor.startProcess(__dirname + '/fixtures/hello-world.coffee', {}, function (error, managedProcess) { expect(error).to.not.exist expect(managedProcess.id).to.be.ok guvnor.once('process:ready', function (readyProcessInfo) { if (readyProcessInfo.id != managedProcess.id) { return } expect(readyProcessInfo.socket).to.include(readyProcessInfo.pid) done() }) }) }) it('should survive starting a process with the wrong group name', function (done) { guvnor.startProcess(__dirname + '/fixtures/hello-world.js', { group: shortid.generate() }, function (error) { expect(error).to.be.ok expect(error.message).to.contain('group') done() }) }) it('should survive starting a process with the wrong user name', function (done) { guvnor.startProcess(__dirname + '/fixtures/hello-world.js', { user: shortid.generate() }, function (error) { expect(error).to.be.ok expect(error.message).to.contain('user') done() }) }) it('should start a process in debug mode', function (done) { guvnor.startProcess(__dirname + '/fixtures/hello-world.js', { debug: true }, function (error, managedProcess) { expect(error).to.not.exist expect(managedProcess.id).to.be.ok expect(managedProcess.status).to.equal('paused') expect(managedProcess.debugPort).to.be.a('number') var continued = false managedProcess.on('process:ready', function () { expect(managedProcess.socket).to.include(managedProcess.pid) expect(continued).to.be.true done() }) continueProcess(managedProcess.debugPort, function (error) { expect(error).to.not.exist continued = true }) }) }) it('should stop a process', function (done) { guvnor.startProcess(__dirname + '/fixtures/hello-world.js', {}, function (error, managedProcess) { expect(error).to.not.exist expect(managedProcess.id).to.be.ok managedProcess.once('process:exit', function (error, code, signal) { expect(managedProcess.status).to.equal('stopped') expect(error).to.not.exist expect(code).to.equal(0) expect(signal).to.not.exist console.info('process exited') guvnor.listProcesses(function (error, processes) { expect(error).to.not.exist expect(processes.length).to.equal(1) expect(processes[0].id).to.equal(managedProcess.id) expect(processes[0].status).to.equal('stopped') done() }) }) managedProcess.once('process:ready', function () { expect(managedProcess.socket).to.be.ok managedProcess.kill() }) }) }) it('should restart a process', function (done) { guvnor.startProcess(__dirname + '/fixtures/hello-world.js', {}, function (error, managedProcess) { expect(error).to.not.exist expect(managedProcess.id).to.be.ok var notifiedOfRestarting = false managedProcess.once('process:restarting', function () { notifiedOfRestarting = true }) managedProcess.once('process:restarted', function () { guvnor.listProcesses(function (error, processes) { expect(error).to.not.exist expect(notifiedOfRestarting).to.be.true expect(processes.length).to.equal(1) expect(processes[0].restarts).to.equal(1) done() }) }) managedProcess.once('process:ready', function () { expect(managedProcess.socket).to.be.ok managedProcess.restart() }) }) }) it('should list processes', function (done) { guvnor.listProcesses(function (error, processes) { expect(error).to.not.exist expect(processes.length).to.equal(0) guvnor.startProcess(__dirname + '/fixtures/hello-world.js', {}, function (error, managedProcess) { expect(error).to.not.exist expect(managedProcess.id).to.be.ok guvnor.once('process:ready', function () { guvnor.listProcesses(function (error, processes) { expect(error).to.not.exist expect(processes.length).to.equal(1) done() }) }) }) }) }) it('should restart a failing process', function (done) { guvnor.startProcess(__dirname + '/fixtures/crash-on-message.js', {}, function (error, managedProcess) { expect(error).to.not.exist expect(managedProcess.id).to.be.ok managedProcess.once('process:restarted', done) managedProcess.once('process:ready', function () { expect(managedProcess.socket).to.be.ok managedProcess.send('custom:euthanise') }) }) }) it('should abort a constantly failing process', function (done) { guvnor.startProcess(__dirname + '/fixtures/first-tick-crash.js', {}, function (error, managedProcess) { expect(error).to.not.exist managedProcess.once('process:aborted', function () { // should have status of 'aborted' guvnor.listProcesses(function (error, processes) { expect(error).to.not.exist expect(processes.length).to.equal(1) expect(processes[0].id).to.equal(managedProcess.id) expect(processes[0].status).to.equal('aborted') done() }) }) }) }) it('should invoke a remote callback', function (done) { guvnor.startProcess(__dirname + '/fixtures/remote-executor.js', {}, function (error, managedProcess) { expect(error).to.not.exist expect(managedProcess.id).to.be.ok managedProcess.once('process:ready', function () { expect(managedProcess.socket).to.be.ok managedProcess.send('custom:hello', function (message) { expect(message).to.equal('hello world') done() }) }) }) }) it('should start cluster and report online when all processes have started', function (done) { guvnor.startProcess(__dirname + '/fixtures/http-server.js', { env: { PORT: 0 }, instances: 2 }, function (error, managedProcess) { expect(error).to.not.exist expect(managedProcess.id).to.be.ok var workersForked = 0 var workersStarting = 0 var workersStarted = 0 var workersReady = 0 managedProcess.on('worker:forked', function (workerProcessInfo) { expect(workerProcessInfo).to.be.ok workersForked++ }) managedProcess.on('worker:starting', function (workerProcessInfo) { expect(workerProcessInfo).to.be.ok workersStarting++ }) managedProcess.on('worker:started', function (workerProcessInfo) { expect(workerProcessInfo).to.be.ok workersStarted++ }) managedProcess.on('worker:ready', function (workerProcessInfo) { expect(workerProcessInfo).to.be.ok workersReady++ }) managedProcess.once('cluster:online', function () { expect(workersForked).to.equal(2) expect(workersStarting).to.equal(2) expect(workersStarted).to.equal(2) expect(workersReady).to.equal(2) done() }) }) }) it('should report status for cluster workers', function (done) { guvnor.startProcess(__dirname + '/fixtures/http-server.js', { env: { PORT: 0 }, instances: 2 }, function (error, managedProcess) { expect(error).to.not.exist expect(managedProcess.id).to.be.ok var debugPort = managedProcess.debugPort managedProcess.once('cluster:online', function () { guvnor.listProcesses(function (error, processes) { expect(error).to.not.exist expect(processes.length).to.equal(1) expect(processes[0].workers.length).to.equal(2) expect(processes[0].workers[0].title).to.equal(processes[0].workers[1].title) expect(processes[0].workers[0].pid).to.not.equal(processes[0].workers[1].pid) // should have assigned sequential debug ports expect(processes[0].workers[0].debugPort).to.equal(debugPort + 1) expect(processes[0].workers[1].debugPort).to.equal(debugPort + 2) done() }) }) }) }) it('should reduce number of cluster workers', function (done) { var instances = 3 guvnor.startProcess(__dirname + '/fixtures/http-server.js', { env: { PORT: 0 }, instances: instances }, function (error, managedProcess) { expect(error).to.not.exist expect(managedProcess.id).to.be.ok managedProcess.once('cluster:online', function () { instances-- managedProcess.setClusterWorkers(instances, function (error) { expect(error).to.not.exist guvnor.listProcesses(function (error, processes) { expect(error).to.not.exist expect(processes.length).to.equal(1) expect(processes[0].workers.length).to.equal(instances) guvnor.findProcessInfoById(managedProcess.id, function (error, managedProcess) { expect(error).to.not.exist expect(managedProcess.instances).to.equal(instances) done() }) }) }) }) }) }) it('should increase number of cluster workers', function (done) { var instances = 2 guvnor.startProcess(__dirname + '/fixtures/http-server.js', { env: { PORT: 0 }, instances: instances, debug: true }, function (error, managedProcess) { expect(error).to.not.exist expect(managedProcess.id).to.be.ok managedProcess.once('cluster:online', function () { instances++ managedProcess.setClusterWorkers(instances, function (error) { expect(error).to.not.exist guvnor.once('cluster:online', function (clusterProcessInfo) { if (clusterProcessInfo.id != managedProcess.id) { return } guvnor.listProcesses(function (error, processes) { expect(error).to.not.exist expect(processes.length).to.equal(1) expect(processes[0].workers.length).to.equal(instances) guvnor.findProcessInfoById(managedProcess.id, function (error, managedProcess) { expect(error).to.not.exist expect(managedProcess.instances).to.equal(instances) done() }) }) }) }) }) }) }) it('should dump process info', function (done) { guvnor.startProcess(__dirname + '/fixtures/hello-world.js', {}, function (error, managedProcess) { expect(error).to.not.exist expect(managedProcess.id).to.be.ok managedProcess.once('process:ready', function () { expect(managedProcess.socket).to.include(managedProcess.pid) guvnor.dumpProcesses(function (error) { expect(error).to.not.exist expect(fs.existsSync(config.guvnor.confdir + '/processes.json')).to.be.true done() }) }) }) }) it('should restore process info', function (done) { fs.writeFileSync( config.guvnor.confdir + '/processes.json', '[{"script": "' + __dirname + '/fixtures/hello-world.js' + '", "name": "super-fun"}]' ) guvnor.listProcesses(function (error, processes) { expect(error).to.not.exist expect(processes.length).to.equal(0) guvnor.restoreProcesses(function (error) { expect(error).to.not.exist guvnor.listProcesses(function (error, processes) { expect(processes.length).to.equal(1) done() }) }) }) }) it('should make a process do a heap dump', function (done) { guvnor.startProcess(__dirname + '/fixtures/hello-world.js', {}, function (error, managedProcess) { expect(error).to.not.exist expect(managedProcess.id).to.be.ok managedProcess.on('process:ready', function () { expect(managedProcess.socket).to.be.ok async.parallel([function (callback) { managedProcess.on('process:heapdump:start', callback) }, function (callback) { managedProcess.on('process:heapdump:complete', callback) }, function (callback) { managedProcess.dumpHeap(function (error, snapshot) { expect(error).to.not.exist expect(fs.existsSync(snapshot.path)).to.be.true // tidy up dump file fs.unlinkSync(snapshot.path) managedProcess.kill() callback() }) } ], function() { done() }) }) }) }) it('should force a process to garbage collect', function (done) { guvnor.startProcess(__dirname + '/fixtures/hello-world.js', {}, function (error, managedProcess) { expect(error).to.not.exist expect(managedProcess.id).to.be.ok managedProcess.on('process:ready', function () { expect(managedProcess.socket, 'socket was missing').to.be.ok async.parallel([function (callback) { managedProcess.on('process:gc:start', callback) }, function (callback) { managedProcess.on('process:gc:complete', callback) }, function (callback) { managedProcess.forceGc(function (error) { expect(error, 'could not perform gc').to.not.exist managedProcess.kill() callback() }) } ], done) }) }) }) it('should deploy an application', function (done) { var repo = tmpdir + '/' + shortid.generate() async.series([ exec.bind(null, 'mkdir', [repo]), exec.bind(null, 'git', ['init'], repo), exec.bind(null, 'git', ['config', 'user.email', 'foo@bar.com'], repo), exec.bind(null, 'git', ['config', 'user.name', 'foo'], repo), exec.bind(null, 'touch', ['file'], repo), exec.bind(null, 'git', ['add', '-A'], repo), exec.bind(null, 'git', ['commit', '-m', 'initial commit'], repo) ], function (error) { if (error) { throw error } var appName = shortid.generate() guvnor.deployApplication(appName, repo, user.name, function() {}, function() {}, function (error, appInfo) { expect(error).to.not.exist expect(fs.existsSync(config.guvnor.appdir + '/' + appInfo.id)).to.be.true done() }) }) }) it('should list deployed applications', function (done) { var deployApp = function (callback) { var repo = tmpdir + '/' + shortid.generate() async.series([ exec.bind(null, 'mkdir', [repo]), exec.bind(null, 'git', ['init'], repo), exec.bind(null, 'git', ['config', 'user.email', 'foo@bar.com'], repo), exec.bind(null, 'git', ['config', 'user.name', 'foo'], repo), exec.bind(null, 'touch', ['file'], repo), exec.bind(null, 'git', ['add', '-A'], repo), exec.bind(null, 'git', ['commit', '-m', 'initial commit'], repo) ], function (error) { if (error) { throw error } var appName = shortid.generate() guvnor.deployApplication(appName, repo, user.name, function() {}, function() {}, callback) }) } var tasks = [deployApp, deployApp, deployApp, deployApp, deployApp] async.parallel(tasks, function (error, results) { expect(error).to.not.exist guvnor.listApplications(function (error, apps) { expect(error).to.not.exist expect(apps.length).to.equal(tasks.length) var found = 0 results.forEach(function (result) { apps.forEach(function (app) { if (result.id == app.id) { found++ } }) }) expect(found).to.equal(tasks.length) done() }) }) }) it('should remove deployed applications', function (done) { var repo = tmpdir + '/' + shortid.generate() async.series([ exec.bind(null, 'mkdir', [repo]), exec.bind(null, 'git', ['init'], repo), exec.bind(null, 'git', ['config', 'user.email', 'foo@bar.com'], repo), exec.bind(null, 'git', ['config', 'user.name', 'foo'], repo), exec.bind(null, 'touch', ['file'], repo), exec.bind(null, 'git', ['add', '-A'], repo), exec.bind(null, 'git', ['commit', '-m', 'initial commit'], repo) ], function (error) { if (error) { throw error } var appName = shortid.generate() guvnor.deployApplication(appName, repo, user.name, function() {}, function() {}, function (error, appInfo) { expect(error).to.not.exist expect(fs.existsSync(config.guvnor.appdir + '/' + appInfo.id)).to.be.true guvnor.listApplications(function (error, apps) { expect(error).to.not.exist expect(apps.length).to.equal(1) guvnor.removeApplication(appName, function (error) { expect(error).to.not.exist expect(fs.existsSync(config.guvnor.appdir + '/' + appInfo.id)).to.be.false guvnor.listApplications(function (error, apps) { expect(error).to.not.exist expect(apps.length).to.equal(0) done() }) }) }) }) }) }) it('should switch an application ref', function (done) { var repo = tmpdir + '/' + shortid.generate() async.series([ exec.bind(null, 'mkdir', [repo]), exec.bind(null, 'git', ['init'], repo), exec.bind(null, 'git', ['config', 'user.email', 'foo@bar.com'], repo), exec.bind(null, 'git', ['config', 'user.name', 'foo'], repo), exec.bind(null, 'touch', ['v1'], repo), exec.bind(null, 'git', ['add', '-A'], repo), exec.bind(null, 'git', ['commit', '-m', 'v1'], repo), exec.bind(null, 'git', ['tag', 'v1'], repo), exec.bind(null, 'touch', ['v2'], repo), exec.bind(null, 'git', ['add', '-A'], repo), exec.bind(null, 'git', ['commit', '-m', 'v2'], repo), exec.bind(null, 'git', ['tag', 'v2'], repo), exec.bind(null, 'touch', ['v3'], repo), exec.bind(null, 'git', ['add', '-A'], repo), exec.bind(null, 'git', ['commit', '-m', 'v3'], repo), exec.bind(null, 'git', ['tag', 'v3'], repo) ], function (error) { expect(error).to.not.exist var appName = shortid.generate() guvnor.deployApplication(appName, repo, user.name, function() {}, function() {}, function (error, appInfo) { expect(error).to.not.exist // should be at latest version expect(fs.existsSync(config.guvnor.appdir + '/' + appInfo.id + '/v1')).to.be.true expect(fs.existsSync(config.guvnor.appdir + '/' + appInfo.id + '/v2')).to.be.true expect(fs.existsSync(config.guvnor.appdir + '/' + appInfo.id + '/v3')).to.be.true guvnor.switchApplicationRef(appName, 'tags/v2', function() {}, function() {}, function (error) { expect(error).to.not.exist // now at v2 expect(fs.existsSync(config.guvnor.appdir + '/' + appInfo.id + '/v1')).to.be.true expect(fs.existsSync(config.guvnor.appdir + '/' + appInfo.id + '/v2')).to.be.true expect(fs.existsSync(config.guvnor.appdir + '/' + appInfo.id + '/v3')).to.be.false guvnor.switchApplicationRef(appName, 'tags/v1', function() {}, function() {}, function (error) { expect(error).to.not.exist // now at v1 expect(fs.existsSync(config.guvnor.appdir + '/' + appInfo.id + '/v1')).to.be.true expect(fs.existsSync(config.guvnor.appdir + '/' + appInfo.id + '/v2')).to.be.false expect(fs.existsSync(config.guvnor.appdir + '/' + appInfo.id + '/v3')).to.be.false done() }) }) }) }) }) it('should list available application refs', function (done) { var repo = tmpdir + '/' + shortid.generate() async.series([ exec.bind(null, 'mkdir', [repo]), exec.bind(null, 'git', ['init'], repo), exec.bind(null, 'git', ['config', 'user.email', 'foo@bar.com'], repo), exec.bind(null, 'git', ['config', 'user.name', 'foo'], repo), exec.bind(null, 'touch', ['v1'], repo), exec.bind(null, 'git', ['add', '-A'], repo), exec.bind(null, 'git', ['commit', '-m', 'v1'], repo), exec.bind(null, 'git', ['tag', 'v1'], repo), exec.bind(null, 'touch', ['v2'], repo), exec.bind(null, 'git', ['add', '-A'], repo), exec.bind(null, 'git', ['commit', '-m', 'v2'], repo), exec.bind(null, 'git', ['tag', 'v2'], repo), exec.bind(null, 'touch', ['v3'], repo), exec.bind(null, 'git', ['add', '-A'], repo), exec.bind(null, 'git', ['commit', '-m', 'v3'], repo), exec.bind(null, 'git', ['tag', 'v3'], repo) ], function (error) { if (error) { throw error } var appName = shortid.generate() guvnor.deployApplication(appName, repo, user.name, console.info, console.error, function (error, appInfo) { expect(error).to.not.exist expect(appInfo.id).to.be.ok appInfo.listRefs(function (error, refs) { expect(error).to.not.exist expect(refs.length).to.equal(4) expect(refs[0].name).to.equal('master') expect(refs[1].name).to.equal('v1') expect(refs[2].name).to.equal('v2') expect(refs[3].name).to.equal('v3') done() }) }) }) }) it('should report the current application ref', function (done) { var repo = tmpdir + '/' + shortid.generate() async.series([ exec.bind(null, 'mkdir', [repo]), exec.bind(null, 'git', ['init'], repo), exec.bind(null, 'git', ['config', 'user.email', 'foo@bar.com'], repo), exec.bind(null, 'git', ['config', 'user.name', 'foo'], repo), exec.bind(null, 'touch', ['v1'], repo), exec.bind(null, 'git', ['add', '-A'], repo), exec.bind(null, 'git', ['commit', '-m', 'v1'], repo), exec.bind(null, 'git', ['rev-parse', 'HEAD'], repo) ], function (error, results) { expect(error).to.not.exist var appName = shortid.generate() guvnor.deployApplication(appName, repo, user.name, function() {}, function() {}, function (error, appInfo) { expect(error).to.not.exist expect(appInfo.id).to.be.ok guvnor.currentRef(appName, function (error, ref, commit) { expect(error).to.not.exist expect(ref).to.equal('master') expect(commit).to.equal(results[results.length - 1][0].trim()) done() }) }) }) }) it('should update application refs', function (done) { var repo = tmpdir + '/' + shortid.generate() async.series([ exec.bind(null, 'mkdir', [repo]), exec.bind(null, 'git', ['init'], repo), exec.bind(null, 'git', ['config', 'user.email', 'foo@bar.com'], repo), exec.bind(null, 'git', ['config', 'user.name', 'foo'], repo), exec.bind(null, 'touch', ['v1'], repo), exec.bind(null, 'git', ['add', '-A'], repo), exec.bind(null, 'git', ['commit', '-m', 'v1'], repo), exec.bind(null, 'git', ['tag', 'v1'], repo) ], function (error) { if (error) { throw error } var appName = shortid.generate() guvnor.deployApplication(appName, repo, user.name, function() {}, function() {}, function (error, appInfo) { expect(error).to.not.exist expect(appInfo.id).to.be.ok guvnor.listApplicationRefs(appName, function (error, refs) { expect(error).to.not.exist expect(refs.length).to.equal(2) async.series([ exec.bind(null, 'touch', ['v2'], repo), exec.bind(null, 'git', ['add', '-A'], repo), exec.bind(null, 'git', ['commit', '-m', 'v2'], repo), exec.bind(null, 'git', ['tag', 'v2'], repo), exec.bind(null, 'touch', ['v3'], repo), exec.bind(null, 'git', ['add', '-A'], repo), exec.bind(null, 'git', ['commit', '-m', 'v3'], repo), exec.bind(null, 'git', ['tag', 'v3'], repo) ], function (error) { if (error) { throw error } guvnor.listApplicationRefs(appName, function (error, refs) { expect(error).to.not.exist expect(refs.length).to.equal(2) guvnor.updateApplicationRefs(appName, function() {}, function() {}, function (error) { expect(error).to.not.exist guvnor.listApplicationRefs(appName, function (error, refs) { expect(error).to.not.exist expect(refs.length).to.equal(4) done() }) }) }) }) }) }) }) }) it('should change the HEAD of the repo when updating application refs', function (done) { var repo = tmpdir + '/' + shortid.generate() async.series([ exec.bind(null, 'mkdir', [repo]), exec.bind(null, 'git', ['init'], repo), exec.bind(null, 'git', ['config', 'user.email', 'foo@bar.com'], repo), exec.bind(null, 'git', ['config', 'user.name', 'foo'], repo), exec.bind(null, 'touch', ['v1'], repo), exec.bind(null, 'git', ['add', '-A'], repo), exec.bind(null, 'git', ['commit', '-m', 'v1'], repo), ], function (error) { if (error) { throw error } var appName = shortid.generate() guvnor.deployApplication(appName, repo, user.name, function() {}, function() {}, function (error, appInfo) { expect(error).to.not.exist expect(appInfo.id).to.be.ok async.series([ exec.bind(null, 'touch', ['v2'], repo), exec.bind(null, 'git', ['add', '-A'], repo), exec.bind(null, 'git', ['commit', '-m', 'v2'], repo) ], function (error) { if (error) { throw error } async.parallel([ exec.bind(null, 'git', ['rev-parse','HEAD'], repo), appInfo.currentRef.bind(appInfo) ], function (error, results) { if (error) { throw error } var repoHead = results[0][0].trim() var appHead = results[1][1].trim() expect(repoHead).to.not.equal(appHead) appInfo.updateRefs(function() {}, function() {}, function (error) { if (error) { throw error } appInfo.currentRef(function (error, ref, commit) { if (error) { throw error } expect(repoHead).to.equal(commit) done() }) }) }) }) }) }) }) it('should write to stdin for a process', function (done) { var message = 'hello world' guvnor.startProcess(__dirname + '/fixtures/stdin.js', {}, function (error, managedProcess) { expect(error).to.not.exist expect(managedProcess.id).to.be.ok managedProcess.on('stdin:received', function (answer) { expect(answer).to.equal(message) done() }) managedProcess.on('process:ready', function () { managedProcess.write(message) }) }) }) })