diff --git a/core/core.mjs b/core/core.mjs index 3646915..0c5fc24 100644 --- a/core/core.mjs +++ b/core/core.mjs @@ -50,19 +50,53 @@ export default class Core { let names = this.util.getAppNames(this.db.config) - for (let name of names) { - let provConstructor = Core.providers.get(this.db.config[name].provider) - let provider = new provConstructor(this.db.config[name]) - await provider.checkConfig(this.db.config[name]) + let lastError = null - let application = new Application({ - db: this.db, - util: this.util, - log: this.log, - core: this, - }, provider, name) - this.applications.push(application) - this.applicationMap.set(name, application) + for (let name of names) { + try { + let provConstructor = Core.providers.get(this.db.config[name].provider) + let provider = new provConstructor(this.db.config[name]) + await provider.checkConfig(this.db.config[name]) + + let application = new Application({ + db: this.db, + util: this.util, + log: this.log, + core: this, + }, provider, name) + this.applications.push(application) + this.applicationMap.set(name, application) + } catch (err) { + this.log.error(err, `Error creating application ${name} with provider ${this.db.config[name].provider}: ${err.message}`) + lastError = err + } + } + + if (names.length && !this.applications.length) { + throw lastError } } + + async runApplication(name) { + let application = this.applicationMap.get(name) + + if (!application) { + return Promise.reject(new Error(`Core.runApplication was called on a non-existing application name ${name}`)) + } + + let found = false + + for (let i = 0; i < this.db.data.core[name].versions.length; i++) { + let version = this.db.data.core[name].versions[i] + await application.closeServer() + + try { + await application.runVersion() + } catch(err) { + this.log.error(err, `Error starting ${name} ${version.id}: ${err.message}`) + } + } + + throw new Error(``) + } } diff --git a/test/application.run.test.mjs b/test/application.run.test.mjs index 8d7c68c..358eb63 100644 --- a/test/application.run.test.mjs +++ b/test/application.run.test.mjs @@ -23,14 +23,6 @@ t.describe('#runVersion("static")', function() { return server.listenAsync(port) } } - - t.before(function() { - return fs.mkdir(util.getPathFromRoot('./testnoexisting'), { recursive: true }) - }) - - t.after(function() { - return fs.rm(util.getPathFromRoot('./testnoexisting'), { force: true, recursive: true }) - }) t.beforeEach(function() { return createFakeContext() @@ -163,15 +155,13 @@ t.describe('#runVersion("version")', function() { let ctx let app - t.before(function() { - return fs.rm(util.getPathFromRoot('./testnoexisting'), { force: true, recursive: true }) - .then(function() { - return fs.mkdir(util.getPathFromRoot('./testnoexisting'), { recursive: true }) - }) - }) - t.after(function() { - return fs.rm(util.getPathFromRoot('./testnoexisting'), { force: true, recursive: true }) + return Promise.all([ + fs.rm(util.getPathFromRoot('./testnoexisting/v100'), { force: true, recursive: true }), + fs.rm(util.getPathFromRoot('./testnoexisting/v99'), { force: true, recursive: true }), + fs.rm(util.getPathFromRoot('./testnoexisting/v98'), { force: true, recursive: true }), + fs.rm(util.getPathFromRoot('./testnoexisting/v97'), { force: true, recursive: true }), + ]) }) t.beforeEach(function() { diff --git a/test/core.test.mjs b/test/core.test.mjs index 1d4d111..efa12f7 100644 --- a/test/core.test.mjs +++ b/test/core.test.mjs @@ -267,7 +267,7 @@ t.describe('#init()', function() { } t.beforeEach(function() { - core = new Core(db, util, createFakeLog(), function() {}) + core = new Core(db, util, log, function() {}) core.util = fakeUtil = { verifyConfig: stub(), getAppNames: stub().returns([]), @@ -362,12 +362,127 @@ t.describe('#init()', function() { assert.ok(application.fresh) assert.ok(application.provider instanceof FakeProvider) }) -}) -t.describe('#runApplication()', function() { - let core + t.test('should continue even if one application fails', async function() { + log.error.reset() + const assertProviderFailName = 'Knee Socks' + let stubFailCheckConfig = stub() + function FakeFailProvider(config) { + fakeProvider(config) + this.static = true + this.checkConfig = stubFailCheckConfig + } + Core.providers.set(assertProviderFailName, FakeFailProvider) - t.beforeEach(function() { - core = new Core(db, util, createFakeLog(), function() {}) + const assertError = new Error('Justice of light') + const assertFirstAppName = 'Kaeshite' + const assertSecondAppName = 'Motteke' + const assertTestFirstString = 'Magia' + const assertTestSecondString = 'Snow Falling' + const assertConfig = { + [assertFirstAppName]: { + provider: assertProviderName, + teststring: assertTestFirstString, + }, + [assertSecondAppName]: { + provider: assertProviderFailName, + teststring: assertTestSecondString, + }, + } + stubFailCheckConfig.throws(assertError) + db.config = assertConfig + fakeUtil.getAppNames.returns([assertSecondAppName, assertFirstAppName]) + assert.strictEqual(core.applications.length, 0) + + await core.init() + let application = core.getApplication(assertFirstAppName) + + assert.ok(application) + assert.strictEqual(core.applications.length, 1) + assert.strictEqual(core.applications[0], application) + assert.strictEqual(application.name, assertFirstAppName) + assert.strictEqual(application.ctx.db, core.db) + assert.strictEqual(application.ctx.util, core.util) + assert.strictEqual(application.ctx.log, core.log) + assert.strictEqual(application.ctx.core, core) + assert.strictEqual(application.config.teststring, assertTestFirstString) + assert.ok(application.fresh) + assert.ok(application.provider instanceof FakeProvider) + assert.ok(log.error.called) + assert.strictEqual(log.error.firstCall[0], assertError) + assert.match(log.error.firstCall[1], new RegExp(assertProviderFailName)) + assert.match(log.error.firstCall[1], new RegExp(assertSecondAppName)) + assert.match(log.error.firstCall[1], new RegExp(assertError.message)) + }) +}) + +t.only().describe('#runApplication()', function() { + let core + let testApp + let testAppName + + t.beforeEach(function() { + db.data.core = { + [testAppName]: { + versions: [] + } + } + core = new Core(db, util, log, function() {}) + log.info.reset() + log.warn.reset() + log.error.reset() + testAppName = 'Precure' + testApp = { + fresh: true, + closeServer: stub(), + runVersion: stub(), + } + core.applicationMap.set(testAppName, testApp) + }) + + t.test('should throw if application not found', async function() { + const assertAppName = 'Sweet Sweet Sweets' + + let err = await assert.isRejected(core.runApplication(assertAppName)) + + assert.match(err.message, new RegExp(assertAppName)) + assert.match(err.message, /exist/i) + }) + + t.test('Should always attempt to close application first', async function() { + const assertAppName = 'Pyramid Collapse' + const assertError = new Error('Pyramid Collapse') + const stubClose = stub().rejects(assertError) + db.data.core[assertAppName] = { + versions: [{}] + } + core.applicationMap.set(assertAppName, { + closeServer: stubClose, + }) + + let err = await assert.isRejected(core.runApplication(assertAppName)) + + assert.strictEqual(err, assertError) + }) + + t.test('should select first valid version', async function() { + const assertVersion = 'v50' + const assertError = new Error('jellyfish') + testApp.runVersion.rejects(assertError) + db.data.core[testAppName].versions.push({ + id: assertVersion, + version: assertVersion + 'asdf', + installed: true, + stable: 0, + }) + + let err = await assert.isRejected(core.runApplication(testAppName)) + assert.notStrictEqual(err, assertError) + assert.ok(log.error.called) + + assert.strictEqual(log.error.firstCall[0], assertError) + assert.match(log.error.firstCall[1], new RegExp(testAppName)) + assert.match(log.error.firstCall[1], new RegExp(assertVersion)) + assert.match(log.error.firstCall[1], new RegExp(assertError.message)) }) }) diff --git a/test/testnoexisting/.gitkeep b/test/testnoexisting/.gitkeep new file mode 100644 index 0000000..e69de29