Massive development. Application finished. Core started
This commit is contained in:
parent
df7e1e5509
commit
758e61b8b1
21 changed files with 2117 additions and 831 deletions
|
@ -1,13 +1,20 @@
|
||||||
import { EventEmitter } from 'events'
|
import { EventEmitter } from 'events'
|
||||||
import fs from 'fs/promises'
|
import fs from 'fs/promises'
|
||||||
|
import { request } from './client.mjs'
|
||||||
import HttpServer from './http.mjs'
|
import HttpServer from './http.mjs'
|
||||||
|
import { defaults } from './defaults.mjs'
|
||||||
|
|
||||||
export default class Application extends EventEmitter {
|
export default class Application extends EventEmitter {
|
||||||
constructor(util, db, provider, name, opts = {}) {
|
constructor(ctx, provider, name, opts = {}) {
|
||||||
super()
|
super()
|
||||||
this.util = util
|
this.ctx = {
|
||||||
this.db = db
|
db: ctx.db,
|
||||||
this.config = db.config[name] || { }
|
util: ctx.util,
|
||||||
|
log: ctx.log,
|
||||||
|
core: ctx.core,
|
||||||
|
app: this,
|
||||||
|
}
|
||||||
|
this.config = defaults({}, this.ctx.db.config[name])
|
||||||
this.provider = provider
|
this.provider = provider
|
||||||
this.name = name
|
this.name = name
|
||||||
this.updating = false
|
this.updating = false
|
||||||
|
@ -26,14 +33,18 @@ export default class Application extends EventEmitter {
|
||||||
|
|
||||||
// Apply defaults to config
|
// Apply defaults to config
|
||||||
this.config.updateEvery = this.config.updateEvery || 180
|
this.config.updateEvery = this.config.updateEvery || 180
|
||||||
this.config.waitUntilFail = this.config.waitUntilFail || (60 * 1000)
|
this.config.startWaitUntilFail = this.config.startWaitUntilFail || (60 * 1000)
|
||||||
|
this.config.heartbeatTimeout = this.config.heartbeatTimeout || (3 * 1000)
|
||||||
|
this.config.heartbeatAttempts = this.config.heartbeatAttempts || 5
|
||||||
|
this.config.heartbeatAttemptsWait = this.config.heartbeatAttemptsWait || (2 * 1000)
|
||||||
|
this.config.heartbeatPath = this.config.heartbeatPath || '/'
|
||||||
|
|
||||||
Object.assign(this, {
|
Object.assign(this, {
|
||||||
setInterval: opts.setInterval || setInterval,
|
setInterval: opts.setInterval || setInterval,
|
||||||
fs: opts.fs || fs,
|
fs: opts.fs || fs,
|
||||||
})
|
})
|
||||||
|
|
||||||
this.db.addApplication(name)
|
this.ctx.db.addApplication(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
startAutoupdater() {
|
startAutoupdater() {
|
||||||
|
@ -42,10 +53,10 @@ export default class Application extends EventEmitter {
|
||||||
let timer = this.setInterval(() => {
|
let timer = this.setInterval(() => {
|
||||||
this.update().then(
|
this.update().then(
|
||||||
() => {
|
() => {
|
||||||
this.db.data.core[this.name].updater += 'Automatic update finished successfully. '
|
this.ctx.db.data.core[this.name].updater += 'Automatic update finished successfully. '
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
this.db.data.core[this.name].updater += 'Error while running automatic update: ' + err.message + '. '
|
this.ctx.db.data.core[this.name].updater += 'Error while running automatic update: ' + err.message + '. '
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}, this.config.updateEvery * 60 * 1000)
|
}, this.config.updateEvery * 60 * 1000)
|
||||||
|
@ -53,8 +64,8 @@ export default class Application extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
updateLog(message) {
|
updateLog(message) {
|
||||||
this.db.data.core[this.name].updater += message
|
this.ctx.db.data.core[this.name].updater += message
|
||||||
this.db.log.info(message)
|
this.ctx.db.log.info(message)
|
||||||
return message
|
return message
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,10 +73,10 @@ export default class Application extends EventEmitter {
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
if (this.provider.static) {
|
if (this.provider.static) {
|
||||||
if (this.db.data.core[this.name].updater !== this.msgStatic) {
|
if (this.ctx.db.data.core[this.name].updater !== this.msgStatic) {
|
||||||
this.db.data.core[this.name].updater = ''
|
this.ctx.db.data.core[this.name].updater = ''
|
||||||
this.updateLog(this.msgStatic)
|
this.updateLog(this.msgStatic)
|
||||||
return this.db.write()
|
return this.ctx.db.write()
|
||||||
}
|
}
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
}
|
}
|
||||||
|
@ -76,11 +87,11 @@ export default class Application extends EventEmitter {
|
||||||
return this._update()
|
return this._update()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.updating = false
|
this.updating = false
|
||||||
return this.db.write()
|
return this.ctx.db.write()
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
this.updating = false
|
this.updating = false
|
||||||
return this.db.write()
|
return this.ctx.db.write()
|
||||||
.then(function() { return Promise.reject(err) })
|
.then(function() { return Promise.reject(err) })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -96,7 +107,7 @@ export default class Application extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
async _update() {
|
async _update() {
|
||||||
this.db.data.core[this.name].updater = ''
|
this.ctx.db.data.core[this.name].updater = ''
|
||||||
let cleanup = true
|
let cleanup = true
|
||||||
let folder = ''
|
let folder = ''
|
||||||
let log = ''
|
let log = ''
|
||||||
|
@ -111,7 +122,7 @@ export default class Application extends EventEmitter {
|
||||||
log += this.updateLog(`Found ${latest.version}. `) + '\n'
|
log += this.updateLog(`Found ${latest.version}. `) + '\n'
|
||||||
|
|
||||||
// If the versino matches the latest installed, then there's nothing to do
|
// If the versino matches the latest installed, then there's nothing to do
|
||||||
if (this.db.data.core[this.name].latestInstalled === latest.version) {
|
if (this.ctx.db.data.core[this.name].latestInstalled === latest.version) {
|
||||||
this.updateLog('Already up to date, nothing to do. ')
|
this.updateLog('Already up to date, nothing to do. ')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -121,7 +132,7 @@ export default class Application extends EventEmitter {
|
||||||
latest.id = latest.version
|
latest.id = latest.version
|
||||||
|
|
||||||
// check to see if we already have this version in our database.
|
// check to see if we already have this version in our database.
|
||||||
var found = this.db.get(this.db.data.core[this.name].versions, latest.id)
|
var found = this.ctx.db.get(this.ctx.db.data.core[this.name].versions, latest.id)
|
||||||
if (found) {
|
if (found) {
|
||||||
// Check if the existing version found was already installed.
|
// Check if the existing version found was already installed.
|
||||||
if (found.installed) {
|
if (found.installed) {
|
||||||
|
@ -155,18 +166,18 @@ export default class Application extends EventEmitter {
|
||||||
} else {
|
} else {
|
||||||
// This is a new version, mark it with stable tag of zero.
|
// This is a new version, mark it with stable tag of zero.
|
||||||
latest.stable = 0
|
latest.stable = 0
|
||||||
this.db.upsertFirst(this.db.data.core[this.name].versions, latest)
|
this.ctx.db.upsertFirst(this.ctx.db.data.core[this.name].versions, latest)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The target file for the archive and the target folder for new our version
|
// The target file for the archive and the target folder for new our version
|
||||||
let target = this.util.getPathFromRoot(`./${this.name}/${latest.version}/file${this.util.getExtension(latest.filename)}`)
|
let target = this.ctx.util.getPathFromRoot(`./${this.name}/${latest.version}/file${this.ctx.util.getExtension(latest.filename)}`)
|
||||||
folder = this.util.getPathFromRoot(`./${this.name}/${latest.version}`)
|
folder = this.ctx.util.getPathFromRoot(`./${this.name}/${latest.version}`)
|
||||||
|
|
||||||
// Create it in case it does not exist.
|
// Create it in case it does not exist.
|
||||||
await this.fs.mkdir(folder, { recursive: true })
|
await this.fs.mkdir(folder, { recursive: true })
|
||||||
|
|
||||||
log += this.updateLog(`Downloading ${latest.link} to ${target}. `) + '\n'
|
log += this.updateLog(`Downloading ${latest.link} to ${target}. `) + '\n'
|
||||||
await this.db.write()
|
await this.ctx.db.write()
|
||||||
|
|
||||||
// Download the latest version using the provider in question.
|
// Download the latest version using the provider in question.
|
||||||
await this.provider.downloadVersion(latest, target)
|
await this.provider.downloadVersion(latest, target)
|
||||||
|
@ -176,10 +187,10 @@ export default class Application extends EventEmitter {
|
||||||
})
|
})
|
||||||
|
|
||||||
log += '\n' + this.updateLog(`Extracting ${target}. `) + '\n'
|
log += '\n' + this.updateLog(`Extracting ${target}. `) + '\n'
|
||||||
await this.db.write()
|
await this.ctx.db.write()
|
||||||
|
|
||||||
// Download was successful, extract the archived file that we downloaded
|
// Download was successful, extract the archived file that we downloaded
|
||||||
await this.util.extractFile(target, function(msg) {
|
await this.ctx.util.extractFile(target, function(msg) {
|
||||||
log += msg
|
log += msg
|
||||||
}).catch(function(err) {
|
}).catch(function(err) {
|
||||||
latest.failtodownload = (latest.failtodownload || 0) + 1
|
latest.failtodownload = (latest.failtodownload || 0) + 1
|
||||||
|
@ -196,7 +207,7 @@ export default class Application extends EventEmitter {
|
||||||
// check if the version we downloaded had index.mjs. If this is
|
// check if the version we downloaded had index.mjs. If this is
|
||||||
// missing then either the extracting or download failed without erroring
|
// missing then either the extracting or download failed without erroring
|
||||||
// or the archived is borked.
|
// or the archived is borked.
|
||||||
await this.fs.stat(this.util.getPathFromRoot(`./${this.name}/${latest.version}/index.mjs`))
|
await this.fs.stat(this.ctx.util.getPathFromRoot(`./${this.name}/${latest.version}/index.mjs`))
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
latest.failtodownload = (latest.failtodownload || 0) + 1
|
latest.failtodownload = (latest.failtodownload || 0) + 1
|
||||||
log += this.updateLog('Version did not include or was missing index.mjs. ') + '\n'
|
log += this.updateLog('Version did not include or was missing index.mjs. ') + '\n'
|
||||||
|
@ -212,16 +223,16 @@ export default class Application extends EventEmitter {
|
||||||
// Check if we have a package.json file. If we do, we need to run
|
// Check if we have a package.json file. If we do, we need to run
|
||||||
// npm install. If we don't then this application either has all the
|
// npm install. If we don't then this application either has all the
|
||||||
// required packages or it doesn't need them to run
|
// required packages or it doesn't need them to run
|
||||||
let packageStat = await this.fs.stat(this.util.getPathFromRoot(`./${this.name}/${latest.version}/package.json`))
|
let packageStat = await this.fs.stat(this.ctx.util.getPathFromRoot(`./${this.name}/${latest.version}/package.json`))
|
||||||
.catch(function() { return null })
|
.catch(function() { return null })
|
||||||
|
|
||||||
if (packageStat) {
|
if (packageStat) {
|
||||||
log += this.updateLog(`running npm install --production. `) + '\n'
|
log += this.updateLog(`running npm install --production. `) + '\n'
|
||||||
await this.db.write()
|
await this.ctx.db.write()
|
||||||
|
|
||||||
// For some weird reason, --loglevel=notice is required otherwise
|
// For some weird reason, --loglevel=notice is required otherwise
|
||||||
// we get practically zero log output.
|
// we get practically zero log output.
|
||||||
await this.util.runCommand(
|
await this.ctx.util.runCommand(
|
||||||
'npm.cmd',
|
'npm.cmd',
|
||||||
['install', '--production', '--no-optional', '--no-package-lock', '--no-audit', '--loglevel=notice'],
|
['install', '--production', '--no-optional', '--no-package-lock', '--no-audit', '--loglevel=notice'],
|
||||||
folder,
|
folder,
|
||||||
|
@ -255,33 +266,45 @@ export default class Application extends EventEmitter {
|
||||||
// If we reached here then everything went swimmingly. Mark the version
|
// If we reached here then everything went swimmingly. Mark the version
|
||||||
// as being installed and attach the install log to it.
|
// as being installed and attach the install log to it.
|
||||||
log += this.updateLog(`Finished updating ${this.name} to version ${latest.version}.`) + '\n'
|
log += this.updateLog(`Finished updating ${this.name} to version ${latest.version}.`) + '\n'
|
||||||
this.db.data.core[this.name].latestInstalled = latest.version
|
this.ctx.db.data.core[this.name].latestInstalled = latest.version
|
||||||
latest.installed = true
|
latest.installed = true
|
||||||
latest.log = log
|
latest.log = log
|
||||||
}
|
}
|
||||||
|
|
||||||
registerModule(module) {
|
registerModule(module, version = '') {
|
||||||
if (module && typeof(module) === 'function') {
|
if (module && typeof(module) === 'function') {
|
||||||
return this.registerModule({ start: module })
|
return this.registerModule({ start: module })
|
||||||
}
|
}
|
||||||
if (!module || typeof(module) !== 'object' || typeof(module.start) !== 'function') {
|
if (!module || typeof(module) !== 'object' || typeof(module.start) !== 'function') {
|
||||||
throw new Error(`Application ${this.name} registerModule was called with a non module missing start function`)
|
throw new Error(`Application ${this.name}${version ? ' version ' + version : '' } registerModule was called with a non module missing start function`)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.module = module
|
this.module = module
|
||||||
}
|
}
|
||||||
|
|
||||||
async runVersion(version) {
|
async runVersion(version) {
|
||||||
let module = this.module
|
this.ctx.db.data.core[this.name].active = version
|
||||||
|
await this.ctx.db.write()
|
||||||
|
|
||||||
let errTimeout = new Error(`Application ${this.name} version ${version} timed out (took over ${this.config.waitUntilFail}ms) while running start()`)
|
if (version !== 'static') {
|
||||||
|
let indexPath = this.ctx.util.getPathFromRoot(`./${this.name}/${version}/index.mjs`)
|
||||||
|
await this.fs.stat(indexPath).catch((err) => {
|
||||||
|
return Promise.reject(new Error(`Application ${this.name} version ${version} was missing index.mjs: ${err.message}`))
|
||||||
|
})
|
||||||
|
let module = await import(this.ctx.util.getUrlFromRoot(`./${this.name}/${version}/index.mjs`)).catch((err) => {
|
||||||
|
return Promise.reject(new Error(`Application ${this.name} version ${version} failed to load index.mjs: ${err.message}`))
|
||||||
|
})
|
||||||
|
this.registerModule(module, version)
|
||||||
|
}
|
||||||
|
|
||||||
|
let errTimeout = new Error(`Application ${this.name} version ${version} timed out (took over ${this.config.startWaitUntilFail}ms) while running start()`)
|
||||||
|
|
||||||
await new Promise((res, rej) => {
|
await new Promise((res, rej) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
rej(errTimeout)
|
rej(errTimeout)
|
||||||
}, this.config.waitUntilFail)
|
}, this.config.startWaitUntilFail)
|
||||||
|
|
||||||
let startRes = module.start(this.db, this.db.log, this.http, this.config.port)
|
let startRes = this.module.start(this.http, this.config.port, this.ctx)
|
||||||
if (startRes && startRes.then) {
|
if (startRes && startRes.then) {
|
||||||
return startRes.then(res, rej)
|
return startRes.then(res, rej)
|
||||||
}
|
}
|
||||||
|
@ -291,5 +314,22 @@ export default class Application extends EventEmitter {
|
||||||
if (!this.http.active) {
|
if (!this.http.active) {
|
||||||
return Promise.reject(new Error(`Application ${this.name} version ${version} did not call http.createServer()`))
|
return Promise.reject(new Error(`Application ${this.name} version ${version} did not call http.createServer()`))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let lastErr = null
|
||||||
|
|
||||||
|
for (let i = 0; i < this.config.heartbeatAttempts; i++) {
|
||||||
|
try {
|
||||||
|
await request({ timeout: this.config.heartbeatAttemptsWait }, `http://localhost:${this.config.port}` + this.config.heartbeatPath, null, 0, true)
|
||||||
|
return
|
||||||
|
} catch (err) {
|
||||||
|
lastErr = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject(new Error(`Application ${this.name} version ${version} failed to start properly: ${lastErr.message}`))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
closeServer() {
|
||||||
|
return this.http.closeServer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -46,13 +46,13 @@ export function request(config, path, filePath = null, redirects, fastRaw = fals
|
||||||
if (config.token) {
|
if (config.token) {
|
||||||
headers['Authorization'] = `token ${config.token}`
|
headers['Authorization'] = `token ${config.token}`
|
||||||
}
|
}
|
||||||
let timeout = fastRaw ? 5000 : config.timeout || 10000
|
let timeout = config.timeout || 10000
|
||||||
|
|
||||||
let timedout = false
|
let timedout = false
|
||||||
let timer = setTimeout(function() {
|
let timer = setTimeout(function() {
|
||||||
timedout = true
|
timedout = true
|
||||||
if (req) { req.destroy() }
|
if (req) { req.destroy() }
|
||||||
reject(new Error(`Request ${path} timed out out after ${timeout}`))
|
reject(new Error(`Request ${path} timed out after ${timeout}ms`))
|
||||||
}, timeout)
|
}, timeout)
|
||||||
|
|
||||||
req = h.request({
|
req = h.request({
|
||||||
|
|
539
core/core.mjs
539
core/core.mjs
|
@ -1,499 +1,68 @@
|
||||||
import fs from 'fs'
|
import Application from './application.mjs'
|
||||||
import { EventEmitter } from 'events'
|
import Util from './util.mjs'
|
||||||
import { request } from './client.mjs'
|
import { Low } from 'lowdb'
|
||||||
import HttpServer from './http.mjs'
|
|
||||||
|
|
||||||
const fsp = fs.promises
|
export default class Core {
|
||||||
|
static providers = new Map()
|
||||||
|
static addProvider(name, provider) {
|
||||||
|
if (!name || typeof(name) !== 'string')
|
||||||
|
throw new Error('addProvider name must be a string')
|
||||||
|
if (typeof(provider) !== 'function')
|
||||||
|
throw new Error(`addProvider ${name} provider must be a class`)
|
||||||
|
|
||||||
|
let test = new provider({})
|
||||||
|
if (typeof(test.checkConfig) !== 'function')
|
||||||
|
throw new Error(`addProvider ${name} provider class missing checkConfig`)
|
||||||
|
if (typeof(test.getLatestVersion) !== 'function')
|
||||||
|
throw new Error(`addProvider ${name} provider class missing getLatestVersion`)
|
||||||
|
|
||||||
|
Core.providers.set(name, provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(db, util, log, restart) {
|
||||||
|
// some sanity checks
|
||||||
|
if (typeof(restart) !== 'function') throw new Error('restart parameter was not a function')
|
||||||
|
if (!log || typeof(log) !== 'object') throw new Error('log parameter was invalid')
|
||||||
|
if (typeof(log.event) !== 'object') throw new Error('log parameter was invalid')
|
||||||
|
if (typeof(log.info) !== 'function'
|
||||||
|
|| typeof(log.warn) !== 'function'
|
||||||
|
|| typeof(log.error) !== 'function'
|
||||||
|
|| typeof(log.event.info) !== 'function'
|
||||||
|
|| typeof(log.event.warn) !== 'function'
|
||||||
|
|| typeof(log.event.error) !== 'function') throw new Error('log parameter was invalid')
|
||||||
|
if (!util || !(util instanceof Util)) throw new Error('util not instance of Util')
|
||||||
|
if (!db || !(db instanceof Low)) throw new Error('db not instance of Low')
|
||||||
|
|
||||||
export default class Core extends EventEmitter{
|
|
||||||
constructor(util, config, db, log, closeCb) {
|
|
||||||
super()
|
|
||||||
process.stdin.resume()
|
|
||||||
this.http = new HttpServer()
|
|
||||||
this.util = util
|
|
||||||
this.config = config
|
|
||||||
this.db = db
|
this.db = db
|
||||||
|
this.util = util
|
||||||
this.log = log
|
this.log = log
|
||||||
this._close = closeCb
|
this.restart = restart
|
||||||
this._activeCrashHandler = null
|
this.applications = []
|
||||||
this.appRunning = false
|
this.applicationMap = new Map()
|
||||||
this.manageRunning = false
|
|
||||||
this.monitoring = false
|
|
||||||
this._appUpdating = {
|
|
||||||
fresh: true,
|
|
||||||
updating: false,
|
|
||||||
starting: false,
|
|
||||||
logs: '',
|
|
||||||
}
|
|
||||||
this._manageUpdating = {
|
|
||||||
fresh: true,
|
|
||||||
updating: false,
|
|
||||||
starting: false,
|
|
||||||
logs: '',
|
|
||||||
}
|
|
||||||
|
|
||||||
this.db.set('core.manageActive', null)
|
|
||||||
.set('core.appActive', null)
|
|
||||||
.write().then()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
startMonitor() {
|
getApplication(name) {
|
||||||
if (this.monitoring) return
|
return this.applicationMap.get(name)
|
||||||
this.log.info('[Scheduler] Automatic updater has been turned on. Will check for updates every 3 hours')
|
|
||||||
let updating = false
|
|
||||||
|
|
||||||
this.monitoring = setInterval(async () => {
|
|
||||||
if (updating) return
|
|
||||||
updating = true
|
|
||||||
this.log.info('[Scheduler] Starting automatic check for latest version of app and manage')
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.installLatestVersion('app')
|
|
||||||
await this.installLatestVersion('manage')
|
|
||||||
} catch(err) {
|
|
||||||
this.log.error(err, 'Error checking for latest versions')
|
|
||||||
this.log.event.error('Error checking for latest versions: ' + err.message)
|
|
||||||
updating = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (this.hasNewVersionAvailable('app') || !this.appRunning) {
|
|
||||||
await this.tryStartProgram('app')
|
|
||||||
}
|
|
||||||
} catch(err) {
|
|
||||||
this.log.error(err, 'Unknown error occured attempting to app')
|
|
||||||
this.log.event.error('Unknown error starting app: ' + err.message)
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (this.hasNewVersionAvailable('manage') || !this.manageRunning) {
|
|
||||||
await this.tryStartProgram('manage')
|
|
||||||
}
|
|
||||||
} catch(err) {
|
|
||||||
this.log.error(err, 'Unknown error occured attempting to start manage')
|
|
||||||
this.log.event.error('Unknown error starting manage: ' + err.message)
|
|
||||||
}
|
|
||||||
updating = false
|
|
||||||
}, 1000 * 60 * 60 * 3) // every 3 hours
|
|
||||||
}
|
}
|
||||||
|
|
||||||
restart() {
|
async init() {
|
||||||
this._close()
|
this.util.verifyConfig(this.db.config)
|
||||||
}
|
|
||||||
|
|
||||||
status() {
|
let names = this.util.getAppNames(this.db.config)
|
||||||
return {
|
|
||||||
app: this.appRunning,
|
|
||||||
manage: this.manageRunning,
|
|
||||||
appUpdating: this._appUpdating.updating,
|
|
||||||
manageUpdating: this._manageUpdating.updating,
|
|
||||||
appStarting: this._appUpdating.starting,
|
|
||||||
manageStarting: this._manageUpdating.starting,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getLatestVersion(active, name) {
|
for (let name of names) {
|
||||||
// Example: 'https://api.github.com/repos/thething/sc-helloworld/releases'
|
let provConstructor = Core.providers.get(this.db.config[name].provider)
|
||||||
this.logActive(name, active, `Updater: Fetching release info from: https://api.github.com/repos/${this.config[name + 'Repository']}/releases\n`)
|
let provider = new provConstructor(this.db.config[name])
|
||||||
|
await provider.checkConfig(this.db.config[name])
|
||||||
|
|
||||||
let result = await request(this.config, `https://api.github.com/repos/${this.config[name + 'Repository']}/releases`)
|
let application = new Application({
|
||||||
|
db: this.db,
|
||||||
let items = result.body.filter(function(item) {
|
util: this.util,
|
||||||
if (!item.assets.length) return false
|
log: this.log,
|
||||||
for (let i = 0; i < item.assets.length; i++) {
|
core: this,
|
||||||
if (item.assets[i].name.endsWith('-sc.zip')) return true
|
}, provider, name)
|
||||||
}
|
this.applications.push(application)
|
||||||
})
|
this.applicationMap.set(name, application)
|
||||||
|
|
||||||
if (items && items.length) {
|
|
||||||
for (let x = 0; x < items.length; x++) {
|
|
||||||
let item = items[x]
|
|
||||||
for (let i = 0; i < item.assets.length; i++) {
|
|
||||||
if (item.assets[i].name.endsWith('-sc.zip')) {
|
|
||||||
if (this.db.get('core.' + name + 'LatestInstalled').value() === item.name) {
|
|
||||||
this.logActive(name, active, `Updater: Latest version already installed, exiting early\n`)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
this.logActive(name, active, `Updater: Found version ${item.name} with file ${item.assets[i].name}\n`)
|
|
||||||
|
|
||||||
await this.db.set(`core.${name}LatestVersion`, item.name)
|
|
||||||
.write()
|
|
||||||
this.emit('dbupdated', {})
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: item.name,
|
|
||||||
filename: item.assets[i].name,
|
|
||||||
url: item.assets[i].browser_download_url,
|
|
||||||
description: item.body,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logActive(name, active, logline, doNotPrint = false) {
|
|
||||||
if (!doNotPrint) {
|
|
||||||
this.log.info(`[${name}] ` + logline.replace(/\n/g, ''))
|
|
||||||
}
|
|
||||||
active.logs += logline
|
|
||||||
this.emit(name + 'log', active)
|
|
||||||
}
|
|
||||||
|
|
||||||
getProgramLogs(name) {
|
|
||||||
if (name === 'app' && this._appUpdating.logs) {
|
|
||||||
return this._appUpdating.logs
|
|
||||||
} else if (name === 'manage' && this._manageUpdating.logs) {
|
|
||||||
return this._manageUpdating.logs
|
|
||||||
}
|
|
||||||
|
|
||||||
let latestInstalled = this.db.get('core.' + name + 'LatestInstalled').value()
|
|
||||||
let latestVersion = this.db.get('core.' + name + 'LatestVersion').value()
|
|
||||||
if (latestVersion) {
|
|
||||||
let value = this.db.get(`core_${name}History`).getById(latestVersion).value()
|
|
||||||
if (value) return value.logs
|
|
||||||
}
|
|
||||||
if (latestInstalled) {
|
|
||||||
let value = this.db.get(`core_${name}History`).getById(latestInstalled).value()
|
|
||||||
if (value) return value.logs
|
|
||||||
}
|
|
||||||
return '< no logs found >'
|
|
||||||
}
|
|
||||||
|
|
||||||
async installVersion(name, active, version) {
|
|
||||||
if (fs.existsSync(this.util.getPathFromRoot(`./${name}/` + version.name))) {
|
|
||||||
await this.util.runCommand('rmdir', ['/S', '/Q', `"${this.util.getPathFromRoot(`./${name}/` + version.name)}"`])
|
|
||||||
}
|
|
||||||
if (!fs.existsSync(this.util.getPathFromRoot(`./${name}/`))) {
|
|
||||||
await fsp.mkdir(this.util.getPathFromRoot(`./${name}/`))
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await fsp.mkdir(this.util.getPathFromRoot(`./${name}/` + version.name))
|
|
||||||
} catch(err) {
|
|
||||||
if (err.code !== 'EEXIST') {
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// await fsp.mkdir(this.util.getPathFromRoot(`./${name}/` + version.name + '/node_modules'))
|
|
||||||
this.logActive(name, active, `Installer: Downloading ${version.name} (${version.url}) to ${version.name + '/' + version.name + '.zip'}\n`)
|
|
||||||
let filePath = this.util.getPathFromRoot(`./${name}/` + version.name + '/' + version.name + '.zip')
|
|
||||||
await request(this.config, version.url, filePath)
|
|
||||||
this.logActive(name, active, `Installer: Downloading finished, starting extraction\n`)
|
|
||||||
await this.util.runCommand(
|
|
||||||
'"C:\\Program Files\\7-Zip\\7z.exe"',
|
|
||||||
['x', `"${filePath}"`],
|
|
||||||
this.util.getPathFromRoot(`./${name}/` + version.name + '/'),
|
|
||||||
this.logActive.bind(this, name, active)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!fs.existsSync(this.util.getPathFromRoot(`./${name}/` + version.name + '/index.mjs'))) {
|
|
||||||
this.logActive(name, active, `\nInstaller: ERROR: Missing index.mjs in the folder, exiting\n`)
|
|
||||||
throw new Error(`Missing index.mjs in ${this.util.getPathFromRoot(`./${name}/` + version.name + '/index.mjs')}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logActive(name, active, `\nInstaller: Starting npm install\n`)
|
|
||||||
|
|
||||||
await this.util.runCommand(
|
|
||||||
'npm.cmd',
|
|
||||||
['install', '--production', '--no-optional', '--no-package-lock', '--no-audit'],
|
|
||||||
this.util.getPathFromRoot(`./${name}/` + version.name + '/'),
|
|
||||||
this.logActive.bind(this, name, active)
|
|
||||||
)
|
|
||||||
|
|
||||||
await this.db.set(`core.${name}LatestInstalled`, version.name)
|
|
||||||
.write()
|
|
||||||
this.emit('dbupdated', {})
|
|
||||||
|
|
||||||
this.logActive(name, active, `\nInstaller: Successfully installed ${version.name}\n`)
|
|
||||||
}
|
|
||||||
|
|
||||||
getActive(name) {
|
|
||||||
if (name === 'app') {
|
|
||||||
return this._appUpdating
|
|
||||||
} else if (name === 'manage') {
|
|
||||||
return this._manageUpdating
|
|
||||||
} else {
|
|
||||||
throw new Error('Invalid name: ' + name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async startModule(module, port) {
|
|
||||||
let out = await module.start(this.config, this.db, this.log, this, this.http, port)
|
|
||||||
if (out && out.then) {
|
|
||||||
await out
|
|
||||||
}
|
|
||||||
if (!this.http.getCurrentServer()) {
|
|
||||||
this.log.warn('Module did not call http.createServer')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hasNewVersionAvailable(name) {
|
|
||||||
let newestVersion = this.db.get(`core.${name}LatestInstalled`).value()
|
|
||||||
if (!newestVersion) return false
|
|
||||||
|
|
||||||
let history = this.db.get(`core_${name}History`).getById(newestVersion).value()
|
|
||||||
if (history.installed && history.stable === 0) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
async tryStartProgram(name) {
|
|
||||||
let active = this.getActive(name)
|
|
||||||
|
|
||||||
if (this[name + 'Running'] && !this.hasNewVersionAvailable(name)) {
|
|
||||||
this.log.event.warn('Attempting to start ' + name + ' which is already running')
|
|
||||||
this.log.warn('Attempting to start ' + name + ' which is already running')
|
|
||||||
this.logActive(name, active, `Runner: Attempting to start it but it is already running\n`, true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
active.starting = true
|
|
||||||
|
|
||||||
if (this[name + 'Running']) {
|
|
||||||
let success = await this.http.closeServer(name)
|
|
||||||
if (!success) {
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
|
||||||
this.logActive(name, active, `Runner: Found new version but server could not be shut down, restarting service core\n`)
|
|
||||||
await new Promise(() => {
|
|
||||||
this.log.event.warn('Found new version of ' + name + ' but server could not be shut down gracefully, restarting...', null, () => {
|
|
||||||
process.exit(100)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.logActive(name, active, `Runner: Found new version but server could not be shut down\n`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this[name + 'Running'] = false
|
|
||||||
this.emit('statusupdated', {})
|
|
||||||
}
|
|
||||||
|
|
||||||
let history = this.db.get(`core_${name}History`)
|
|
||||||
.filter('installed')
|
|
||||||
.orderBy('installed', 'desc')
|
|
||||||
.value()
|
|
||||||
this.logActive(name, active, `Runner: Finding available version\n`)
|
|
||||||
|
|
||||||
for (let i = 0; i < history.length; i++) {
|
|
||||||
if ((history[i].stable === -1 && !active.fresh)
|
|
||||||
|| (history[i].stable < -1)) {
|
|
||||||
this.logActive(name, active, `Runner: Skipping version ${history[i].name} due to marked as unstable\n`)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.db.set(`core.${name}Active`, history[i].name)
|
|
||||||
.write()
|
|
||||||
this.emit('dbupdated', {})
|
|
||||||
|
|
||||||
let running = await this.tryStartProgramVersion(name, active, history[i].name)
|
|
||||||
if (running) {
|
|
||||||
history[i].stable = 1
|
|
||||||
} else {
|
|
||||||
if (active.fresh || history[i].stable === -1) {
|
|
||||||
history[i].stable = -2
|
|
||||||
} else {
|
|
||||||
history[i].stable = -1
|
|
||||||
}
|
|
||||||
await this.db.set(`core.${name}Active`, null)
|
|
||||||
.write()
|
|
||||||
this.emit('dbupdated', {})
|
|
||||||
}
|
|
||||||
active.fresh = false
|
|
||||||
|
|
||||||
await this.db.get(`core_${name}History`).updateById(history[i].id, history[i].stable).write()
|
|
||||||
if (history[i].stable > 0) break
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.db.get(`core.${name}Active`).value()) {
|
|
||||||
this.logActive(name, active, `Runner: Could not find any available stable version of ${name}\n`)
|
|
||||||
this.log.error('Unable to start ' + name)
|
|
||||||
this.log.event.error('Unable to start ' + name)
|
|
||||||
}
|
|
||||||
|
|
||||||
active.starting = false
|
|
||||||
}
|
|
||||||
|
|
||||||
programCrashed(name, version, active, oldStable) {
|
|
||||||
let newStable = -2
|
|
||||||
console.log('EXITING:', oldStable, active)
|
|
||||||
if (oldStable === 0 && !active.fresh) {
|
|
||||||
newStable = -1
|
|
||||||
}
|
|
||||||
let temp = this.db.get(`core_${name}History`).getById(version).set('stable', newStable )
|
|
||||||
temp.value() // Trigger update on __wrapped__
|
|
||||||
fs.writeFileSync(this.db.adapterFilePath, JSON.stringify(temp.__wrapped__, null, 2))
|
|
||||||
}
|
|
||||||
|
|
||||||
async tryStartProgramVersion(name, active, version) {
|
|
||||||
if (!version) return false
|
|
||||||
this.logActive(name, active, `Runner: Attempting to start ${version}\n`)
|
|
||||||
let indexPath = this.util.getUrlFromRoot(`./${name}/` + version + '/index.mjs')
|
|
||||||
let module
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.logActive(name, active, `Runner: Loading ${indexPath}\n`)
|
|
||||||
module = await import(indexPath)
|
|
||||||
} catch (err) {
|
|
||||||
this.logActive(name, active, `Runner: Error importing module\n`, true)
|
|
||||||
this.logActive(name, active, `${err.stack}\n`, true)
|
|
||||||
this.log.error(err, `Failed to load ${indexPath}`)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
let checkTimeout = null
|
|
||||||
let oldStable = this.db.get(`core_${name}History`).getById(version).value().stable
|
|
||||||
this._activeCrashHandler = this.programCrashed.bind(this, name, version, active, oldStable)
|
|
||||||
process.once('exit', this._activeCrashHandler)
|
|
||||||
try {
|
|
||||||
let port = name === 'app' ? this.config.port : this.config.managePort
|
|
||||||
await new Promise((res, rej) => {
|
|
||||||
checkTimeout = setTimeout(function() {
|
|
||||||
rej(new Error('Program took longer than 60 seconds to resolve promise'))
|
|
||||||
}, 60 * 1000)
|
|
||||||
|
|
||||||
this.logActive(name, active, `Runner: Starting module\n`)
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.http.setContext(name)
|
|
||||||
this.startModule(module, port)
|
|
||||||
.then(res, rej)
|
|
||||||
} catch (err) {
|
|
||||||
rej(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
clearTimeout(checkTimeout)
|
|
||||||
|
|
||||||
await this.checkProgramRunning(name, active, port)
|
|
||||||
process.off('exit', this._activeCrashHandler)
|
|
||||||
} catch (err) {
|
|
||||||
clearTimeout(checkTimeout)
|
|
||||||
process.off('exit', this._activeCrashHandler)
|
|
||||||
await this.http.closeServer(name)
|
|
||||||
|
|
||||||
this.logActive(name, active, `Runner: Error starting\n`, true)
|
|
||||||
this.logActive(name, active, `${err.stack}\n`, true)
|
|
||||||
this.log.error(err, `Failed to start ${name}`)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
this._activeCrashHandler = null
|
|
||||||
|
|
||||||
this.logActive(name, active, `Runner: Successfully started version ${version}\n`)
|
|
||||||
await this.db.set(`core.${name}Active`, version)
|
|
||||||
.write()
|
|
||||||
|
|
||||||
if (name === 'app') {
|
|
||||||
this.appRunning = true
|
|
||||||
} else {
|
|
||||||
this.manageRunning = true
|
|
||||||
}
|
|
||||||
this.emit('statusupdated', {})
|
|
||||||
|
|
||||||
this.logActive(name, active, `Runner: Module is running successfully\n`)
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
async checkProgramRunning(name, active, port) {
|
|
||||||
this.logActive(name, active, `Checker: Testing out module port ${port}\n`)
|
|
||||||
let start = new Date()
|
|
||||||
let error = null
|
|
||||||
let success = false
|
|
||||||
|
|
||||||
while (new Date() - start < 10 * 1000) {
|
|
||||||
try {
|
|
||||||
let check = await request(this.config, `http://localhost:${port}`, null, 0, true)
|
|
||||||
success = true
|
|
||||||
break
|
|
||||||
} catch(err) {
|
|
||||||
this.logActive(name, active, `Checker: ${err.message}, retrying in 3 seconds\n`)
|
|
||||||
error = err
|
|
||||||
await new Promise(function(res) { setTimeout(res, 3000)})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (success) return true
|
|
||||||
throw error || new Error('Checking server failed')
|
|
||||||
}
|
|
||||||
|
|
||||||
async installLatestVersion(name) {
|
|
||||||
if (!this.config[name + 'Repository']) {
|
|
||||||
if (name === 'app') {
|
|
||||||
this.log.error(name + ' Repository was missing from config')
|
|
||||||
this.log.event.error(name + ' Repository was missing from config')
|
|
||||||
} else {
|
|
||||||
this.log.warn(name + ' Repository was missing from config')
|
|
||||||
this.log.event.warn(name + ' Repository was missing from config')
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let active = this.getActive(name)
|
|
||||||
let oldLogs = active.logs || ''
|
|
||||||
if (oldLogs) {
|
|
||||||
oldLogs += '\n'
|
|
||||||
}
|
|
||||||
active.logs = ''
|
|
||||||
active.updating = true
|
|
||||||
|
|
||||||
this.emit('statusupdated', {})
|
|
||||||
this.logActive(name, active, `Installer: Checking for updates at time: ${new Date().toISOString().replace('T', ' ').split('.')[0]}\n`)
|
|
||||||
|
|
||||||
let version = null
|
|
||||||
let installed = false
|
|
||||||
let found = false
|
|
||||||
try {
|
|
||||||
version = await this.getLatestVersion(active, name)
|
|
||||||
if (version) {
|
|
||||||
let core = this.db.get('core').value()
|
|
||||||
let fromDb = this.db.get(`core_${name}History`).getById(version.name).value()
|
|
||||||
if (!fromDb || !fromDb.installed) {
|
|
||||||
let oldVersion = core[name + 'Current'] || '<none>'
|
|
||||||
this.logActive(name, active, `Installer: Updating from ${oldVersion} to ${version.name}\n`)
|
|
||||||
await this.installVersion(name, active, version)
|
|
||||||
this.logActive(name, active, `Installer: Finished: ${new Date().toISOString().replace('T', ' ').split('.')[0]}\n`)
|
|
||||||
installed = new Date()
|
|
||||||
} else {
|
|
||||||
found = true
|
|
||||||
this.logActive(name, active, `Installer: Version ${version.name} already installed\n`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(err) {
|
|
||||||
this.logActive(name, active, '\n', true)
|
|
||||||
this.logActive(name, active, `Installer: Exception occured while updating ${name}\n`, true)
|
|
||||||
this.logActive(name, active, err.stack, true)
|
|
||||||
this.log.error('Error while updating ' + name, err)
|
|
||||||
}
|
|
||||||
active.updating = false
|
|
||||||
if (version && !found) {
|
|
||||||
await this.db.get(`core_${name}History`).upsert({
|
|
||||||
id: version.name,
|
|
||||||
name: version.name,
|
|
||||||
filename: version.filename,
|
|
||||||
url: version.url,
|
|
||||||
description: version.description,
|
|
||||||
logs: active.logs,
|
|
||||||
stable: 0,
|
|
||||||
installed: installed && installed.toISOString(),
|
|
||||||
}).write()
|
|
||||||
}
|
|
||||||
active.logs = oldLogs + active.logs
|
|
||||||
this.emit(name + 'log', active)
|
|
||||||
this.emit('statusupdated', {})
|
|
||||||
}
|
|
||||||
|
|
||||||
async start(name) {
|
|
||||||
var version = this.db.get('core.' + name + 'LatestInstalled').value()
|
|
||||||
if (version) {
|
|
||||||
await this.tryStartProgram(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.installLatestVersion(name)
|
|
||||||
|
|
||||||
if (version !== this.db.get('core.' + name + 'LatestInstalled').value()) {
|
|
||||||
if (!this[name + 'Running'] || this.hasNewVersionAvailable(name)) {
|
|
||||||
await this.tryStartProgram(name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
499
core/core_old.mjs
Normal file
499
core/core_old.mjs
Normal file
|
@ -0,0 +1,499 @@
|
||||||
|
import fs from 'fs'
|
||||||
|
import { EventEmitter } from 'events'
|
||||||
|
import { request } from './client.mjs'
|
||||||
|
import HttpServer from './http.mjs'
|
||||||
|
|
||||||
|
const fsp = fs.promises
|
||||||
|
|
||||||
|
export default class Core extends EventEmitter{
|
||||||
|
constructor(util, config, db, log, closeCb) {
|
||||||
|
super()
|
||||||
|
process.stdin.resume()
|
||||||
|
this.http = new HttpServer()
|
||||||
|
this.util = util
|
||||||
|
this.config = config
|
||||||
|
this.db = db
|
||||||
|
this.log = log
|
||||||
|
this._close = closeCb
|
||||||
|
this._activeCrashHandler = null
|
||||||
|
this.appRunning = false
|
||||||
|
this.manageRunning = false
|
||||||
|
this.monitoring = false
|
||||||
|
this._appUpdating = {
|
||||||
|
fresh: true,
|
||||||
|
updating: false,
|
||||||
|
starting: false,
|
||||||
|
logs: '',
|
||||||
|
}
|
||||||
|
this._manageUpdating = {
|
||||||
|
fresh: true,
|
||||||
|
updating: false,
|
||||||
|
starting: false,
|
||||||
|
logs: '',
|
||||||
|
}
|
||||||
|
|
||||||
|
this.db.set('core.manageActive', null)
|
||||||
|
.set('core.appActive', null)
|
||||||
|
.write().then()
|
||||||
|
}
|
||||||
|
|
||||||
|
startMonitor() {
|
||||||
|
if (this.monitoring) return
|
||||||
|
this.log.info('[Scheduler] Automatic updater has been turned on. Will check for updates every 3 hours')
|
||||||
|
let updating = false
|
||||||
|
|
||||||
|
this.monitoring = setInterval(async () => {
|
||||||
|
if (updating) return
|
||||||
|
updating = true
|
||||||
|
this.log.info('[Scheduler] Starting automatic check for latest version of app and manage')
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.installLatestVersion('app')
|
||||||
|
await this.installLatestVersion('manage')
|
||||||
|
} catch(err) {
|
||||||
|
this.log.error(err, 'Error checking for latest versions')
|
||||||
|
this.log.event.error('Error checking for latest versions: ' + err.message)
|
||||||
|
updating = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (this.hasNewVersionAvailable('app') || !this.appRunning) {
|
||||||
|
await this.tryStartProgram('app')
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
this.log.error(err, 'Unknown error occured attempting to app')
|
||||||
|
this.log.event.error('Unknown error starting app: ' + err.message)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (this.hasNewVersionAvailable('manage') || !this.manageRunning) {
|
||||||
|
await this.tryStartProgram('manage')
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
this.log.error(err, 'Unknown error occured attempting to start manage')
|
||||||
|
this.log.event.error('Unknown error starting manage: ' + err.message)
|
||||||
|
}
|
||||||
|
updating = false
|
||||||
|
}, 1000 * 60 * 60 * 3) // every 3 hours
|
||||||
|
}
|
||||||
|
|
||||||
|
restart() {
|
||||||
|
this._close()
|
||||||
|
}
|
||||||
|
|
||||||
|
status() {
|
||||||
|
return {
|
||||||
|
app: this.appRunning,
|
||||||
|
manage: this.manageRunning,
|
||||||
|
appUpdating: this._appUpdating.updating,
|
||||||
|
manageUpdating: this._manageUpdating.updating,
|
||||||
|
appStarting: this._appUpdating.starting,
|
||||||
|
manageStarting: this._manageUpdating.starting,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLatestVersion(active, name) {
|
||||||
|
// Example: 'https://api.github.com/repos/thething/sc-helloworld/releases'
|
||||||
|
this.logActive(name, active, `Updater: Fetching release info from: https://api.github.com/repos/${this.config[name + 'Repository']}/releases\n`)
|
||||||
|
|
||||||
|
let result = await request(this.config, `https://api.github.com/repos/${this.config[name + 'Repository']}/releases`)
|
||||||
|
|
||||||
|
let items = result.body.filter(function(item) {
|
||||||
|
if (!item.assets.length) return false
|
||||||
|
for (let i = 0; i < item.assets.length; i++) {
|
||||||
|
if (item.assets[i].name.endsWith('-sc.zip')) return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (items && items.length) {
|
||||||
|
for (let x = 0; x < items.length; x++) {
|
||||||
|
let item = items[x]
|
||||||
|
for (let i = 0; i < item.assets.length; i++) {
|
||||||
|
if (item.assets[i].name.endsWith('-sc.zip')) {
|
||||||
|
if (this.db.get('core.' + name + 'LatestInstalled').value() === item.name) {
|
||||||
|
this.logActive(name, active, `Updater: Latest version already installed, exiting early\n`)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
this.logActive(name, active, `Updater: Found version ${item.name} with file ${item.assets[i].name}\n`)
|
||||||
|
|
||||||
|
await this.db.set(`core.${name}LatestVersion`, item.name)
|
||||||
|
.write()
|
||||||
|
this.emit('dbupdated', {})
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: item.name,
|
||||||
|
filename: item.assets[i].name,
|
||||||
|
url: item.assets[i].browser_download_url,
|
||||||
|
description: item.body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logActive(name, active, logline, doNotPrint = false) {
|
||||||
|
if (!doNotPrint) {
|
||||||
|
this.log.info(`[${name}] ` + logline.replace(/\n/g, ''))
|
||||||
|
}
|
||||||
|
active.logs += logline
|
||||||
|
this.emit(name + 'log', active)
|
||||||
|
}
|
||||||
|
|
||||||
|
getProgramLogs(name) {
|
||||||
|
if (name === 'app' && this._appUpdating.logs) {
|
||||||
|
return this._appUpdating.logs
|
||||||
|
} else if (name === 'manage' && this._manageUpdating.logs) {
|
||||||
|
return this._manageUpdating.logs
|
||||||
|
}
|
||||||
|
|
||||||
|
let latestInstalled = this.db.get('core.' + name + 'LatestInstalled').value()
|
||||||
|
let latestVersion = this.db.get('core.' + name + 'LatestVersion').value()
|
||||||
|
if (latestVersion) {
|
||||||
|
let value = this.db.get(`core_${name}History`).getById(latestVersion).value()
|
||||||
|
if (value) return value.logs
|
||||||
|
}
|
||||||
|
if (latestInstalled) {
|
||||||
|
let value = this.db.get(`core_${name}History`).getById(latestInstalled).value()
|
||||||
|
if (value) return value.logs
|
||||||
|
}
|
||||||
|
return '< no logs found >'
|
||||||
|
}
|
||||||
|
|
||||||
|
async installVersion(name, active, version) {
|
||||||
|
if (fs.existsSync(this.util.getPathFromRoot(`./${name}/` + version.name))) {
|
||||||
|
await this.util.runCommand('rmdir', ['/S', '/Q', `"${this.util.getPathFromRoot(`./${name}/` + version.name)}"`])
|
||||||
|
}
|
||||||
|
if (!fs.existsSync(this.util.getPathFromRoot(`./${name}/`))) {
|
||||||
|
await fsp.mkdir(this.util.getPathFromRoot(`./${name}/`))
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await fsp.mkdir(this.util.getPathFromRoot(`./${name}/` + version.name))
|
||||||
|
} catch(err) {
|
||||||
|
if (err.code !== 'EEXIST') {
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// await fsp.mkdir(this.util.getPathFromRoot(`./${name}/` + version.name + '/node_modules'))
|
||||||
|
this.logActive(name, active, `Installer: Downloading ${version.name} (${version.url}) to ${version.name + '/' + version.name + '.zip'}\n`)
|
||||||
|
let filePath = this.util.getPathFromRoot(`./${name}/` + version.name + '/' + version.name + '.zip')
|
||||||
|
await request(this.config, version.url, filePath)
|
||||||
|
this.logActive(name, active, `Installer: Downloading finished, starting extraction\n`)
|
||||||
|
await this.util.runCommand(
|
||||||
|
'"C:\\Program Files\\7-Zip\\7z.exe"',
|
||||||
|
['x', `"${filePath}"`],
|
||||||
|
this.util.getPathFromRoot(`./${name}/` + version.name + '/'),
|
||||||
|
this.logActive.bind(this, name, active)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!fs.existsSync(this.util.getPathFromRoot(`./${name}/` + version.name + '/index.mjs'))) {
|
||||||
|
this.logActive(name, active, `\nInstaller: ERROR: Missing index.mjs in the folder, exiting\n`)
|
||||||
|
throw new Error(`Missing index.mjs in ${this.util.getPathFromRoot(`./${name}/` + version.name + '/index.mjs')}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logActive(name, active, `\nInstaller: Starting npm install\n`)
|
||||||
|
|
||||||
|
await this.util.runCommand(
|
||||||
|
'npm.cmd',
|
||||||
|
['install', '--production', '--no-optional', '--no-package-lock', '--no-audit'],
|
||||||
|
this.util.getPathFromRoot(`./${name}/` + version.name + '/'),
|
||||||
|
this.logActive.bind(this, name, active)
|
||||||
|
)
|
||||||
|
|
||||||
|
await this.db.set(`core.${name}LatestInstalled`, version.name)
|
||||||
|
.write()
|
||||||
|
this.emit('dbupdated', {})
|
||||||
|
|
||||||
|
this.logActive(name, active, `\nInstaller: Successfully installed ${version.name}\n`)
|
||||||
|
}
|
||||||
|
|
||||||
|
getActive(name) {
|
||||||
|
if (name === 'app') {
|
||||||
|
return this._appUpdating
|
||||||
|
} else if (name === 'manage') {
|
||||||
|
return this._manageUpdating
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid name: ' + name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async startModule(module, port) {
|
||||||
|
let out = await module.start(this.config, this.db, this.log, this, this.http, port)
|
||||||
|
if (out && out.then) {
|
||||||
|
await out
|
||||||
|
}
|
||||||
|
if (!this.http.getCurrentServer()) {
|
||||||
|
this.log.warn('Module did not call http.createServer')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hasNewVersionAvailable(name) {
|
||||||
|
let newestVersion = this.db.get(`core.${name}LatestInstalled`).value()
|
||||||
|
if (!newestVersion) return false
|
||||||
|
|
||||||
|
let history = this.db.get(`core_${name}History`).getById(newestVersion).value()
|
||||||
|
if (history.installed && history.stable === 0) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
async tryStartProgram(name) {
|
||||||
|
let active = this.getActive(name)
|
||||||
|
|
||||||
|
if (this[name + 'Running'] && !this.hasNewVersionAvailable(name)) {
|
||||||
|
this.log.event.warn('Attempting to start ' + name + ' which is already running')
|
||||||
|
this.log.warn('Attempting to start ' + name + ' which is already running')
|
||||||
|
this.logActive(name, active, `Runner: Attempting to start it but it is already running\n`, true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
active.starting = true
|
||||||
|
|
||||||
|
if (this[name + 'Running']) {
|
||||||
|
let success = await this.http.closeServer(name)
|
||||||
|
if (!success) {
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
this.logActive(name, active, `Runner: Found new version but server could not be shut down, restarting service core\n`)
|
||||||
|
await new Promise(() => {
|
||||||
|
this.log.event.warn('Found new version of ' + name + ' but server could not be shut down gracefully, restarting...', null, () => {
|
||||||
|
process.exit(100)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.logActive(name, active, `Runner: Found new version but server could not be shut down\n`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this[name + 'Running'] = false
|
||||||
|
this.emit('statusupdated', {})
|
||||||
|
}
|
||||||
|
|
||||||
|
let history = this.db.get(`core_${name}History`)
|
||||||
|
.filter('installed')
|
||||||
|
.orderBy('installed', 'desc')
|
||||||
|
.value()
|
||||||
|
this.logActive(name, active, `Runner: Finding available version\n`)
|
||||||
|
|
||||||
|
for (let i = 0; i < history.length; i++) {
|
||||||
|
if ((history[i].stable === -1 && !active.fresh)
|
||||||
|
|| (history[i].stable < -1)) {
|
||||||
|
this.logActive(name, active, `Runner: Skipping version ${history[i].name} due to marked as unstable\n`)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.db.set(`core.${name}Active`, history[i].name)
|
||||||
|
.write()
|
||||||
|
this.emit('dbupdated', {})
|
||||||
|
|
||||||
|
let running = await this.tryStartProgramVersion(name, active, history[i].name)
|
||||||
|
if (running) {
|
||||||
|
history[i].stable = 1
|
||||||
|
} else {
|
||||||
|
if (active.fresh || history[i].stable === -1) {
|
||||||
|
history[i].stable = -2
|
||||||
|
} else {
|
||||||
|
history[i].stable = -1
|
||||||
|
}
|
||||||
|
await this.db.set(`core.${name}Active`, null)
|
||||||
|
.write()
|
||||||
|
this.emit('dbupdated', {})
|
||||||
|
}
|
||||||
|
active.fresh = false
|
||||||
|
|
||||||
|
await this.db.get(`core_${name}History`).updateById(history[i].id, history[i].stable).write()
|
||||||
|
if (history[i].stable > 0) break
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.db.get(`core.${name}Active`).value()) {
|
||||||
|
this.logActive(name, active, `Runner: Could not find any available stable version of ${name}\n`)
|
||||||
|
this.log.error('Unable to start ' + name)
|
||||||
|
this.log.event.error('Unable to start ' + name)
|
||||||
|
}
|
||||||
|
|
||||||
|
active.starting = false
|
||||||
|
}
|
||||||
|
|
||||||
|
programCrashed(name, version, active, oldStable) {
|
||||||
|
let newStable = -2
|
||||||
|
console.log('EXITING:', oldStable, active)
|
||||||
|
if (oldStable === 0 && !active.fresh) {
|
||||||
|
newStable = -1
|
||||||
|
}
|
||||||
|
let temp = this.db.get(`core_${name}History`).getById(version).set('stable', newStable )
|
||||||
|
temp.value() // Trigger update on __wrapped__
|
||||||
|
fs.writeFileSync(this.db.adapterFilePath, JSON.stringify(temp.__wrapped__, null, 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
async tryStartProgramVersion(name, active, version) {
|
||||||
|
if (!version) return false
|
||||||
|
this.logActive(name, active, `Runner: Attempting to start ${version}\n`)
|
||||||
|
let indexPath = this.util.getUrlFromRoot(`./${name}/` + version + '/index.mjs')
|
||||||
|
let module
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.logActive(name, active, `Runner: Loading ${indexPath}\n`)
|
||||||
|
module = await import(indexPath)
|
||||||
|
} catch (err) {
|
||||||
|
this.logActive(name, active, `Runner: Error importing module\n`, true)
|
||||||
|
this.logActive(name, active, `${err.stack}\n`, true)
|
||||||
|
this.log.error(err, `Failed to load ${indexPath}`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let checkTimeout = null
|
||||||
|
let oldStable = this.db.get(`core_${name}History`).getById(version).value().stable
|
||||||
|
this._activeCrashHandler = this.programCrashed.bind(this, name, version, active, oldStable)
|
||||||
|
process.once('exit', this._activeCrashHandler)
|
||||||
|
try {
|
||||||
|
let port = name === 'app' ? this.config.port : this.config.managePort
|
||||||
|
await new Promise((res, rej) => {
|
||||||
|
checkTimeout = setTimeout(function() {
|
||||||
|
rej(new Error('Program took longer than 60 seconds to resolve promise'))
|
||||||
|
}, 60 * 1000)
|
||||||
|
|
||||||
|
this.logActive(name, active, `Runner: Starting module\n`)
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.http.setContext(name)
|
||||||
|
this.startModule(module, port)
|
||||||
|
.then(res, rej)
|
||||||
|
} catch (err) {
|
||||||
|
rej(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
clearTimeout(checkTimeout)
|
||||||
|
|
||||||
|
await this.checkProgramRunning(name, active, port)
|
||||||
|
process.off('exit', this._activeCrashHandler)
|
||||||
|
} catch (err) {
|
||||||
|
clearTimeout(checkTimeout)
|
||||||
|
process.off('exit', this._activeCrashHandler)
|
||||||
|
await this.http.closeServer(name)
|
||||||
|
|
||||||
|
this.logActive(name, active, `Runner: Error starting\n`, true)
|
||||||
|
this.logActive(name, active, `${err.stack}\n`, true)
|
||||||
|
this.log.error(err, `Failed to start ${name}`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
this._activeCrashHandler = null
|
||||||
|
|
||||||
|
this.logActive(name, active, `Runner: Successfully started version ${version}\n`)
|
||||||
|
await this.db.set(`core.${name}Active`, version)
|
||||||
|
.write()
|
||||||
|
|
||||||
|
if (name === 'app') {
|
||||||
|
this.appRunning = true
|
||||||
|
} else {
|
||||||
|
this.manageRunning = true
|
||||||
|
}
|
||||||
|
this.emit('statusupdated', {})
|
||||||
|
|
||||||
|
this.logActive(name, active, `Runner: Module is running successfully\n`)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkProgramRunning(name, active, port) {
|
||||||
|
this.logActive(name, active, `Checker: Testing out module port ${port}\n`)
|
||||||
|
let start = new Date()
|
||||||
|
let error = null
|
||||||
|
let success = false
|
||||||
|
|
||||||
|
while (new Date() - start < 10 * 1000) {
|
||||||
|
try {
|
||||||
|
let check = await request(this.config, `http://localhost:${port}`, null, 0, true)
|
||||||
|
success = true
|
||||||
|
break
|
||||||
|
} catch(err) {
|
||||||
|
this.logActive(name, active, `Checker: ${err.message}, retrying in 3 seconds\n`)
|
||||||
|
error = err
|
||||||
|
await new Promise(function(res) { setTimeout(res, 3000)})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (success) return true
|
||||||
|
throw error || new Error('Checking server failed')
|
||||||
|
}
|
||||||
|
|
||||||
|
async installLatestVersion(name) {
|
||||||
|
if (!this.config[name + 'Repository']) {
|
||||||
|
if (name === 'app') {
|
||||||
|
this.log.error(name + ' Repository was missing from config')
|
||||||
|
this.log.event.error(name + ' Repository was missing from config')
|
||||||
|
} else {
|
||||||
|
this.log.warn(name + ' Repository was missing from config')
|
||||||
|
this.log.event.warn(name + ' Repository was missing from config')
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let active = this.getActive(name)
|
||||||
|
let oldLogs = active.logs || ''
|
||||||
|
if (oldLogs) {
|
||||||
|
oldLogs += '\n'
|
||||||
|
}
|
||||||
|
active.logs = ''
|
||||||
|
active.updating = true
|
||||||
|
|
||||||
|
this.emit('statusupdated', {})
|
||||||
|
this.logActive(name, active, `Installer: Checking for updates at time: ${new Date().toISOString().replace('T', ' ').split('.')[0]}\n`)
|
||||||
|
|
||||||
|
let version = null
|
||||||
|
let installed = false
|
||||||
|
let found = false
|
||||||
|
try {
|
||||||
|
version = await this.getLatestVersion(active, name)
|
||||||
|
if (version) {
|
||||||
|
let core = this.db.get('core').value()
|
||||||
|
let fromDb = this.db.get(`core_${name}History`).getById(version.name).value()
|
||||||
|
if (!fromDb || !fromDb.installed) {
|
||||||
|
let oldVersion = core[name + 'Current'] || '<none>'
|
||||||
|
this.logActive(name, active, `Installer: Updating from ${oldVersion} to ${version.name}\n`)
|
||||||
|
await this.installVersion(name, active, version)
|
||||||
|
this.logActive(name, active, `Installer: Finished: ${new Date().toISOString().replace('T', ' ').split('.')[0]}\n`)
|
||||||
|
installed = new Date()
|
||||||
|
} else {
|
||||||
|
found = true
|
||||||
|
this.logActive(name, active, `Installer: Version ${version.name} already installed\n`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
this.logActive(name, active, '\n', true)
|
||||||
|
this.logActive(name, active, `Installer: Exception occured while updating ${name}\n`, true)
|
||||||
|
this.logActive(name, active, err.stack, true)
|
||||||
|
this.log.error('Error while updating ' + name, err)
|
||||||
|
}
|
||||||
|
active.updating = false
|
||||||
|
if (version && !found) {
|
||||||
|
await this.db.get(`core_${name}History`).upsert({
|
||||||
|
id: version.name,
|
||||||
|
name: version.name,
|
||||||
|
filename: version.filename,
|
||||||
|
url: version.url,
|
||||||
|
description: version.description,
|
||||||
|
logs: active.logs,
|
||||||
|
stable: 0,
|
||||||
|
installed: installed && installed.toISOString(),
|
||||||
|
}).write()
|
||||||
|
}
|
||||||
|
active.logs = oldLogs + active.logs
|
||||||
|
this.emit(name + 'log', active)
|
||||||
|
this.emit('statusupdated', {})
|
||||||
|
}
|
||||||
|
|
||||||
|
async start(name) {
|
||||||
|
var version = this.db.get('core.' + name + 'LatestInstalled').value()
|
||||||
|
if (version) {
|
||||||
|
await this.tryStartProgram(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.installLatestVersion(name)
|
||||||
|
|
||||||
|
if (version !== this.db.get('core.' + name + 'LatestInstalled').value()) {
|
||||||
|
if (!this[name + 'Running'] || this.hasNewVersionAvailable(name)) {
|
||||||
|
await this.tryStartProgram(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
import { setTimeout } from 'timers/promises'
|
import { setTimeout } from 'timers/promises'
|
||||||
import { Low, JSONFile, Memory } from 'lowdb'
|
import { Low, JSONFile, Memory } from 'lowdb'
|
||||||
import { type } from 'os'
|
|
||||||
import { defaults, isObject } from './defaults.mjs'
|
import { defaults, isObject } from './defaults.mjs'
|
||||||
|
|
||||||
export default function GetDB(config, log, orgFilename = 'db.json') {
|
export default function GetDB(config, log, orgFilename = 'db.json') {
|
||||||
|
@ -87,9 +86,9 @@ export default function GetDB(config, log, orgFilename = 'db.json') {
|
||||||
db.addApplication = function(name) {
|
db.addApplication = function(name) {
|
||||||
db.data.core[name] ||= {}
|
db.data.core[name] ||= {}
|
||||||
defaults(db.data.core[name], {
|
defaults(db.data.core[name], {
|
||||||
active: null,
|
active: '',
|
||||||
latestInstalled: null,
|
latestInstalled: '',
|
||||||
latestVersion: null,
|
latestVersion: '',
|
||||||
updater: '',
|
updater: '',
|
||||||
versions: [],
|
versions: [],
|
||||||
})
|
})
|
||||||
|
|
|
@ -24,6 +24,17 @@ export default class HttpServer {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
server.listenAsync = (port, host) => {
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
server.once('error', rej)
|
||||||
|
|
||||||
|
server.listen(port, host || '0.0.0.0', () => {
|
||||||
|
server.off('error', rej)
|
||||||
|
res()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
this.active = server
|
this.active = server
|
||||||
return server
|
return server
|
||||||
}
|
}
|
||||||
|
@ -38,11 +49,13 @@ export default class HttpServer {
|
||||||
this.sockets.clear()
|
this.sockets.clear()
|
||||||
|
|
||||||
this.active.close(err => {
|
this.active.close(err => {
|
||||||
if (err) return rej(err)
|
if (err) {
|
||||||
|
if (err.code !== 'ERR_SERVER_NOT_RUNNING') return rej(err)
|
||||||
|
}
|
||||||
this.active = null
|
this.active = null
|
||||||
|
|
||||||
// Waiting 1 second for it to close down
|
// Waiting 1 second for it to close down
|
||||||
setTimeout(function() {res() }, 1000)
|
setTimeout(function() {res() }, 100)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
77
core/log.mjs
77
core/log.mjs
|
@ -1,15 +1,24 @@
|
||||||
import nodewindows from 'node-windows'
|
// import nodewindows from 'node-windows'
|
||||||
import bunyan from 'bunyan-lite'
|
import bunyan from 'bunyan-lite'
|
||||||
|
import { setTimeout } from 'timers/promises'
|
||||||
|
|
||||||
export default function getLog(name) {
|
export default function getLog(name, streams = null, opts = {}) {
|
||||||
let settings
|
let settings
|
||||||
let ringbuffer = new bunyan.RingBuffer({ limit: 100 })
|
let ringbuffer = new bunyan.RingBuffer({ limit: 100 })
|
||||||
let ringbufferwarn = new bunyan.RingBuffer({ limit: 100 })
|
let ringbufferwarn = new bunyan.RingBuffer({ limit: 100 })
|
||||||
|
|
||||||
|
if (streams) {
|
||||||
|
streams.forEach(function(stream) {
|
||||||
|
if (stream.stream === 'process.stdout') {
|
||||||
|
stream.stream = process.stdout
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
if (process.env.NODE_ENV === 'production') {
|
||||||
settings = {
|
settings = {
|
||||||
"name": "service-core",
|
"name": name,
|
||||||
"streams": [{
|
"streams": streams || [{
|
||||||
path: 'log.log',
|
path: 'log.log',
|
||||||
level: 'info',
|
level: 'info',
|
||||||
}
|
}
|
||||||
|
@ -17,8 +26,8 @@ export default function getLog(name) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
settings = {
|
settings = {
|
||||||
"name": "service-core",
|
"name": name,
|
||||||
"streams": [{
|
"streams": streams || [{
|
||||||
"stream": process.stdout,
|
"stream": process.stdout,
|
||||||
"level": "debug"
|
"level": "debug"
|
||||||
}
|
}
|
||||||
|
@ -53,16 +62,64 @@ export default function getLog(name) {
|
||||||
level: 'info',
|
level: 'info',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let eventManager = null
|
||||||
|
let eventManagerLoading = false
|
||||||
|
|
||||||
|
async function safeLoadEvent(level, message, code) {
|
||||||
|
if (eventManager === false) {
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!eventManager) {
|
||||||
|
if (eventManagerLoading) {
|
||||||
|
for (let i = 0; i < 10 && eventManagerLoading; i++) {
|
||||||
|
await setTimeout(50)
|
||||||
|
}
|
||||||
|
if (eventManagerLoading) {
|
||||||
|
eventManager = false
|
||||||
|
}
|
||||||
|
return safeLoadEvent(level, message, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
eventManagerLoading = true
|
||||||
|
|
||||||
|
let prom
|
||||||
|
if (opts.import) {
|
||||||
|
prom = opts.import('node-windows')
|
||||||
|
} else {
|
||||||
|
prom = import('node-windows')
|
||||||
|
}
|
||||||
|
await prom.then(
|
||||||
|
function(res) { eventManager = new res.default.EventLogger(name) },
|
||||||
|
function() { eventManager = false },
|
||||||
|
)
|
||||||
|
eventManagerLoading = false
|
||||||
|
return safeLoadEvent(level, message, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise(function(res) {
|
||||||
|
try {
|
||||||
|
eventManager[level](message, code, function() { res() })
|
||||||
|
} catch {
|
||||||
|
res()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Create our logger.
|
// Create our logger.
|
||||||
logger = bunyan.createLogger(settings)
|
logger = bunyan.createLogger(settings)
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
if (process.env.NODE_ENV === 'production') {
|
||||||
logger.event = new nodewindows.EventLogger(name)
|
logger.event = {
|
||||||
|
info: safeLoadEvent.bind(this, 'info'),
|
||||||
|
warn: safeLoadEvent.bind(this, 'warn'),
|
||||||
|
error: safeLoadEvent.bind(this, 'error'),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.event = {
|
logger.event = {
|
||||||
info: function() {},
|
info: function() { return Promise.resolve() },
|
||||||
warn: function() {},
|
warn: function() { return Promise.resolve() },
|
||||||
error: function() {},
|
error: function() { return Promise.resolve() },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.ringbuffer = ringbuffer
|
logger.ringbuffer = ringbuffer
|
||||||
|
|
|
@ -26,15 +26,58 @@ export default class Util {
|
||||||
}
|
}
|
||||||
|
|
||||||
getAppNames(config) {
|
getAppNames(config) {
|
||||||
|
const validLevels = [
|
||||||
|
'fatal',
|
||||||
|
'error',
|
||||||
|
'warn',
|
||||||
|
'info',
|
||||||
|
'debug',
|
||||||
|
'trace',
|
||||||
|
]
|
||||||
let out = []
|
let out = []
|
||||||
let keys = Object.keys(config)
|
let keys = Object.keys(config)
|
||||||
for (let key of keys) {
|
for (let key of keys) {
|
||||||
if (typeof(config[key]) !== 'object' || config[key] == null) continue
|
if (typeof(config[key]) !== 'object' || config[key] == null)
|
||||||
if (typeof(config[key].port) !== 'number' || !config[key].port) continue
|
continue
|
||||||
if (typeof(config[key].provider) !== 'string' || !config[key].provider) continue
|
if (typeof(config[key].port) !== 'number' || !config[key].port)
|
||||||
if (config[key].https != null && typeof(config[key].https) !== 'boolean') continue
|
continue
|
||||||
if (config[key].updateEvery != null && (typeof(config[key].updateEvery) !== 'number' || config[key].updateEvery < 1)) continue
|
if (typeof(config[key].provider) !== 'string' || !config[key].provider)
|
||||||
if (config[key].waitUntilFail != null && (typeof(config[key].waitUntilFail) !== 'number' || config[key].waitUntilFail < 10)) continue
|
continue
|
||||||
|
if (config[key].https != null && typeof(config[key].https) !== 'boolean')
|
||||||
|
continue
|
||||||
|
if (config[key].updateEvery != null && (typeof(config[key].updateEvery) !== 'number' || config[key].updateEvery < 0))
|
||||||
|
continue
|
||||||
|
if (config[key].startWaitUntilFail != null && (typeof(config[key].startWaitUntilFail) !== 'number' || config[key].startWaitUntilFail < 10))
|
||||||
|
continue
|
||||||
|
if (config[key].heartbeatTimeout != null && (typeof(config[key].heartbeatTimeout) !== 'number' || config[key].heartbeatTimeout < 10))
|
||||||
|
continue
|
||||||
|
if (config[key].heartbeatAttempts != null && (typeof(config[key].heartbeatAttempts) !== 'number' || config[key].heartbeatAttempts < 1))
|
||||||
|
continue
|
||||||
|
if (config[key].heartbeatAttemptsWait != null && (typeof(config[key].heartbeatAttemptsWait) !== 'number' || config[key].heartbeatAttemptsWait < 10))
|
||||||
|
continue
|
||||||
|
if (config[key].heartbeatPath != null && (typeof(config[key].heartbeatPath) !== 'string' || config[key].heartbeatPath[0] !== '/'))
|
||||||
|
continue
|
||||||
|
if (config[key].log != null) {
|
||||||
|
if (!Array.isArray(config[key].log))
|
||||||
|
continue
|
||||||
|
let valid = true
|
||||||
|
for (let stream of config[key].log) {
|
||||||
|
if (!stream || typeof(stream) !== 'object' || Array.isArray(stream)) {
|
||||||
|
valid = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (typeof(stream.level) !== 'string' || !stream.level || !validLevels.includes(stream.level)) {
|
||||||
|
valid = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if ((typeof(stream.path) !== 'string' || !stream.path) && stream.stream !== 'process.stdout') {
|
||||||
|
valid = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!valid)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
out.push(key)
|
out.push(key)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "nodemon --watch dev/api --watch core --watch runner.mjs --watch db.mjs --watch log.mjs runner.mjs | bunyan",
|
"dev": "nodemon --watch dev/api --watch core --watch runner.mjs --watch db.mjs --watch log.mjs runner.mjs | bunyan",
|
||||||
"test": "eltro \"test/**/*.test.mjs\" -r dot",
|
"test": "eltro \"test/**/*.test.mjs\" -r dot",
|
||||||
|
"test:spec": "eltro \"test/**/*.test.mjs\" -r list",
|
||||||
"test:watch": "npm-watch test"
|
"test:watch": "npm-watch test"
|
||||||
},
|
},
|
||||||
"watch": {
|
"watch": {
|
||||||
|
@ -13,7 +14,10 @@
|
||||||
"patterns": [
|
"patterns": [
|
||||||
"{core,test}/*"
|
"{core,test}/*"
|
||||||
],
|
],
|
||||||
"ignore": "test/testapp",
|
"ignore": [
|
||||||
|
"test/testapp",
|
||||||
|
"test/testnoexisting"
|
||||||
|
],
|
||||||
"extensions": "js,mjs",
|
"extensions": "js,mjs",
|
||||||
"quiet": true,
|
"quiet": true,
|
||||||
"inherit": true
|
"inherit": true
|
||||||
|
|
|
@ -1,38 +1,38 @@
|
||||||
import { Eltro as t, assert, stub } from 'eltro'
|
import { Eltro as t, assert, stub } from 'eltro'
|
||||||
import fs from 'fs/promises'
|
import fs from 'fs/promises'
|
||||||
import lowdb from '../core/db.mjs'
|
|
||||||
import Application from '../core/application.mjs'
|
import Application from '../core/application.mjs'
|
||||||
import GitProvider from '../core/providers/git.mjs'
|
import GitProvider from '../core/providers/git.mjs'
|
||||||
import Util from '../core/util.mjs'
|
import Util from '../core/util.mjs'
|
||||||
|
import { createFakeContext } from './helpers.mjs'
|
||||||
|
|
||||||
const util = new Util(import.meta.url)
|
const util = new Util(import.meta.url)
|
||||||
const logger = {
|
|
||||||
info: stub(),
|
|
||||||
warn: stub(),
|
|
||||||
error: stub(),
|
|
||||||
}
|
|
||||||
|
|
||||||
t.skip().timeout(10000).describe('Application update integration test', function() {
|
t.skip().timeout(10000).describe('Application update integration test', function() {
|
||||||
let db
|
let ctx
|
||||||
let app
|
let app
|
||||||
let provider
|
let provider
|
||||||
|
|
||||||
t.before(function() {
|
t.before(function() {
|
||||||
return lowdb({ test: { } }, logger, util.getPathFromRoot('./db_test.json')).then(function(res) {
|
return createFakeContext({ }, util, util.getPathFromRoot('./db_test.json'))
|
||||||
db = res
|
.then(function(res) {
|
||||||
provider = new GitProvider({ url: 'https://git.nfp.is/api/v1/repos/thething/sc-helloworld/releases' })
|
ctx = res
|
||||||
app = new Application(util, db, provider, 'testapp')
|
provider = new GitProvider({ url: 'https://git.nfp.is/api/v1/repos/thething/sc-helloworld/releases' })
|
||||||
|
app = new Application(ctx, provider, 'testapp')
|
||||||
return provider.getLatestVersion()
|
|
||||||
}).then(function(version) {
|
return provider.getLatestVersion()
|
||||||
return fs.rm(`./test/testapp/${version.version}`, { force: true, recursive: true })
|
}).then(function(version) {
|
||||||
})
|
return fs.rm(`./test/testapp/${version.version}`, { force: true, recursive: true })
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.after(function() {
|
t.after(function() {
|
||||||
if (db.data.core.testapp.versions.length) {
|
return fs.rm(util.getPathFromRoot('./db_test.json'))
|
||||||
return fs.rm(`./test/testapp/${db.data.core.testapp.versions[0].id}`, { force: true, recursive: true })
|
.then(function() {
|
||||||
}
|
if (ctx.db.data.core.testapp.versions.length) {
|
||||||
|
return fs.rm(`./test/testapp/${ctx.db.data.core.testapp.versions[0].id}`, { force: true, recursive: true })
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should run update and install correctly', async function(){
|
t.test('should run update and install correctly', async function(){
|
||||||
|
@ -40,15 +40,15 @@ t.skip().timeout(10000).describe('Application update integration test', function
|
||||||
await app.update()
|
await app.update()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
if (db.data.core.testapp.versions.length) {
|
if (ctx.db.data.core.testapp.versions.length) {
|
||||||
console.log(db.data.core.testapp.versions[0].log)
|
console.log(ctx.db.data.core.testapp.versions[0].log)
|
||||||
}
|
}
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.ok(db.data.core.testapp.latestInstalled)
|
assert.ok(ctx.db.data.core.testapp.latestInstalled)
|
||||||
await fs.stat(util.getPathFromRoot(`./testapp/${db.data.core.testapp.latestInstalled}/index.mjs`))
|
await fs.stat(util.getPathFromRoot(`./testapp/${ctx.db.data.core.testapp.latestInstalled}/index.mjs`))
|
||||||
await fs.stat(util.getPathFromRoot(`./testapp/${db.data.core.testapp.latestInstalled}/package.json`))
|
await fs.stat(util.getPathFromRoot(`./testapp/${ctx.db.data.core.testapp.latestInstalled}/package.json`))
|
||||||
await fs.stat(util.getPathFromRoot(`./testapp/${db.data.core.testapp.latestInstalled}/node_modules`))
|
await fs.stat(util.getPathFromRoot(`./testapp/${ctx.db.data.core.testapp.latestInstalled}/node_modules`))
|
||||||
})
|
})
|
||||||
})
|
})
|
|
@ -1,58 +1,59 @@
|
||||||
import { Eltro as t, assert, stub } from 'eltro'
|
import { Eltro as t, assert, stub } from 'eltro'
|
||||||
import fs from 'fs/promises'
|
import fs from 'fs/promises'
|
||||||
import lowdb from '../core/db.mjs'
|
|
||||||
import Application from '../core/application.mjs'
|
import Application from '../core/application.mjs'
|
||||||
import Util from '../core/util.mjs'
|
import Util from '../core/util.mjs'
|
||||||
|
import lowdb from '../core/db.mjs'
|
||||||
import StaticProvider from '../core/providers/static.mjs'
|
import StaticProvider from '../core/providers/static.mjs'
|
||||||
|
import { createFakeContext } from './helpers.mjs'
|
||||||
|
|
||||||
const util = new Util(import.meta.url)
|
const util = new Util(import.meta.url)
|
||||||
|
|
||||||
const logger = {
|
t.describe('#runVersion("static")', function() {
|
||||||
info: stub(),
|
|
||||||
warn: stub(),
|
|
||||||
error: stub(),
|
|
||||||
}
|
|
||||||
function createProvider() {
|
|
||||||
return {
|
|
||||||
getLatestVersion: stub(),
|
|
||||||
downloadVersion: stub(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
t.timeout(250).describe('#runVersion()', function() {
|
|
||||||
const assertPort = 22345
|
const assertPort = 22345
|
||||||
let db
|
let ctx
|
||||||
let app
|
let app
|
||||||
|
|
||||||
const defaultHandler = function(db, log, http, port) {
|
const defaultHandler = function(orgHandler) {
|
||||||
const server = http.createServer(function (req, res) {
|
let handler = orgHandler || function (req, res) {
|
||||||
res.writeHead(204); res.end(JSON.stringify({ a: 1 }))
|
res.writeHead(204); res.end(JSON.stringify({ a: 1 }))
|
||||||
})
|
}
|
||||||
|
return function(http, port, ctx) {
|
||||||
|
const server = http.createServer(handler)
|
||||||
|
|
||||||
return new Promise(function(res, rej) {
|
return server.listenAsync(port)
|
||||||
server.listen(port, '0.0.0.0', function(err) {
|
}
|
||||||
if (err) return rej(err)
|
|
||||||
res()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
t.beforeEach(function() {
|
||||||
return lowdb({ test: { } }, logger, null).then(function(res) {
|
return createFakeContext()
|
||||||
db = res
|
.then(function(res) {
|
||||||
let provider = new StaticProvider()
|
ctx = res
|
||||||
app = new Application(util, db, provider, 'testapp')
|
let provider = new StaticProvider()
|
||||||
app.config.port = assertPort
|
app = new Application(ctx, provider, 'testapp')
|
||||||
app.registerModule(defaultHandler)
|
app.config.port = assertPort
|
||||||
})
|
app.registerModule(defaultHandler())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.afterEach(function() {
|
||||||
|
return app.http.closeServer()
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should throw if http is not called', async function() {
|
t.test('should throw if http is not called', async function() {
|
||||||
app.registerModule(function(checkDb, checkLog, checkHttp, checkPort) {
|
app.registerModule(function(checkHttp, checkPort, checkCtx) {
|
||||||
assert.strictEqual(checkDb, db)
|
|
||||||
assert.strictEqual(checkLog, db.log)
|
|
||||||
assert.strictEqual(checkHttp, app.http)
|
assert.strictEqual(checkHttp, app.http)
|
||||||
assert.strictEqual(checkPort, assertPort)
|
assert.strictEqual(checkPort, assertPort)
|
||||||
|
assert.strictEqual(checkCtx.db, ctx.db)
|
||||||
|
assert.strictEqual(checkCtx.log, ctx.log)
|
||||||
|
assert.strictEqual(checkCtx.app, app)
|
||||||
})
|
})
|
||||||
|
|
||||||
let err = await assert.isRejected(app.runVersion('static'))
|
let err = await assert.isRejected(app.runVersion('static'))
|
||||||
|
@ -62,10 +63,11 @@ t.timeout(250).describe('#runVersion()', function() {
|
||||||
assert.match(err.message, /static/)
|
assert.match(err.message, /static/)
|
||||||
assert.match(err.message, new RegExp(app.name))
|
assert.match(err.message, new RegExp(app.name))
|
||||||
assert.match(err.message, /call/i)
|
assert.match(err.message, /call/i)
|
||||||
|
assert.strictEqual(ctx.db.data.core.testapp.active, 'static')
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should throw if it timeouts waiting for promise to succeed', async function() {
|
t.test('should throw if it timeouts waiting for promise to succeed', async function() {
|
||||||
app.config.waitUntilFail = 50
|
app.config.startWaitUntilFail = 50
|
||||||
app.registerModule(function() { return new Promise(function() {}) })
|
app.registerModule(function() { return new Promise(function() {}) })
|
||||||
|
|
||||||
let err = await assert.isRejected(app.runVersion('static'))
|
let err = await assert.isRejected(app.runVersion('static'))
|
||||||
|
@ -75,18 +77,203 @@ t.timeout(250).describe('#runVersion()', function() {
|
||||||
assert.match(err.message, /static/)
|
assert.match(err.message, /static/)
|
||||||
assert.match(err.message, /50ms/)
|
assert.match(err.message, /50ms/)
|
||||||
assert.match(err.message, new RegExp(app.name))
|
assert.match(err.message, new RegExp(app.name))
|
||||||
|
assert.strictEqual(ctx.db.data.core.testapp.active, 'static')
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should otherwise succeed if it finished within the time limit', async function() {
|
t.test('should otherwise succeed if it finished within the time limit', async function() {
|
||||||
app.config.waitUntilFail = 250
|
const handler = defaultHandler()
|
||||||
app.registerModule(function(db, log, http, port) {
|
app.config.startWaitUntilFail = 250
|
||||||
|
app.registerModule(function(http, port, ctx) {
|
||||||
return new Promise(function(res) {
|
return new Promise(function(res) {
|
||||||
setTimeout(res, 25)
|
setTimeout(res, 25)
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
return defaultHandler(db, log, http, port)
|
return handler(http, port, ctx)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
await app.runVersion('static')
|
await app.runVersion('static')
|
||||||
|
|
||||||
|
assert.strictEqual(ctx.db.data.core.testapp.active, 'static')
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should fail if run succeeds but heartbeat errors', async function() {
|
||||||
|
let called = 0
|
||||||
|
const handler = function(req, res) {
|
||||||
|
called++
|
||||||
|
res.statusCode = 400
|
||||||
|
res.end(JSON.stringify({ a: 1 }))
|
||||||
|
}
|
||||||
|
app.config.heartbeatAttempts = 3
|
||||||
|
app.registerModule(defaultHandler(handler))
|
||||||
|
|
||||||
|
let err = await assert.isRejected(app.runVersion('static'))
|
||||||
|
assert.match(err.message, /app/i)
|
||||||
|
assert.match(err.message, /failed/i)
|
||||||
|
assert.match(err.message, /static/i)
|
||||||
|
assert.match(err.message, /testapp/i)
|
||||||
|
assert.match(err.message, /400/i)
|
||||||
|
assert.strictEqual(called, 3)
|
||||||
|
assert.strictEqual(ctx.db.data.core.testapp.active, 'static')
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should fail if run succeeds but heartbeat times out', async function() {
|
||||||
|
let called = 0
|
||||||
|
const handler = function(req, res) {
|
||||||
|
called++
|
||||||
|
}
|
||||||
|
app.config.heartbeatAttempts = 2
|
||||||
|
app.config.heartbeatAttemptsWait = 30
|
||||||
|
app.registerModule(defaultHandler(handler))
|
||||||
|
|
||||||
|
let start = performance.now()
|
||||||
|
let err = await assert.isRejected(app.runVersion('static'))
|
||||||
|
let end = performance.now()
|
||||||
|
assert.match(err.message, /app/i)
|
||||||
|
assert.match(err.message, /failed/i)
|
||||||
|
assert.match(err.message, /static/i)
|
||||||
|
assert.match(err.message, /testapp/i)
|
||||||
|
assert.match(err.message, /time/i)
|
||||||
|
assert.match(err.message, /out/i)
|
||||||
|
assert.match(err.message, /30ms/i)
|
||||||
|
assert.ok(end - start > app.config.heartbeatAttempts * app.config.heartbeatAttemptsWait)
|
||||||
|
assert.strictEqual(called, 2)
|
||||||
|
assert.strictEqual(ctx.db.data.core.testapp.active, 'static')
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should call with correct path', async function() {
|
||||||
|
const assertPath = '/test/something'
|
||||||
|
const handler = function(req, res) {
|
||||||
|
if (req.url === assertPath) {
|
||||||
|
res.writeHead(204); res.end(JSON.stringify({ a: 1 }))
|
||||||
|
} else {
|
||||||
|
res.statusCode = 400
|
||||||
|
res.end(JSON.stringify({ a: 1 }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
app.config.heartbeatAttempts = 3
|
||||||
|
app.registerModule(defaultHandler(handler))
|
||||||
|
|
||||||
|
let err = await assert.isRejected(app.runVersion('static'))
|
||||||
|
assert.match(err.message, /app/i)
|
||||||
|
assert.match(err.message, /failed/i)
|
||||||
|
assert.match(err.message, /static/i)
|
||||||
|
assert.match(err.message, /testapp/i)
|
||||||
|
assert.match(err.message, /400/i)
|
||||||
|
|
||||||
|
await app.http.closeServer()
|
||||||
|
app.registerModule(defaultHandler(handler))
|
||||||
|
|
||||||
|
app.config.heartbeatPath = assertPath
|
||||||
|
await app.runVersion('static')
|
||||||
|
|
||||||
|
assert.strictEqual(ctx.db.data.core.testapp.active, 'static')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.skip().describe('#runVersion("version")', function() {
|
||||||
|
const assertConfig = util.getPathFromRoot('./db_test_applicationrun.json')
|
||||||
|
const assertPort = 22345
|
||||||
|
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 })
|
||||||
|
})
|
||||||
|
|
||||||
|
t.beforeEach(function() {
|
||||||
|
return createFakeContext({ }, util, assertConfig)
|
||||||
|
.then(function(res) {
|
||||||
|
ctx = res
|
||||||
|
let provider = new StaticProvider()
|
||||||
|
app = new Application(ctx, provider, 'testnoexisting')
|
||||||
|
app.config.port = assertPort
|
||||||
|
return app.ctx.db.write()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.afterEach(function() {
|
||||||
|
return Promise.all([
|
||||||
|
fs.rm(assertConfig),
|
||||||
|
app.http.closeServer(),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('when version is specified, should check if index.mjs exists', async function() {
|
||||||
|
const assertNotError = new Error('AI DO')
|
||||||
|
const assertTarget = util.getPathFromRoot('./testnoexisting/v100/index.mjs')
|
||||||
|
let stubFsStat = stub()
|
||||||
|
let provider = new StaticProvider()
|
||||||
|
app = new Application(ctx, provider, 'testnoexisting', {
|
||||||
|
fs: { stat: stubFsStat }
|
||||||
|
})
|
||||||
|
app.config.port = assertPort
|
||||||
|
stubFsStat.rejects(assertNotError)
|
||||||
|
|
||||||
|
let err = await assert.isRejected(app.runVersion('v100'))
|
||||||
|
assert.notStrictEqual(err, assertNotError)
|
||||||
|
assert.match(err.message, new RegExp(assertNotError.message))
|
||||||
|
assert.match(err.message, /index\.mjs/i)
|
||||||
|
assert.match(err.message, /testnoexisting/i)
|
||||||
|
assert.match(err.message, /v100/i)
|
||||||
|
assert.match(err.message, /missing/i)
|
||||||
|
assert.strictEqual(stubFsStat.firstCall[0], assertTarget)
|
||||||
|
|
||||||
|
assert.strictEqual(app.ctx.db.data.core.testnoexisting.active, 'v100')
|
||||||
|
let checkDb = await lowdb({}, ctx.log, assertConfig)
|
||||||
|
assert.strictEqual(checkDb.data.core.testnoexisting.active, 'v100')
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('when version is specified and file exists, should attempt to load module', async function() {
|
||||||
|
const assertError = new Error('Parallel Days')
|
||||||
|
await fs.mkdir(util.getPathFromRoot('./testnoexisting/v99'), { recursive: true })
|
||||||
|
await fs.writeFile(util.getPathFromRoot('./testnoexisting/v99/index.mjs'), `throw new Error('${assertError.message}')`)
|
||||||
|
|
||||||
|
let err = await assert.isRejected(app.runVersion('v99'))
|
||||||
|
assert.notStrictEqual(err, assertError)
|
||||||
|
assert.match(err.message, new RegExp(assertError.message))
|
||||||
|
assert.match(err.message, /testnoexisting/i)
|
||||||
|
assert.match(err.message, /v99/i)
|
||||||
|
assert.match(err.message, /index\.mjs/i)
|
||||||
|
|
||||||
|
assert.strictEqual(app.ctx.db.data.core.testnoexisting.active, 'v99')
|
||||||
|
let checkDb = await lowdb({}, ctx.log, assertConfig)
|
||||||
|
assert.strictEqual(checkDb.data.core.testnoexisting.active, 'v99')
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('when version is specified and file exists, should check if it has start', async function() {
|
||||||
|
await fs.mkdir(util.getPathFromRoot('./testnoexisting/v98'), { recursive: true })
|
||||||
|
await fs.writeFile(util.getPathFromRoot('./testnoexisting/v98/index.mjs'), ``)
|
||||||
|
|
||||||
|
let err = await assert.isRejected(app.runVersion('v98'))
|
||||||
|
assert.match(err.message, /testnoexisting/i)
|
||||||
|
assert.match(err.message, /v98/i)
|
||||||
|
assert.match(err.message, /start/i)
|
||||||
|
|
||||||
|
assert.strictEqual(app.ctx.db.data.core.testnoexisting.active, 'v98')
|
||||||
|
let checkDb = await lowdb({}, ctx.log, assertConfig)
|
||||||
|
assert.strictEqual(checkDb.data.core.testnoexisting.active, 'v98')
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('when version is specified and file exists and everything is okay, should work normally', async function() {
|
||||||
|
await fs.mkdir(util.getPathFromRoot('./testnoexisting/v97'), { recursive: true })
|
||||||
|
await fs.copyFile(
|
||||||
|
util.getPathFromRoot('./exampleindex.mjs'),
|
||||||
|
util.getPathFromRoot('./testnoexisting/v97/index.mjs')
|
||||||
|
)
|
||||||
|
|
||||||
|
app.ctx.log.info.reset()
|
||||||
|
app.ctx.log.event.info.reset()
|
||||||
|
|
||||||
|
await app.runVersion('v97')
|
||||||
|
|
||||||
|
assert.ok(app.ctx.log.info.called)
|
||||||
|
assert.ok(app.ctx.log.event.info.called)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { setTimeout, setImmediate } from 'timers/promises'
|
import { setTimeout, setImmediate } from 'timers/promises'
|
||||||
import { Eltro as t, assert, stub } from 'eltro'
|
import { Eltro as t, assert, stub } from 'eltro'
|
||||||
import fs from 'fs/promises'
|
import fs from 'fs/promises'
|
||||||
import lowdb from '../core/db.mjs'
|
|
||||||
import Application from '../core/application.mjs'
|
import Application from '../core/application.mjs'
|
||||||
import Util from '../core/util.mjs'
|
import Util from '../core/util.mjs'
|
||||||
import StaticProvider from '../core/providers/static.mjs'
|
import StaticProvider from '../core/providers/static.mjs'
|
||||||
|
import { createFakeContext } from './helpers.mjs'
|
||||||
|
|
||||||
const util = new Util(import.meta.url)
|
const util = new Util(import.meta.url)
|
||||||
|
|
||||||
|
@ -21,41 +21,46 @@ function createProvider() {
|
||||||
}
|
}
|
||||||
|
|
||||||
t.describe('constructor()', function() {
|
t.describe('constructor()', function() {
|
||||||
let db
|
let ctx
|
||||||
|
|
||||||
t.beforeEach(function() {
|
t.beforeEach(function() {
|
||||||
return lowdb({ test: { } }, logger, null).then(function(res) {
|
return createFakeContext()
|
||||||
db = res
|
.then(function(res) { ctx = res })
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should auto-create application', function() {
|
t.test('should auto-create application', function() {
|
||||||
assert.notOk(db.data.core.test)
|
assert.notOk(ctx.db.data.core.test)
|
||||||
|
|
||||||
new Application(util, db, {}, 'test')
|
new Application(ctx, {}, 'test')
|
||||||
|
|
||||||
assert.ok(db.data.core.test)
|
assert.ok(ctx.db.data.core.test)
|
||||||
assert.ok(db.data.core.test.versions)
|
assert.ok(ctx.db.data.core.test.versions)
|
||||||
assert.strictEqual(db.data.core.test.active, null)
|
assert.strictEqual(ctx.db.data.core.test.active, '')
|
||||||
assert.strictEqual(db.data.core.test.latestInstalled, null)
|
assert.strictEqual(ctx.db.data.core.test.latestInstalled, '')
|
||||||
assert.strictEqual(db.data.core.test.latestVersion, null)
|
assert.strictEqual(ctx.db.data.core.test.latestVersion, '')
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should keep config and other of itself', function() {
|
t.test('should keep config and other of itself', function() {
|
||||||
const assertTest = { a: 1 }
|
const assertTest = { a: 1 }
|
||||||
const assertName = 'test'
|
const assertName = 'test'
|
||||||
db.config = {
|
ctx.db.config = {
|
||||||
test: assertTest,
|
test: assertTest,
|
||||||
app: { b: 2},
|
app: { b: 2},
|
||||||
manage: { c: 3 },
|
manage: { c: 3 },
|
||||||
}
|
}
|
||||||
|
|
||||||
let app = new Application(util, db, {}, assertName)
|
let app = new Application(ctx, {}, assertName)
|
||||||
assert.strictEqual(app.config, assertTest)
|
assert.notStrictEqual(app.config, assertTest)
|
||||||
|
assert.strictEqual(app.config.a, assertTest.a)
|
||||||
assert.strictEqual(app.config.updateEvery, 180)
|
assert.strictEqual(app.config.updateEvery, 180)
|
||||||
assert.strictEqual(app.config.waitUntilFail, 60 * 1000)
|
assert.strictEqual(app.config.startWaitUntilFail, 60 * 1000)
|
||||||
assert.strictEqual(app.db, db)
|
assert.strictEqual(app.config.heartbeatTimeout, 3 * 1000)
|
||||||
assert.strictEqual(app.util, util)
|
assert.strictEqual(app.config.heartbeatAttempts, 5)
|
||||||
|
assert.strictEqual(app.config.heartbeatAttemptsWait, 2 * 1000)
|
||||||
|
assert.strictEqual(app.config.heartbeatPath, '/')
|
||||||
|
assert.strictEqual(app.ctx.db, ctx.db)
|
||||||
|
assert.strictEqual(app.ctx.app, app)
|
||||||
|
assert.strictEqual(app.ctx.util, ctx.util)
|
||||||
assert.strictEqual(app.name, assertName)
|
assert.strictEqual(app.name, assertName)
|
||||||
assert.strictEqual(app.fresh, true)
|
assert.strictEqual(app.fresh, true)
|
||||||
assert.strictEqual(app.running, false)
|
assert.strictEqual(app.running, false)
|
||||||
|
@ -66,38 +71,37 @@ t.describe('constructor()', function() {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should create http instance correctly', function() {
|
t.test('should create http instance correctly', function() {
|
||||||
db.config = {
|
ctx.db.config = {
|
||||||
testapp: { a: 1, https: true },
|
testapp: { a: 1, https: true },
|
||||||
app: { b: 2},
|
app: { b: 2},
|
||||||
manage: { c: 3 },
|
manage: { c: 3 },
|
||||||
}
|
}
|
||||||
|
|
||||||
let app = new Application(util, db, {}, 'testapp')
|
let app = new Application(ctx, {}, 'testapp')
|
||||||
assert.ok(app.http)
|
assert.ok(app.http)
|
||||||
assert.ok(app.http.ishttps)
|
assert.ok(app.http.ishttps)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should keep provider', function() {
|
t.test('should keep provider', function() {
|
||||||
const assertProvider = { a: 1 }
|
const assertProvider = { a: 1 }
|
||||||
let app = new Application(util, db, assertProvider, 'test')
|
let app = new Application(ctx, assertProvider, 'test')
|
||||||
assert.strictEqual(app.provider, assertProvider)
|
assert.strictEqual(app.provider, assertProvider)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.timeout(250).describe('#startAutoupdater()', function() {
|
t.timeout(250).describe('#startAutoupdater()', function() {
|
||||||
let db
|
let ctx
|
||||||
|
|
||||||
t.beforeEach(function() {
|
t.beforeEach(function() {
|
||||||
return lowdb({ test: { }, testapp: { } }, logger, null).then(function(res) {
|
return createFakeContext()
|
||||||
db = res
|
.then(function(res) { ctx = res })
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should do nothing if provider is static', async function() {
|
t.test('should do nothing if provider is static', async function() {
|
||||||
const stubInterval = stub()
|
const stubInterval = stub()
|
||||||
stubInterval.throws(new Error('should not be seen'))
|
stubInterval.throws(new Error('should not be seen'))
|
||||||
let provider = new StaticProvider()
|
let provider = new StaticProvider()
|
||||||
let app = new Application(util, db, provider, 'teststatic', { setInterval: stubInterval })
|
let app = new Application(ctx, provider, 'teststatic', { setInterval: stubInterval })
|
||||||
|
|
||||||
app.startAutoupdater()
|
app.startAutoupdater()
|
||||||
})
|
})
|
||||||
|
@ -108,9 +112,11 @@ t.timeout(250).describe('#startAutoupdater()', function() {
|
||||||
const stubUnref = stub()
|
const stubUnref = stub()
|
||||||
stubInterval.returns({ unref: stubUnref })
|
stubInterval.returns({ unref: stubUnref })
|
||||||
|
|
||||||
db.config.test.updateEvery = assertTimeMinutes
|
ctx.db.config.test = {
|
||||||
|
updateEvery: assertTimeMinutes,
|
||||||
|
}
|
||||||
|
|
||||||
let app = new Application(util, db, {}, 'test', { setInterval: stubInterval })
|
let app = new Application(ctx, {}, 'test', { setInterval: stubInterval })
|
||||||
|
|
||||||
assert.strictEqual(stubInterval.called, false)
|
assert.strictEqual(stubInterval.called, false)
|
||||||
assert.strictEqual(stubUnref.called, false)
|
assert.strictEqual(stubUnref.called, false)
|
||||||
|
@ -127,7 +133,7 @@ t.timeout(250).describe('#startAutoupdater()', function() {
|
||||||
const stubInterval = stub()
|
const stubInterval = stub()
|
||||||
stubInterval.returns({ unref: function() {} })
|
stubInterval.returns({ unref: function() {} })
|
||||||
|
|
||||||
let app = new Application(util, db, {}, 'test', { setInterval: stubInterval })
|
let app = new Application(ctx, {}, 'test', { setInterval: stubInterval })
|
||||||
|
|
||||||
assert.strictEqual(stubInterval.called, false)
|
assert.strictEqual(stubInterval.called, false)
|
||||||
|
|
||||||
|
@ -147,7 +153,7 @@ t.timeout(250).describe('#startAutoupdater()', function() {
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
})
|
})
|
||||||
|
|
||||||
let app = new Application(util, db, {}, 'test', { setInterval: stubInterval })
|
let app = new Application(ctx, {}, 'test', { setInterval: stubInterval })
|
||||||
app.update = stubUpdate
|
app.update = stubUpdate
|
||||||
app.startAutoupdater()
|
app.startAutoupdater()
|
||||||
|
|
||||||
|
@ -156,12 +162,12 @@ t.timeout(250).describe('#startAutoupdater()', function() {
|
||||||
|
|
||||||
stubInterval.firstCall[0]()
|
stubInterval.firstCall[0]()
|
||||||
|
|
||||||
while (db.data.core.test.updater === '') {
|
while (ctx.db.data.core.test.updater === '') {
|
||||||
await setTimeout(10)
|
await setTimeout(10)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.match(db.data.core.test.updater, /auto/i)
|
assert.match(ctx.db.data.core.test.updater, /auto/i)
|
||||||
assert.match(db.data.core.test.updater, /update/i)
|
assert.match(ctx.db.data.core.test.updater, /update/i)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should add any errors to last in db update check on errors when updating', async function() {
|
t.test('should add any errors to last in db update check on errors when updating', async function() {
|
||||||
|
@ -169,28 +175,55 @@ t.timeout(250).describe('#startAutoupdater()', function() {
|
||||||
const assertErrorMessage = 'Ai Do'
|
const assertErrorMessage = 'Ai Do'
|
||||||
stubInterval.returns({ unref: function() {} })
|
stubInterval.returns({ unref: function() {} })
|
||||||
|
|
||||||
let app = new Application(util, db, {}, 'test', { setInterval: stubInterval })
|
let app = new Application(ctx, {}, 'test', { setInterval: stubInterval })
|
||||||
app.update = function() {
|
app.update = function() {
|
||||||
return Promise.reject(new Error(assertErrorMessage))
|
return Promise.reject(new Error(assertErrorMessage))
|
||||||
}
|
}
|
||||||
app.startAutoupdater()
|
app.startAutoupdater()
|
||||||
|
|
||||||
assert.strictEqual(db.data.core.test.updater, '')
|
assert.strictEqual(ctx.db.data.core.test.updater, '')
|
||||||
|
|
||||||
stubInterval.firstCall[0]()
|
stubInterval.firstCall[0]()
|
||||||
|
|
||||||
while (db.data.core.test.updater === '') {
|
while (ctx.db.data.core.test.updater === '') {
|
||||||
await setTimeout(10)
|
await setTimeout(10)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.match(db.data.core.test.updater, /auto/i)
|
assert.match(ctx.db.data.core.test.updater, /auto/i)
|
||||||
assert.match(db.data.core.test.updater, /update/i)
|
assert.match(ctx.db.data.core.test.updater, /update/i)
|
||||||
assert.match(db.data.core.test.updater, new RegExp(assertErrorMessage))
|
assert.match(ctx.db.data.core.test.updater, new RegExp(assertErrorMessage))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.timeout(250).describe('#closeServer()', function() {
|
||||||
|
let app
|
||||||
|
let stubCloseServer
|
||||||
|
|
||||||
|
t.beforeEach(function() {
|
||||||
|
return createFakeContext()
|
||||||
|
.then(function(res) {
|
||||||
|
let provider = createProvider()
|
||||||
|
app = new Application(res, provider, 'testapp')
|
||||||
|
app.http.closeServer = stubCloseServer = stub().resolves()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should call closeServer correctly', async function() {
|
||||||
|
const assertError = new Error('Moonlight Fiesta')
|
||||||
|
stubCloseServer.rejects(assertError)
|
||||||
|
|
||||||
|
let err = await assert.isRejected(app.closeServer())
|
||||||
|
|
||||||
|
assert.strictEqual(err, assertError)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('otherwise should work fine', async function() {
|
||||||
|
await app.closeServer()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.timeout(250).describe('#update()', function() {
|
t.timeout(250).describe('#update()', function() {
|
||||||
let db
|
let ctx
|
||||||
let app
|
let app
|
||||||
let provider
|
let provider
|
||||||
let stubExtract
|
let stubExtract
|
||||||
|
@ -201,30 +234,27 @@ t.timeout(250).describe('#update()', function() {
|
||||||
let stubFsStat
|
let stubFsStat
|
||||||
|
|
||||||
t.beforeEach(function() {
|
t.beforeEach(function() {
|
||||||
util.extractFile = stubExtract = stub()
|
return createFakeContext()
|
||||||
util.runCommand = stubRunCommand = stub()
|
.then(function(res) {
|
||||||
|
ctx = res
|
||||||
|
ctx.util.extractFile = stubExtract = stub().resolves()
|
||||||
|
ctx.util.runCommand = stubRunCommand = stub().resolves()
|
||||||
|
ctx.db.write = stubWrite = stub().resolves()
|
||||||
|
|
||||||
stubExtract.resolves()
|
provider = createProvider()
|
||||||
stubRunCommand.resolves()
|
app = new Application(ctx, provider, 'testapp', {
|
||||||
|
fs: {
|
||||||
return lowdb({ test: { } }, logger, null).then(function(res) {
|
mkdir: stubFsMkdir = stub(),
|
||||||
db = res
|
rm: stubFsRm = stub(),
|
||||||
db.write = stubWrite = stub()
|
stat: stubFsStat = stub(),
|
||||||
stubWrite.resolves()
|
},
|
||||||
provider = createProvider()
|
})
|
||||||
app = new Application(util, db, provider, 'testapp', {
|
stubFsMkdir.resolves()
|
||||||
fs: {
|
stubFsRm.resolves()
|
||||||
mkdir: stubFsMkdir = stub(),
|
stubFsStat.resolves({})
|
||||||
rm: stubFsRm = stub(),
|
provider.downloadVersion.resolves()
|
||||||
stat: stubFsStat = stub(),
|
provider.getLatestVersion.resolves({ version: '123456789', link: 'httplinkhere', filename: 'test.7z' })
|
||||||
},
|
|
||||||
})
|
})
|
||||||
stubFsMkdir.resolves()
|
|
||||||
stubFsRm.resolves()
|
|
||||||
stubFsStat.resolves({})
|
|
||||||
provider.downloadVersion.resolves()
|
|
||||||
provider.getLatestVersion.resolves({ version: '123456789', link: 'httplinkhere', filename: 'test.7z' })
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.afterEach(function() {
|
t.afterEach(function() {
|
||||||
|
@ -233,33 +263,35 @@ t.timeout(250).describe('#update()', function() {
|
||||||
|
|
||||||
t.test('should do nothing if provider is static', async function() {
|
t.test('should do nothing if provider is static', async function() {
|
||||||
provider = new StaticProvider()
|
provider = new StaticProvider()
|
||||||
app = new Application(util, db, provider, 'teststatic')
|
app = new Application(ctx, provider, 'teststatic')
|
||||||
|
|
||||||
|
stubWrite.reset()
|
||||||
|
|
||||||
await app.update()
|
await app.update()
|
||||||
|
|
||||||
assert.match(db.data.core.teststatic.updater, /static/i)
|
assert.match(ctx.db.data.core.teststatic.updater, /static/i)
|
||||||
assert.match(db.data.core.teststatic.updater, /nothing/i)
|
assert.match(ctx.db.data.core.teststatic.updater, /nothing/i)
|
||||||
let old = db.data.core.teststatic.updater
|
let old = ctx.db.data.core.teststatic.updater
|
||||||
assert.ok(stubWrite.called)
|
assert.ok(stubWrite.called)
|
||||||
assert.strictEqual(stubWrite.callCount, 1)
|
assert.strictEqual(stubWrite.callCount, 1)
|
||||||
|
|
||||||
await app.update()
|
await app.update()
|
||||||
assert.strictEqual(db.data.core.teststatic.updater, old)
|
assert.strictEqual(ctx.db.data.core.teststatic.updater, old)
|
||||||
assert.strictEqual(stubWrite.callCount, 1)
|
assert.strictEqual(stubWrite.callCount, 1)
|
||||||
|
|
||||||
db.data.core.teststatic.updater = 'asdf'
|
ctx.db.data.core.teststatic.updater = 'asdf'
|
||||||
|
|
||||||
await app.update()
|
await app.update()
|
||||||
assert.strictEqual(db.data.core.teststatic.updater, old)
|
assert.strictEqual(ctx.db.data.core.teststatic.updater, old)
|
||||||
assert.strictEqual(stubWrite.callCount, 2)
|
assert.strictEqual(stubWrite.callCount, 2)
|
||||||
|
|
||||||
await app.update()
|
await app.update()
|
||||||
assert.strictEqual(db.data.core.teststatic.updater, old)
|
assert.strictEqual(ctx.db.data.core.teststatic.updater, old)
|
||||||
assert.strictEqual(stubWrite.callCount, 2)
|
assert.strictEqual(stubWrite.callCount, 2)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('multiple calls should be safe', async function() {
|
t.test('multiple calls should be safe', async function() {
|
||||||
db.data.core.testapp.updater = ''
|
ctx.db.data.core.testapp.updater = ''
|
||||||
|
|
||||||
provider.getLatestVersion.returnWith(function() {
|
provider.getLatestVersion.returnWith(function() {
|
||||||
return new Promise(function() {})
|
return new Promise(function() {})
|
||||||
|
@ -282,7 +314,7 @@ t.timeout(250).describe('#update()', function() {
|
||||||
t.test('should check for latest version', async function() {
|
t.test('should check for latest version', async function() {
|
||||||
const assertError = new Error('Ore wa Subete wo Shihaisuru')
|
const assertError = new Error('Ore wa Subete wo Shihaisuru')
|
||||||
provider.getLatestVersion.rejects(assertError)
|
provider.getLatestVersion.rejects(assertError)
|
||||||
db.data.core.testapp.updater = ''
|
ctx.db.data.core.testapp.updater = ''
|
||||||
|
|
||||||
let err = await assert.isRejected(app.update())
|
let err = await assert.isRejected(app.update())
|
||||||
|
|
||||||
|
@ -291,10 +323,10 @@ t.timeout(250).describe('#update()', function() {
|
||||||
|
|
||||||
assert.ok(stubWrite.called)
|
assert.ok(stubWrite.called)
|
||||||
assert.ok(stubWrite.callCount >= 1)
|
assert.ok(stubWrite.callCount >= 1)
|
||||||
assert.match(db.data.core.testapp.updater, /check/i)
|
assert.match(ctx.db.data.core.testapp.updater, /check/i)
|
||||||
assert.match(db.data.core.testapp.updater, /version/i)
|
assert.match(ctx.db.data.core.testapp.updater, /version/i)
|
||||||
assert.match(db.data.core.testapp.updater, new RegExp(new Date().toISOString().split('T')[0]))
|
assert.match(ctx.db.data.core.testapp.updater, new RegExp(new Date().toISOString().split('T')[0]))
|
||||||
assert.match(db.data.core.testapp.updater, new RegExp(assertError.message))
|
assert.match(ctx.db.data.core.testapp.updater, new RegExp(assertError.message))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should call provider download latest correctly if new 7zip version', async function() {
|
t.test('should call provider download latest correctly if new 7zip version', async function() {
|
||||||
|
@ -302,27 +334,27 @@ t.timeout(250).describe('#update()', function() {
|
||||||
const assertLink = 'All of you'
|
const assertLink = 'All of you'
|
||||||
const assertVersion = { version: '123456789', link: assertLink, filename: 'test.7z' }
|
const assertVersion = { version: '123456789', link: assertLink, filename: 'test.7z' }
|
||||||
const assertTarget = util.getPathFromRoot('./testapp/123456789/file.7z')
|
const assertTarget = util.getPathFromRoot('./testapp/123456789/file.7z')
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 0)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 0)
|
||||||
|
|
||||||
provider.getLatestVersion.resolves(assertVersion)
|
provider.getLatestVersion.resolves(assertVersion)
|
||||||
provider.downloadVersion.rejects(assertError)
|
provider.downloadVersion.rejects(assertError)
|
||||||
db.data.core.testapp.updater = ''
|
ctx.db.data.core.testapp.updater = ''
|
||||||
|
|
||||||
let err = await assert.isRejected(app.update())
|
let err = await assert.isRejected(app.update())
|
||||||
|
|
||||||
assert.strictEqual(app.updating, false)
|
assert.strictEqual(app.updating, false)
|
||||||
assert.strictEqual(err, assertError)
|
assert.strictEqual(err, assertError)
|
||||||
assert.match(db.data.core.testapp.updater, /found/i)
|
assert.match(ctx.db.data.core.testapp.updater, /found/i)
|
||||||
assert.match(db.data.core.testapp.updater, new RegExp(assertVersion.version))
|
assert.match(ctx.db.data.core.testapp.updater, new RegExp(assertVersion.version))
|
||||||
assert.match(db.data.core.testapp.updater, /downloading/i)
|
assert.match(ctx.db.data.core.testapp.updater, /downloading/i)
|
||||||
assert.match(db.data.core.testapp.updater, new RegExp(assertLink))
|
assert.match(ctx.db.data.core.testapp.updater, new RegExp(assertLink))
|
||||||
assert.match(db.data.core.testapp.updater, new RegExp(assertTarget.replace(/\\/g, '\\\\')))
|
assert.match(ctx.db.data.core.testapp.updater, new RegExp(assertTarget.replace(/\\/g, '\\\\')))
|
||||||
assert.strictEqual(provider.downloadVersion.firstCall[0], assertVersion)
|
assert.strictEqual(provider.downloadVersion.firstCall[0], assertVersion)
|
||||||
assert.strictEqual(provider.downloadVersion.firstCall[1], assertTarget)
|
assert.strictEqual(provider.downloadVersion.firstCall[1], assertTarget)
|
||||||
assert.match(db.data.core.testapp.updater, new RegExp(assertError.message))
|
assert.match(ctx.db.data.core.testapp.updater, new RegExp(assertError.message))
|
||||||
|
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 1)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 1)
|
||||||
assert.strictEqual(db.data.core.testapp.versions[0], assertVersion)
|
assert.strictEqual(ctx.db.data.core.testapp.versions[0], assertVersion)
|
||||||
assert.ok(assertVersion.log)
|
assert.ok(assertVersion.log)
|
||||||
assert.match(assertVersion.log, /\. \n/)
|
assert.match(assertVersion.log, /\. \n/)
|
||||||
assert.match(assertVersion.log, new RegExp(assertError.message))
|
assert.match(assertVersion.log, new RegExp(assertError.message))
|
||||||
|
@ -341,8 +373,8 @@ t.timeout(250).describe('#update()', function() {
|
||||||
|
|
||||||
assert.strictEqual(app.updating, false)
|
assert.strictEqual(app.updating, false)
|
||||||
assert.strictEqual(err, assertError)
|
assert.strictEqual(err, assertError)
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 1)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 1)
|
||||||
assert.strictEqual(db.data.core.testapp.versions[0], assertVersion)
|
assert.strictEqual(ctx.db.data.core.testapp.versions[0], assertVersion)
|
||||||
assert.strictEqual(assertVersion.failtodownload, 2)
|
assert.strictEqual(assertVersion.failtodownload, 2)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -351,27 +383,27 @@ t.timeout(250).describe('#update()', function() {
|
||||||
const assertLink = 'All of you'
|
const assertLink = 'All of you'
|
||||||
const assertVersion = { version: '123456789', link: assertLink, filename: 'test.7z' }
|
const assertVersion = { version: '123456789', link: assertLink, filename: 'test.7z' }
|
||||||
const assertTarget = util.getPathFromRoot('./testapp/123456789/file.7z')
|
const assertTarget = util.getPathFromRoot('./testapp/123456789/file.7z')
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 0)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 0)
|
||||||
|
|
||||||
provider.getLatestVersion.resolves(assertVersion)
|
provider.getLatestVersion.resolves(assertVersion)
|
||||||
provider.downloadVersion.rejects(assertError)
|
provider.downloadVersion.rejects(assertError)
|
||||||
db.data.core.testapp.updater = ''
|
ctx.db.data.core.testapp.updater = ''
|
||||||
|
|
||||||
let err = await assert.isRejected(app.update())
|
let err = await assert.isRejected(app.update())
|
||||||
|
|
||||||
assert.strictEqual(app.updating, false)
|
assert.strictEqual(app.updating, false)
|
||||||
assert.strictEqual(err, assertError)
|
assert.strictEqual(err, assertError)
|
||||||
assert.match(db.data.core.testapp.updater, /found/i)
|
assert.match(ctx.db.data.core.testapp.updater, /found/i)
|
||||||
assert.match(db.data.core.testapp.updater, new RegExp(assertVersion.version))
|
assert.match(ctx.db.data.core.testapp.updater, new RegExp(assertVersion.version))
|
||||||
assert.match(db.data.core.testapp.updater, /downloading/i)
|
assert.match(ctx.db.data.core.testapp.updater, /downloading/i)
|
||||||
assert.match(db.data.core.testapp.updater, new RegExp(assertLink))
|
assert.match(ctx.db.data.core.testapp.updater, new RegExp(assertLink))
|
||||||
assert.match(db.data.core.testapp.updater, new RegExp(assertTarget.replace(/\\/g, '\\\\')))
|
assert.match(ctx.db.data.core.testapp.updater, new RegExp(assertTarget.replace(/\\/g, '\\\\')))
|
||||||
assert.strictEqual(provider.downloadVersion.firstCall[0], assertVersion)
|
assert.strictEqual(provider.downloadVersion.firstCall[0], assertVersion)
|
||||||
assert.strictEqual(provider.downloadVersion.firstCall[1], assertTarget)
|
assert.strictEqual(provider.downloadVersion.firstCall[1], assertTarget)
|
||||||
assert.match(db.data.core.testapp.updater, new RegExp(assertError.message))
|
assert.match(ctx.db.data.core.testapp.updater, new RegExp(assertError.message))
|
||||||
|
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 1)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 1)
|
||||||
assert.strictEqual(db.data.core.testapp.versions[0], assertVersion)
|
assert.strictEqual(ctx.db.data.core.testapp.versions[0], assertVersion)
|
||||||
assert.ok(assertVersion.log)
|
assert.ok(assertVersion.log)
|
||||||
assert.match(assertVersion.log, /\. \n/)
|
assert.match(assertVersion.log, /\. \n/)
|
||||||
assert.match(assertVersion.log, new RegExp(assertError.message))
|
assert.match(assertVersion.log, new RegExp(assertError.message))
|
||||||
|
@ -389,8 +421,8 @@ t.timeout(250).describe('#update()', function() {
|
||||||
|
|
||||||
assert.strictEqual(app.updating, false)
|
assert.strictEqual(app.updating, false)
|
||||||
assert.strictEqual(err, assertError)
|
assert.strictEqual(err, assertError)
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 1)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 1)
|
||||||
assert.strictEqual(db.data.core.testapp.versions[0], assertVersion)
|
assert.strictEqual(ctx.db.data.core.testapp.versions[0], assertVersion)
|
||||||
assert.strictEqual(assertVersion.failtodownload, 2)
|
assert.strictEqual(assertVersion.failtodownload, 2)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -404,7 +436,7 @@ t.timeout(250).describe('#update()', function() {
|
||||||
stream(assertExtractText)
|
stream(assertExtractText)
|
||||||
return Promise.reject(assertError)
|
return Promise.reject(assertError)
|
||||||
})
|
})
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 0)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 0)
|
||||||
|
|
||||||
let err = await assert.isRejected(app.update())
|
let err = await assert.isRejected(app.update())
|
||||||
|
|
||||||
|
@ -413,8 +445,8 @@ t.timeout(250).describe('#update()', function() {
|
||||||
assert.strictEqual(app.updating, false)
|
assert.strictEqual(app.updating, false)
|
||||||
assert.strictEqual(stubExtract.firstCall[0], assertTarget)
|
assert.strictEqual(stubExtract.firstCall[0], assertTarget)
|
||||||
|
|
||||||
assert.match(db.data.core.testapp.updater, new RegExp('extracting[^.]+file\.7z', 'i'))
|
assert.match(ctx.db.data.core.testapp.updater, new RegExp('extracting[^.]+file\.7z', 'i'))
|
||||||
assert.match(db.data.core.testapp.updater, new RegExp(assertError.message))
|
assert.match(ctx.db.data.core.testapp.updater, new RegExp(assertError.message))
|
||||||
|
|
||||||
assert.ok(stubFsRm.called)
|
assert.ok(stubFsRm.called)
|
||||||
assert.strictEqual(stubFsRm.firstCall[0], assertFolder)
|
assert.strictEqual(stubFsRm.firstCall[0], assertFolder)
|
||||||
|
@ -423,8 +455,8 @@ t.timeout(250).describe('#update()', function() {
|
||||||
|
|
||||||
assert.ok(stubWrite.called)
|
assert.ok(stubWrite.called)
|
||||||
assert.ok(stubWrite.callCount >= 3)
|
assert.ok(stubWrite.callCount >= 3)
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 1)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 1)
|
||||||
let version = db.data.core.testapp.versions[0]
|
let version = ctx.db.data.core.testapp.versions[0]
|
||||||
assert.ok(version.log)
|
assert.ok(version.log)
|
||||||
assert.match(version.log, /\. \n/)
|
assert.match(version.log, /\. \n/)
|
||||||
assert.match(version.log, new RegExp('extracting[^.]+file\.7z', 'i'))
|
assert.match(version.log, new RegExp('extracting[^.]+file\.7z', 'i'))
|
||||||
|
@ -439,15 +471,15 @@ t.timeout(250).describe('#update()', function() {
|
||||||
|
|
||||||
assert.strictEqual(app.updating, false)
|
assert.strictEqual(app.updating, false)
|
||||||
assert.strictEqual(err, assertError)
|
assert.strictEqual(err, assertError)
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 1)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 1)
|
||||||
assert.strictEqual(db.data.core.testapp.versions[0], version)
|
assert.strictEqual(ctx.db.data.core.testapp.versions[0], version)
|
||||||
assert.strictEqual(version.failtodownload, 2)
|
assert.strictEqual(version.failtodownload, 2)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should call fs remove the archieve file', async function() {
|
t.test('should call fs remove the archieve file', async function() {
|
||||||
const assertError = new Error('Tiny Kizuna')
|
const assertError = new Error('Tiny Kizuna')
|
||||||
const assertTarget = util.getPathFromRoot('./testapp/123456789/file.7z')
|
const assertTarget = util.getPathFromRoot('./testapp/123456789/file.7z')
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 0)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 0)
|
||||||
stubFsRm.rejects(assertError)
|
stubFsRm.rejects(assertError)
|
||||||
|
|
||||||
await app.update()
|
await app.update()
|
||||||
|
@ -464,7 +496,7 @@ t.timeout(250).describe('#update()', function() {
|
||||||
const assertTarget = util.getPathFromRoot('./testapp/123456789/index.mjs')
|
const assertTarget = util.getPathFromRoot('./testapp/123456789/index.mjs')
|
||||||
stubRunCommand.rejects(new Error('should not be seen'))
|
stubRunCommand.rejects(new Error('should not be seen'))
|
||||||
stubFsStat.rejects(assertError)
|
stubFsStat.rejects(assertError)
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 0)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 0)
|
||||||
|
|
||||||
let err = await assert.isRejected(app.update())
|
let err = await assert.isRejected(app.update())
|
||||||
|
|
||||||
|
@ -472,11 +504,11 @@ t.timeout(250).describe('#update()', function() {
|
||||||
assert.ok(stubExtract.called)
|
assert.ok(stubExtract.called)
|
||||||
assert.strictEqual(err, assertError)
|
assert.strictEqual(err, assertError)
|
||||||
assert.strictEqual(stubFsStat.firstCall[0], assertTarget)
|
assert.strictEqual(stubFsStat.firstCall[0], assertTarget)
|
||||||
assert.match(db.data.core.testapp.updater, /index\.mjs/i)
|
assert.match(ctx.db.data.core.testapp.updater, /index\.mjs/i)
|
||||||
assert.match(db.data.core.testapp.updater, /missing/i)
|
assert.match(ctx.db.data.core.testapp.updater, /missing/i)
|
||||||
|
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 1)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 1)
|
||||||
let version = db.data.core.testapp.versions[0]
|
let version = ctx.db.data.core.testapp.versions[0]
|
||||||
assert.ok(version.log)
|
assert.ok(version.log)
|
||||||
assert.match(version.log, /index\.mjs/i)
|
assert.match(version.log, /index\.mjs/i)
|
||||||
assert.match(version.log, /missing/i)
|
assert.match(version.log, /missing/i)
|
||||||
|
@ -489,8 +521,8 @@ t.timeout(250).describe('#update()', function() {
|
||||||
|
|
||||||
assert.strictEqual(app.updating, false)
|
assert.strictEqual(app.updating, false)
|
||||||
assert.strictEqual(err, assertError)
|
assert.strictEqual(err, assertError)
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 1)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 1)
|
||||||
assert.strictEqual(db.data.core.testapp.versions[0], version)
|
assert.strictEqual(ctx.db.data.core.testapp.versions[0], version)
|
||||||
assert.strictEqual(version.failtodownload, 2)
|
assert.strictEqual(version.failtodownload, 2)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -504,7 +536,7 @@ t.timeout(250).describe('#update()', function() {
|
||||||
}
|
}
|
||||||
return Promise.resolve({})
|
return Promise.resolve({})
|
||||||
})
|
})
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 0)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 0)
|
||||||
|
|
||||||
await app.update()
|
await app.update()
|
||||||
|
|
||||||
|
@ -514,16 +546,16 @@ t.timeout(250).describe('#update()', function() {
|
||||||
assert.strictEqual(stubFsStat.secondCall[0], assertTarget)
|
assert.strictEqual(stubFsStat.secondCall[0], assertTarget)
|
||||||
assert.ok(stubExtract.called)
|
assert.ok(stubExtract.called)
|
||||||
assert.notOk(stubRunCommand.called)
|
assert.notOk(stubRunCommand.called)
|
||||||
assert.match(db.data.core.testapp.updater, /package\.json/i)
|
assert.match(ctx.db.data.core.testapp.updater, /package\.json/i)
|
||||||
assert.match(db.data.core.testapp.updater, /contain/i)
|
assert.match(ctx.db.data.core.testapp.updater, /contain/i)
|
||||||
|
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 1)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 1)
|
||||||
let version = db.data.core.testapp.versions[0]
|
let version = ctx.db.data.core.testapp.versions[0]
|
||||||
assert.ok(version.log)
|
assert.ok(version.log)
|
||||||
assert.match(version.log, /package\.json/i)
|
assert.match(version.log, /package\.json/i)
|
||||||
assert.match(version.log, /contain/i)
|
assert.match(version.log, /contain/i)
|
||||||
assert.ok(version.log.endsWith('\n'))
|
assert.ok(version.log.endsWith('\n'))
|
||||||
assert.ok(db.data.core.testapp.latestInstalled)
|
assert.ok(ctx.db.data.core.testapp.latestInstalled)
|
||||||
assert.match(version.log, /finished/i)
|
assert.match(version.log, /finished/i)
|
||||||
assert.match(version.log, /updating/i)
|
assert.match(version.log, /updating/i)
|
||||||
|
|
||||||
|
@ -533,10 +565,10 @@ t.timeout(250).describe('#update()', function() {
|
||||||
|
|
||||||
await app.update()
|
await app.update()
|
||||||
|
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 1)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 1)
|
||||||
assert.notOk(provider.downloadVersion.called)
|
assert.notOk(provider.downloadVersion.called)
|
||||||
assert.match(db.data.core.testapp.updater, /already/i)
|
assert.match(ctx.db.data.core.testapp.updater, /already/i)
|
||||||
assert.match(db.data.core.testapp.updater, /nothing/i)
|
assert.match(ctx.db.data.core.testapp.updater, /nothing/i)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should otherwise call npm install correctly', async function() {
|
t.test('should otherwise call npm install correctly', async function() {
|
||||||
|
@ -547,7 +579,7 @@ t.timeout(250).describe('#update()', function() {
|
||||||
const assertTarget = util.getPathFromRoot('./testapp/123456789')
|
const assertTarget = util.getPathFromRoot('./testapp/123456789')
|
||||||
const assertTargetCheck = util.getPathFromRoot('./testapp/123456789/')
|
const assertTargetCheck = util.getPathFromRoot('./testapp/123456789/')
|
||||||
provider.getLatestVersion.resolves(assertVersion)
|
provider.getLatestVersion.resolves(assertVersion)
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 0)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 0)
|
||||||
|
|
||||||
stubExtract.returnWith(function(target, stream) {
|
stubExtract.returnWith(function(target, stream) {
|
||||||
stream(assertExtractText)
|
stream(assertExtractText)
|
||||||
|
@ -578,10 +610,10 @@ t.timeout(250).describe('#update()', function() {
|
||||||
|
|
||||||
assert.ok(stubWrite.called)
|
assert.ok(stubWrite.called)
|
||||||
assert.ok(stubWrite.callCount >= 4)
|
assert.ok(stubWrite.callCount >= 4)
|
||||||
assert.match(db.data.core.testapp.updater, /npm/i)
|
assert.match(ctx.db.data.core.testapp.updater, /npm/i)
|
||||||
assert.match(db.data.core.testapp.updater, /install/i)
|
assert.match(ctx.db.data.core.testapp.updater, /install/i)
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 1)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 1)
|
||||||
assert.strictEqual(db.data.core.testapp.versions[0], assertVersion)
|
assert.strictEqual(ctx.db.data.core.testapp.versions[0], assertVersion)
|
||||||
assert.ok(assertVersion.log)
|
assert.ok(assertVersion.log)
|
||||||
assert.match(assertVersion.log, /\. \n/)
|
assert.match(assertVersion.log, /\. \n/)
|
||||||
assert.match(assertVersion.log, new RegExp(assertExtractText))
|
assert.match(assertVersion.log, new RegExp(assertExtractText))
|
||||||
|
@ -598,23 +630,23 @@ t.timeout(250).describe('#update()', function() {
|
||||||
|
|
||||||
assert.strictEqual(app.updating, false)
|
assert.strictEqual(app.updating, false)
|
||||||
assert.strictEqual(err, assertError)
|
assert.strictEqual(err, assertError)
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 1)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 1)
|
||||||
assert.strictEqual(db.data.core.testapp.versions[0], assertVersion)
|
assert.strictEqual(ctx.db.data.core.testapp.versions[0], assertVersion)
|
||||||
assert.strictEqual(assertVersion.failtoinstall, 2)
|
assert.strictEqual(assertVersion.failtoinstall, 2)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should update latest installed correctly', async function() {
|
t.test('should update latest installed correctly', async function() {
|
||||||
const assertVersion = { version: '123456789', link: 'httplinkhere', filename: 'test.7z' }
|
const assertVersion = { version: '123456789', link: 'httplinkhere', filename: 'test.7z' }
|
||||||
provider.getLatestVersion.resolves(assertVersion)
|
provider.getLatestVersion.resolves(assertVersion)
|
||||||
assert.notStrictEqual(db.data.core.testapp.latestInstalled, assertVersion.version)
|
assert.notStrictEqual(ctx.db.data.core.testapp.latestInstalled, assertVersion.version)
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 0)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 0)
|
||||||
|
|
||||||
await app.update()
|
await app.update()
|
||||||
|
|
||||||
assert.strictEqual(app.updating, false)
|
assert.strictEqual(app.updating, false)
|
||||||
assert.strictEqual(db.data.core.testapp.latestInstalled, assertVersion.version)
|
assert.strictEqual(ctx.db.data.core.testapp.latestInstalled, assertVersion.version)
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 1)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 1)
|
||||||
assert.strictEqual(db.data.core.testapp.versions[0], assertVersion)
|
assert.strictEqual(ctx.db.data.core.testapp.versions[0], assertVersion)
|
||||||
assert.ok(assertVersion.log)
|
assert.ok(assertVersion.log)
|
||||||
assert.ok(stubWrite.callCount >= 4)
|
assert.ok(stubWrite.callCount >= 4)
|
||||||
assert.strictEqual(assertVersion.installed, true)
|
assert.strictEqual(assertVersion.installed, true)
|
||||||
|
@ -635,18 +667,18 @@ t.timeout(250).describe('#update()', function() {
|
||||||
const assertVersion = { version: '123456789', link: 'httplinkhere', filename: 'test.7z', log: oldLog, stable: assertStable }
|
const assertVersion = { version: '123456789', link: 'httplinkhere', filename: 'test.7z', log: oldLog, stable: assertStable }
|
||||||
|
|
||||||
assertVersion.id = assertVersion.version
|
assertVersion.id = assertVersion.version
|
||||||
db.upsert(db.data.core.testapp.versions, assertVersion)
|
ctx.db.upsert(ctx.db.data.core.testapp.versions, assertVersion)
|
||||||
|
|
||||||
provider.getLatestVersion.resolves({ version: assertVersion.version, link: assertNewLink, filename: assertNewFilename })
|
provider.getLatestVersion.resolves({ version: assertVersion.version, link: assertNewLink, filename: assertNewFilename })
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 1)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 1)
|
||||||
|
|
||||||
await app.update()
|
await app.update()
|
||||||
|
|
||||||
assert.ok(assertVersion.log)
|
assert.ok(assertVersion.log)
|
||||||
assert.ok(stubWrite.callCount >= 4)
|
assert.ok(stubWrite.callCount >= 4)
|
||||||
assert.strictEqual(app.updating, false)
|
assert.strictEqual(app.updating, false)
|
||||||
assert.strictEqual(db.data.core.testapp.versions.length, 1)
|
assert.strictEqual(ctx.db.data.core.testapp.versions.length, 1)
|
||||||
assert.strictEqual(db.data.core.testapp.versions[0], assertVersion)
|
assert.strictEqual(ctx.db.data.core.testapp.versions[0], assertVersion)
|
||||||
assert.strictEqual(assertVersion.stable, assertStable)
|
assert.strictEqual(assertVersion.stable, assertStable)
|
||||||
assert.ok(assertVersion.log)
|
assert.ok(assertVersion.log)
|
||||||
assert.ok(assertVersion.log.startsWith(oldLog))
|
assert.ok(assertVersion.log.startsWith(oldLog))
|
||||||
|
@ -664,16 +696,16 @@ t.timeout(250).describe('#update()', function() {
|
||||||
const assertVersion = { version: '999.888.777.666', filename: 'test.7z' }
|
const assertVersion = { version: '999.888.777.666', filename: 'test.7z' }
|
||||||
provider.getLatestVersion.resolves(assertVersion)
|
provider.getLatestVersion.resolves(assertVersion)
|
||||||
provider.downloadVersion.rejects(assertError)
|
provider.downloadVersion.rejects(assertError)
|
||||||
db.data.core.testapp.updater = ''
|
ctx.db.data.core.testapp.updater = ''
|
||||||
db.data.core.testapp.latestInstalled = assertVersion.version
|
ctx.db.data.core.testapp.latestInstalled = assertVersion.version
|
||||||
|
|
||||||
await app.update()
|
await app.update()
|
||||||
|
|
||||||
assert.ok(stubWrite.callCount >= 1)
|
assert.ok(stubWrite.callCount >= 1)
|
||||||
assert.strictEqual(app.updating, false)
|
assert.strictEqual(app.updating, false)
|
||||||
assert.notOk(provider.downloadVersion.called)
|
assert.notOk(provider.downloadVersion.called)
|
||||||
assert.match(db.data.core.testapp.updater, /already/i)
|
assert.match(ctx.db.data.core.testapp.updater, /already/i)
|
||||||
assert.match(db.data.core.testapp.updater, /nothing/i)
|
assert.match(ctx.db.data.core.testapp.updater, /nothing/i)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should do nothing if installed version is found', async function() {
|
t.test('should do nothing if installed version is found', async function() {
|
||||||
|
@ -681,20 +713,20 @@ t.timeout(250).describe('#update()', function() {
|
||||||
const assertVersion = { version: '999.888.777.666', filename: 'test.7z' }
|
const assertVersion = { version: '999.888.777.666', filename: 'test.7z' }
|
||||||
provider.getLatestVersion.resolves(assertVersion)
|
provider.getLatestVersion.resolves(assertVersion)
|
||||||
provider.downloadVersion.rejects(assertError)
|
provider.downloadVersion.rejects(assertError)
|
||||||
db.data.core.testapp.updater = ''
|
ctx.db.data.core.testapp.updater = ''
|
||||||
|
|
||||||
db.upsert(db.data.core.testapp.versions, { id: '111.111.111.111', installed: true })
|
ctx.db.upsert(ctx.db.data.core.testapp.versions, { id: '111.111.111.111', installed: true })
|
||||||
db.upsert(db.data.core.testapp.versions, { id: '222.222.222.222', installed: true })
|
ctx.db.upsert(ctx.db.data.core.testapp.versions, { id: '222.222.222.222', installed: true })
|
||||||
db.upsert(db.data.core.testapp.versions, { id: '999.888.777.666', installed: true })
|
ctx.db.upsert(ctx.db.data.core.testapp.versions, { id: '999.888.777.666', installed: true })
|
||||||
db.upsert(db.data.core.testapp.versions, { id: '333.333.333.333', installed: true })
|
ctx.db.upsert(ctx.db.data.core.testapp.versions, { id: '333.333.333.333', installed: true })
|
||||||
|
|
||||||
await app.update()
|
await app.update()
|
||||||
|
|
||||||
assert.ok(stubWrite.callCount >= 1)
|
assert.ok(stubWrite.callCount >= 1)
|
||||||
assert.strictEqual(app.updating, false)
|
assert.strictEqual(app.updating, false)
|
||||||
assert.notOk(provider.downloadVersion.called)
|
assert.notOk(provider.downloadVersion.called)
|
||||||
assert.match(db.data.core.testapp.updater, /already/i)
|
assert.match(ctx.db.data.core.testapp.updater, /already/i)
|
||||||
assert.match(db.data.core.testapp.updater, /nothing/i)
|
assert.match(ctx.db.data.core.testapp.updater, /nothing/i)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should do nothing it exists and failtodownload is higher than 3', async function() {
|
t.test('should do nothing it exists and failtodownload is higher than 3', async function() {
|
||||||
|
@ -702,17 +734,17 @@ t.timeout(250).describe('#update()', function() {
|
||||||
const assertVersion = { version: '999.888.777.666', filename: 'test.7z' }
|
const assertVersion = { version: '999.888.777.666', filename: 'test.7z' }
|
||||||
provider.getLatestVersion.resolves(assertVersion)
|
provider.getLatestVersion.resolves(assertVersion)
|
||||||
provider.downloadVersion.rejects(assertError)
|
provider.downloadVersion.rejects(assertError)
|
||||||
db.data.core.testapp.updater = ''
|
ctx.db.data.core.testapp.updater = ''
|
||||||
db.upsert(db.data.core.testapp.versions, { id: '999.888.777.666', version: '999.888.777.666', link: 'httplinkhere', filename: 'test.7z', failtodownload: 4 })
|
ctx.db.upsert(ctx.db.data.core.testapp.versions, { id: '999.888.777.666', version: '999.888.777.666', link: 'httplinkhere', filename: 'test.7z', failtodownload: 4 })
|
||||||
|
|
||||||
await app.update()
|
await app.update()
|
||||||
|
|
||||||
assert.ok(stubWrite.callCount >= 1)
|
assert.ok(stubWrite.callCount >= 1)
|
||||||
assert.strictEqual(app.updating, false)
|
assert.strictEqual(app.updating, false)
|
||||||
assert.notOk(provider.downloadVersion.called)
|
assert.notOk(provider.downloadVersion.called)
|
||||||
assert.match(db.data.core.testapp.updater, /many/i)
|
assert.match(ctx.db.data.core.testapp.updater, /many/i)
|
||||||
assert.match(db.data.core.testapp.updater, /fail/i)
|
assert.match(ctx.db.data.core.testapp.updater, /fail/i)
|
||||||
assert.match(db.data.core.testapp.updater, /skip/i)
|
assert.match(ctx.db.data.core.testapp.updater, /skip/i)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should do nothing it exists and failtoinstall is higher than 3', async function() {
|
t.test('should do nothing it exists and failtoinstall is higher than 3', async function() {
|
||||||
|
@ -720,31 +752,32 @@ t.timeout(250).describe('#update()', function() {
|
||||||
const assertVersion = { version: '999.888.777.666', filename: 'test.7z' }
|
const assertVersion = { version: '999.888.777.666', filename: 'test.7z' }
|
||||||
provider.getLatestVersion.resolves(assertVersion)
|
provider.getLatestVersion.resolves(assertVersion)
|
||||||
provider.downloadVersion.rejects(assertError)
|
provider.downloadVersion.rejects(assertError)
|
||||||
db.data.core.testapp.updater = ''
|
ctx.db.data.core.testapp.updater = ''
|
||||||
db.upsert(db.data.core.testapp.versions, { id: '999.888.777.666', version: '999.888.777.666', link: 'httplinkhere', filename: 'test.7z', failtoinstall: 4 })
|
ctx.db.upsert(ctx.db.data.core.testapp.versions, { id: '999.888.777.666', version: '999.888.777.666', link: 'httplinkhere', filename: 'test.7z', failtoinstall: 4 })
|
||||||
|
|
||||||
await app.update()
|
await app.update()
|
||||||
|
|
||||||
assert.ok(stubWrite.callCount >= 1)
|
assert.ok(stubWrite.callCount >= 1)
|
||||||
assert.strictEqual(app.updating, false)
|
assert.strictEqual(app.updating, false)
|
||||||
assert.notOk(provider.downloadVersion.called)
|
assert.notOk(provider.downloadVersion.called)
|
||||||
assert.match(db.data.core.testapp.updater, /many/i)
|
assert.match(ctx.db.data.core.testapp.updater, /many/i)
|
||||||
assert.match(db.data.core.testapp.updater, /fail/i)
|
assert.match(ctx.db.data.core.testapp.updater, /fail/i)
|
||||||
assert.match(db.data.core.testapp.updater, /skip/i)
|
assert.match(ctx.db.data.core.testapp.updater, /skip/i)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.timeout(250).describe('#registerModule()', function() {
|
t.timeout(250).describe('#registerModule()', function() {
|
||||||
const assertAppName = 'testappregister'
|
const assertAppName = 'testappregister'
|
||||||
let db
|
let ctx
|
||||||
let app
|
let app
|
||||||
|
|
||||||
t.beforeEach(function() {
|
t.beforeEach(function() {
|
||||||
return lowdb({ test: { } }, logger, null).then(function(res) {
|
return createFakeContext()
|
||||||
db = res
|
.then(function(res) {
|
||||||
let provider = new StaticProvider()
|
ctx = res
|
||||||
app = new Application(util, db, provider, assertAppName)
|
let provider = new StaticProvider()
|
||||||
})
|
app = new Application(ctx, provider, assertAppName)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should fail if not an object with start', function() {
|
t.test('should fail if not an object with start', function() {
|
||||||
|
|
365
test/core.test.mjs
Normal file
365
test/core.test.mjs
Normal file
|
@ -0,0 +1,365 @@
|
||||||
|
import { Eltro as t, assert, stub } from 'eltro'
|
||||||
|
import fs from 'fs/promises'
|
||||||
|
import Core from '../core/core.mjs'
|
||||||
|
import Util from '../core/util.mjs'
|
||||||
|
import { createFakeLog } from './helpers.mjs'
|
||||||
|
import StaticProvider from '../core/providers/static.mjs'
|
||||||
|
import lowdb from '../core/db.mjs'
|
||||||
|
|
||||||
|
const util = new Util(import.meta.url)
|
||||||
|
const log = createFakeLog()
|
||||||
|
let db
|
||||||
|
|
||||||
|
t.before(function() {
|
||||||
|
return lowdb({}, log, null).then(function(res) {
|
||||||
|
db = res
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.describe('Core.addProvider()', function() {
|
||||||
|
t.beforeEach(function() {
|
||||||
|
Core.providers.clear()
|
||||||
|
})
|
||||||
|
|
||||||
|
t.after(function() {
|
||||||
|
Core.providers.clear()
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should fail if name is not a string', function() {
|
||||||
|
let tests = [
|
||||||
|
[1, 'number'],
|
||||||
|
[0, 'false number'],
|
||||||
|
['', 'false string'],
|
||||||
|
[[], 'array'],
|
||||||
|
[{}, 'object'],
|
||||||
|
]
|
||||||
|
|
||||||
|
tests.forEach(function(check) {
|
||||||
|
assert.throws(function() {
|
||||||
|
Core.addProvider(check[0], StaticProvider)
|
||||||
|
}, function(err) {
|
||||||
|
assert.match(err.message, /name/i)
|
||||||
|
assert.match(err.message, /string/i)
|
||||||
|
return true
|
||||||
|
}, `throw if name is ${check[1]}`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should fail if provider not a function', function() {
|
||||||
|
let tests = [
|
||||||
|
[1, 'number'],
|
||||||
|
[0, 'false number'],
|
||||||
|
['asdf', 'string'],
|
||||||
|
['', 'false string'],
|
||||||
|
[[], 'array'],
|
||||||
|
[{}, 'object'],
|
||||||
|
]
|
||||||
|
|
||||||
|
tests.forEach(function(check) {
|
||||||
|
assert.throws(function() {
|
||||||
|
Core.addProvider('insertname', check[0])
|
||||||
|
}, function(err) {
|
||||||
|
assert.match(err.message, /provider/i)
|
||||||
|
assert.match(err.message, /class/i)
|
||||||
|
assert.match(err.message, /insertname/i)
|
||||||
|
return true
|
||||||
|
}, `throw if provider is ${check[1]}`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should fail if provider instance is missing checkConfig', function() {
|
||||||
|
let tests = [
|
||||||
|
[1, 'number'],
|
||||||
|
[0, 'false number'],
|
||||||
|
['asdf', 'string'],
|
||||||
|
['', 'false string'],
|
||||||
|
[[], 'array'],
|
||||||
|
[{}, 'object'],
|
||||||
|
]
|
||||||
|
|
||||||
|
tests.forEach(function(check) {
|
||||||
|
assert.throws(function() {
|
||||||
|
let provider = function() { this.getLatestVersion = function() {}; this.checkConfig = check[0] }
|
||||||
|
Core.addProvider('somename', provider)
|
||||||
|
}, function(err) {
|
||||||
|
assert.match(err.message, /provider/i)
|
||||||
|
assert.match(err.message, /class/i)
|
||||||
|
assert.match(err.message, /missing/i)
|
||||||
|
assert.match(err.message, /checkConfig/i)
|
||||||
|
assert.match(err.message, /somename/i)
|
||||||
|
return true
|
||||||
|
}, `throw if provider checkConfig is ${check[1]}`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should fail if provider instance is missing getLatestVersion', function() {
|
||||||
|
let tests = [
|
||||||
|
[1, 'number'],
|
||||||
|
[0, 'false number'],
|
||||||
|
['asdf', 'string'],
|
||||||
|
['', 'false string'],
|
||||||
|
[[], 'array'],
|
||||||
|
[{}, 'object'],
|
||||||
|
]
|
||||||
|
|
||||||
|
tests.forEach(function(check) {
|
||||||
|
assert.throws(function() {
|
||||||
|
let provider = function() { this.checkConfig = function() {}; this.getLatestVersion = check[0] }
|
||||||
|
Core.addProvider('somename', provider)
|
||||||
|
}, function(err) {
|
||||||
|
assert.match(err.message, /provider/i)
|
||||||
|
assert.match(err.message, /class/i)
|
||||||
|
assert.match(err.message, /missing/i)
|
||||||
|
assert.match(err.message, /getLatestVersion/i)
|
||||||
|
assert.match(err.message, /somename/i)
|
||||||
|
return true
|
||||||
|
}, `throw if provider getLatestVersion is ${check[1]}`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should otherwise add provider to map', function() {
|
||||||
|
assert.strictEqual(Core.providers.size, 0)
|
||||||
|
Core.addProvider('testnamehere', StaticProvider)
|
||||||
|
assert.strictEqual(Core.providers.size, 1)
|
||||||
|
assert.strictEqual(Core.providers.get('testnamehere'), StaticProvider)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.describe('#constructor()', function() {
|
||||||
|
t.test('should throw if close is not a function', function() {
|
||||||
|
let tests = [
|
||||||
|
[1, 'number'],
|
||||||
|
[0, 'false number'],
|
||||||
|
['asdf', 'string'],
|
||||||
|
['', 'false string'],
|
||||||
|
[[], 'array'],
|
||||||
|
[{}, 'object'],
|
||||||
|
]
|
||||||
|
|
||||||
|
tests.forEach(function(check) {
|
||||||
|
assert.throws(function() {
|
||||||
|
new Core(db, util, log, check[0])
|
||||||
|
}, function(err) {
|
||||||
|
assert.match(err.message, /restart/i)
|
||||||
|
assert.match(err.message, /function/i)
|
||||||
|
return true
|
||||||
|
}, `throw if restart is ${check[1]}`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should throw if util is not util', function() {
|
||||||
|
let tests = [
|
||||||
|
[1, 'number'],
|
||||||
|
[0, 'false number'],
|
||||||
|
['asdf', 'string'],
|
||||||
|
['', 'false string'],
|
||||||
|
[[], 'array'],
|
||||||
|
[{}, 'object'],
|
||||||
|
[Util, 'not instance'],
|
||||||
|
]
|
||||||
|
|
||||||
|
tests.forEach(function(check) {
|
||||||
|
assert.throws(function() {
|
||||||
|
new Core(db, check[0], log, function() {})
|
||||||
|
}, function(err) {
|
||||||
|
assert.match(err.message, /util/i)
|
||||||
|
assert.match(err.message, /instance/i)
|
||||||
|
return true
|
||||||
|
}, `throw if util is ${check[1]}`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should throw if db is not lowdb', function() {
|
||||||
|
let tests = [
|
||||||
|
[1, 'number'],
|
||||||
|
[0, 'false number'],
|
||||||
|
['asdf', 'string'],
|
||||||
|
['', 'false string'],
|
||||||
|
[[], 'array'],
|
||||||
|
[{}, 'object'],
|
||||||
|
[lowdb.Low, 'not instance'],
|
||||||
|
]
|
||||||
|
|
||||||
|
tests.forEach(function(check) {
|
||||||
|
assert.throws(function() {
|
||||||
|
new Core(check[0], util, log, function() {})
|
||||||
|
}, function(err) {
|
||||||
|
assert.match(err.message, /db/i)
|
||||||
|
assert.match(err.message, /instance/i)
|
||||||
|
return true
|
||||||
|
}, `throw if db is ${check[1]}`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should throw if log is not an object with event', function() {
|
||||||
|
let func = function() {}
|
||||||
|
let validEvent = { info: func, warn: func, error: func }
|
||||||
|
let tests = [
|
||||||
|
[1, 'number'],
|
||||||
|
[0, 'false number'],
|
||||||
|
[null, 'null'],
|
||||||
|
[undefined, 'undefined'],
|
||||||
|
['asdf', 'string'],
|
||||||
|
['', 'false string'],
|
||||||
|
[[], 'array'],
|
||||||
|
[{}, 'object'],
|
||||||
|
[{warn: func, event: validEvent }, 'log only warn'],
|
||||||
|
[{error: func, event: validEvent }, 'log only error'],
|
||||||
|
[{info: func, event: validEvent }, 'log only info'],
|
||||||
|
[{warn: func, error: func, event: validEvent }, 'log only warn and error'],
|
||||||
|
[{warn: func, info: func, event: validEvent }, 'log only warn and info'],
|
||||||
|
[{error: func, info: func, event: validEvent }, 'log only error and info'],
|
||||||
|
[{ warn: func, error: func, info: func, event: { warn: func } }, 'event only warn'],
|
||||||
|
[{ warn: func, error: func, info: func, event: { error: func } }, 'event only error'],
|
||||||
|
[{ warn: func, error: func, info: func, event: { info: func } }, 'event only info'],
|
||||||
|
[{ warn: func, error: func, info: func, event: { warn: func, error: func } }, 'event only warn and error'],
|
||||||
|
[{ warn: func, error: func, info: func, event: { warn: func, info: func } }, 'event only warn and info'],
|
||||||
|
[{ warn: func, error: func, info: func, event: { error: func, info: func } }, 'event only error and info'],
|
||||||
|
]
|
||||||
|
|
||||||
|
tests.forEach(function(check) {
|
||||||
|
assert.throws(function() {
|
||||||
|
new Core(db, util, check[0], func)
|
||||||
|
}, function(err) {
|
||||||
|
assert.match(err.message, /log/i)
|
||||||
|
assert.match(err.message, /valid/i)
|
||||||
|
return true
|
||||||
|
}, `throw if log is ${check[1]}`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should accept log, util and close function', function() {
|
||||||
|
const assertLog = log
|
||||||
|
const assertClose = function() {}
|
||||||
|
|
||||||
|
let core = new Core(db, util, assertLog, assertClose)
|
||||||
|
assert.strictEqual(core.db, db)
|
||||||
|
assert.strictEqual(core.util, util)
|
||||||
|
assert.strictEqual(core.log, assertLog)
|
||||||
|
assert.strictEqual(core.restart, assertClose)
|
||||||
|
assert.deepStrictEqual(core.applications, [])
|
||||||
|
assert.ok(core.applicationMap)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.describe('#getApplication()', function() {
|
||||||
|
|
||||||
|
t.test('should return application based on the name', function() {
|
||||||
|
const assertName = 'Yami no Naka'
|
||||||
|
const assertApplication = { a: 1 }
|
||||||
|
let core = new Core(db, util, log, function() {})
|
||||||
|
core.applicationMap.set(assertName, assertApplication)
|
||||||
|
assert.strictEqual(core.getApplication(assertName), assertApplication)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.describe('#init()', function() {
|
||||||
|
const assertProviderName = 'Kyousuu Gakku Gogyou Kikan'
|
||||||
|
let core
|
||||||
|
let fakeUtil
|
||||||
|
let fakeProvider
|
||||||
|
let fakeProviderConfig
|
||||||
|
|
||||||
|
function FakeProvider(config) {
|
||||||
|
fakeProvider(config)
|
||||||
|
this.static = true
|
||||||
|
this.checkConfig = fakeProviderConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
t.beforeEach(function() {
|
||||||
|
core = new Core(db, util, createFakeLog(), function() {})
|
||||||
|
core.util = fakeUtil = {
|
||||||
|
verifyConfig: stub(),
|
||||||
|
getAppNames: stub().returns([]),
|
||||||
|
}
|
||||||
|
fakeProvider = stub()
|
||||||
|
fakeProviderConfig = stub()
|
||||||
|
Core.providers.set(assertProviderName, FakeProvider)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('it should call util.verifyConfig correctly', async function() {
|
||||||
|
const assertError = new Error('Red faction IO drive mix')
|
||||||
|
const assertConfig = { a: 1 }
|
||||||
|
db.config = assertConfig
|
||||||
|
fakeUtil.verifyConfig.throws(assertError)
|
||||||
|
|
||||||
|
let err = await assert.isRejected(core.init())
|
||||||
|
assert.strictEqual(err, assertError)
|
||||||
|
assert.strictEqual(fakeUtil.verifyConfig.firstCall[0], assertConfig)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should call util.getNames correctly', async function() {
|
||||||
|
const assertError = new Error('Hero within')
|
||||||
|
const assertConfig = { a: 1 }
|
||||||
|
db.config = assertConfig
|
||||||
|
fakeUtil.getAppNames.throws(assertError)
|
||||||
|
|
||||||
|
let err = await assert.isRejected(core.init())
|
||||||
|
assert.strictEqual(err, assertError)
|
||||||
|
assert.strictEqual(fakeUtil.getAppNames.firstCall[0], assertConfig)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should call provider constructor correctly', async function() {
|
||||||
|
const assertError = new Error('Funny days')
|
||||||
|
const assertAppName = 'Tsuugakuro'
|
||||||
|
const assertConfig = {
|
||||||
|
[assertAppName]: {
|
||||||
|
provider: assertProviderName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
db.config = assertConfig
|
||||||
|
fakeProvider.throws(assertError)
|
||||||
|
fakeUtil.getAppNames.returns([assertAppName])
|
||||||
|
|
||||||
|
let err = await assert.isRejected(core.init())
|
||||||
|
assert.strictEqual(err, assertError)
|
||||||
|
assert.strictEqual(fakeProvider.firstCall[0], assertConfig[assertAppName])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should call provider checkConfig correctly', async function() {
|
||||||
|
const assertAppName = 'Zetsubou'
|
||||||
|
const assertConfig = {
|
||||||
|
[assertAppName]: {
|
||||||
|
provider: assertProviderName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
db.config = assertConfig
|
||||||
|
|
||||||
|
const assertError = new Error('Shousou')
|
||||||
|
fakeProviderConfig.rejects(assertError)
|
||||||
|
fakeUtil.getAppNames.returns([assertAppName])
|
||||||
|
|
||||||
|
let err = await assert.isRejected(core.init())
|
||||||
|
assert.strictEqual(err, assertError)
|
||||||
|
assert.strictEqual(fakeProviderConfig.firstCall[0], assertConfig[assertAppName])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should create an application with the provider and name and config', async function() {
|
||||||
|
const assertAppName = 'Yasashii Ketsumatsu'
|
||||||
|
const assertTestString = 'Serozore no Omoi'
|
||||||
|
const assertConfig = {
|
||||||
|
[assertAppName]: {
|
||||||
|
provider: assertProviderName,
|
||||||
|
teststring: assertTestString,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
db.config = assertConfig
|
||||||
|
fakeUtil.getAppNames.returns([assertAppName])
|
||||||
|
assert.strictEqual(core.applications.length, 0)
|
||||||
|
|
||||||
|
await core.init()
|
||||||
|
let application = core.getApplication(assertAppName)
|
||||||
|
|
||||||
|
assert.ok(application)
|
||||||
|
assert.strictEqual(core.applications.length, 1)
|
||||||
|
assert.strictEqual(core.applications[0], application)
|
||||||
|
assert.strictEqual(application.name, assertAppName)
|
||||||
|
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, assertTestString)
|
||||||
|
assert.ok(application.fresh)
|
||||||
|
assert.ok(application.provider instanceof FakeProvider)
|
||||||
|
})
|
||||||
|
})
|
|
@ -118,9 +118,9 @@ t.test('Should support adding an application with defaults', async function() {
|
||||||
|
|
||||||
assert.ok(db.data.core.app)
|
assert.ok(db.data.core.app)
|
||||||
assert.ok(db.data.core.app.versions)
|
assert.ok(db.data.core.app.versions)
|
||||||
assert.strictEqual(db.data.core.app.active, null)
|
assert.strictEqual(db.data.core.app.active, '')
|
||||||
assert.strictEqual(db.data.core.app.latestInstalled, null)
|
assert.strictEqual(db.data.core.app.latestInstalled, '')
|
||||||
assert.strictEqual(db.data.core.app.latestVersion, null)
|
assert.strictEqual(db.data.core.app.latestVersion, '')
|
||||||
|
|
||||||
assert.notOk(db.data.core.herpderp)
|
assert.notOk(db.data.core.herpderp)
|
||||||
|
|
||||||
|
@ -128,9 +128,9 @@ t.test('Should support adding an application with defaults', async function() {
|
||||||
|
|
||||||
assert.ok(db.data.core.herpderp)
|
assert.ok(db.data.core.herpderp)
|
||||||
assert.ok(db.data.core.herpderp.versions)
|
assert.ok(db.data.core.herpderp.versions)
|
||||||
assert.strictEqual(db.data.core.herpderp.active, null)
|
assert.strictEqual(db.data.core.herpderp.active, '')
|
||||||
assert.strictEqual(db.data.core.herpderp.latestInstalled, null)
|
assert.strictEqual(db.data.core.herpderp.latestInstalled, '')
|
||||||
assert.strictEqual(db.data.core.herpderp.latestVersion, null)
|
assert.strictEqual(db.data.core.herpderp.latestVersion, '')
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('Should support reading from db', async function() {
|
t.test('Should support reading from db', async function() {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export function start(db, log, core, http, port) {
|
export function start(http, port, ctx) {
|
||||||
const server = http.createServer(function (req, res) {
|
const server = http.createServer(function (req, res) {
|
||||||
res.writeHead(200);
|
res.writeHead(200);
|
||||||
res.end(JSON.stringify({ version: 'exampleindex' }))
|
res.end(JSON.stringify({ version: 'exampleindex' }))
|
||||||
|
@ -9,8 +9,8 @@ export function start(db, log, core, http, port) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return rej(err)
|
return rej(err)
|
||||||
}
|
}
|
||||||
log.event.info(`Server is listening on ${port} serving package ${staticPackage}`)
|
ctx.log.event.info(`Server is listening on ${port} serving exampleindex`)
|
||||||
log.info(`Server is listening on ${port} serving package ${staticPackage}`)
|
ctx.log.info(`Server is listening on ${port} serving exampleindex`)
|
||||||
res()
|
res()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
29
test/helpers.mjs
Normal file
29
test/helpers.mjs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import { stub } from 'eltro'
|
||||||
|
import lowdb from '../core/db.mjs'
|
||||||
|
import Util from '../core/util.mjs'
|
||||||
|
|
||||||
|
export function createFakeLog() {
|
||||||
|
return {
|
||||||
|
info: stub(),
|
||||||
|
warn: stub(),
|
||||||
|
error: stub(),
|
||||||
|
event: {
|
||||||
|
info: stub(),
|
||||||
|
warn: stub(),
|
||||||
|
error: stub(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createFakeContext(config = { }, util = new Util(import.meta.url), filename = null) {
|
||||||
|
const log = createFakeLog()
|
||||||
|
|
||||||
|
return lowdb(config, log, filename).then(function(res) {
|
||||||
|
return {
|
||||||
|
db: res,
|
||||||
|
util: util,
|
||||||
|
log: log,
|
||||||
|
core: { },
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import { Eltro as t, assert, stub } from 'eltro'
|
import { Eltro as t, assert, stub } from 'eltro'
|
||||||
import http from 'http'
|
import http from 'http'
|
||||||
import https from 'https'
|
import https from 'https'
|
||||||
|
import { setTimeout } from 'timers/promises'
|
||||||
import { request } from '../core/client.mjs'
|
import { request } from '../core/client.mjs'
|
||||||
import HttpServer from '../core/http.mjs'
|
import HttpServer from '../core/http.mjs'
|
||||||
|
|
||||||
|
@ -22,9 +23,7 @@ t.describe('Sockets', function() {
|
||||||
let http = new HttpServer()
|
let http = new HttpServer()
|
||||||
|
|
||||||
t.after(function() {
|
t.after(function() {
|
||||||
http.closeServer().then(function() { }, function(err) {
|
return http.closeServer()
|
||||||
console.error(err)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should keep track of sockets through its lifetime', function(cb) {
|
t.test('should keep track of sockets through its lifetime', function(cb) {
|
||||||
|
@ -41,7 +40,7 @@ t.describe('Sockets', function() {
|
||||||
Promise.resolve()
|
Promise.resolve()
|
||||||
.then(async function() {
|
.then(async function() {
|
||||||
await new Promise(function(res, rej) {
|
await new Promise(function(res, rej) {
|
||||||
server.listen(port, function(err) { if (err) rej(err); res()})
|
server.listen(port, function() { res()})
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.strictEqual(actives.length, 0)
|
assert.strictEqual(actives.length, 0)
|
||||||
|
@ -50,16 +49,18 @@ t.describe('Sockets', function() {
|
||||||
request({}, prefix).then(function() {}, cb)
|
request({}, prefix).then(function() {}, cb)
|
||||||
request({}, prefix).then(async function() {
|
request({}, prefix).then(async function() {
|
||||||
while (http.sockets.size > 0) {
|
while (http.sockets.size > 0) {
|
||||||
await new Promise(function(res) { setTimeout(res, 10) })
|
await setTimeout(10)
|
||||||
}
|
}
|
||||||
assert.strictEqual(http.sockets.size, 0)
|
assert.strictEqual(http.sockets.size, 0)
|
||||||
cb()
|
cb()
|
||||||
}, cb)
|
}, cb)
|
||||||
|
|
||||||
while (actives.length < 2) {
|
while (actives.length < 2) {
|
||||||
await new Promise(function(res) { setTimeout(res, 10) })
|
await setTimeout(10)
|
||||||
}
|
}
|
||||||
assert.strictEqual(http.sockets.size, 2)
|
assert.strictEqual(http.sockets.size, 2)
|
||||||
|
|
||||||
|
assert.ok(http.active)
|
||||||
actives[0].statusCode = 200
|
actives[0].statusCode = 200
|
||||||
actives[0].end('{}')
|
actives[0].end('{}')
|
||||||
actives[1].statusCode = 200
|
actives[1].statusCode = 200
|
||||||
|
@ -68,13 +69,17 @@ t.describe('Sockets', function() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.describe('Close', function() {
|
t.describe('closeServer()', function() {
|
||||||
let http = new HttpServer()
|
let http = new HttpServer()
|
||||||
|
|
||||||
t.after(function() {
|
t.after(function() {
|
||||||
http.closeServer().then(function() { }, function(err) {
|
return http.closeServer()
|
||||||
console.error(err)
|
})
|
||||||
})
|
|
||||||
|
t.test('should not fail if server is not listening', function() {
|
||||||
|
http.createServer(function() { })
|
||||||
|
|
||||||
|
return http.closeServer()
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should support forcefully closing them on server close', function(cb) {
|
t.test('should support forcefully closing them on server close', function(cb) {
|
||||||
|
@ -90,7 +95,7 @@ t.describe('Close', function() {
|
||||||
Promise.resolve()
|
Promise.resolve()
|
||||||
.then(async function() {
|
.then(async function() {
|
||||||
await new Promise(function(res, rej) {
|
await new Promise(function(res, rej) {
|
||||||
server.listen(port, function(err) { if (err) rej(err); res()})
|
server.listen(port, function() { res()})
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.strictEqual(http.sockets.size, 0)
|
assert.strictEqual(http.sockets.size, 0)
|
||||||
|
@ -105,13 +110,15 @@ t.describe('Close', function() {
|
||||||
)
|
)
|
||||||
|
|
||||||
while (http.sockets.size < 2) {
|
while (http.sockets.size < 2) {
|
||||||
await new Promise(function(res) { setTimeout(res, 10) })
|
await setTimeout(10)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert.ok(http.active)
|
||||||
|
|
||||||
http.closeServer().then(function() { }, cb)
|
http.closeServer().then(function() { }, cb)
|
||||||
|
|
||||||
while (requestErrors.length < 2) {
|
while (requestErrors.length < 2) {
|
||||||
await new Promise(function(res) { setTimeout(res, 10) })
|
await setTimeout(10)
|
||||||
}
|
}
|
||||||
assert.strictEqual(http.sockets.size, 0)
|
assert.strictEqual(http.sockets.size, 0)
|
||||||
assert.strictEqual(requestErrors.length, 2)
|
assert.strictEqual(requestErrors.length, 2)
|
||||||
|
@ -122,12 +129,39 @@ t.describe('Close', function() {
|
||||||
assert.strictEqual(requestErrors[1].code, 'ECONNRESET')
|
assert.strictEqual(requestErrors[1].code, 'ECONNRESET')
|
||||||
|
|
||||||
while (requestErrors.length < 2) {
|
while (requestErrors.length < 2) {
|
||||||
await new Promise(function(res) { setTimeout(res, 10) })
|
await setTimeout(10)
|
||||||
}
|
}
|
||||||
while (http.active) {
|
while (http.active) {
|
||||||
await new Promise(function(res) { setTimeout(res, 10) })
|
await setTimeout(10)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(function() { cb()}, cb)
|
.then(function() { cb()}, cb)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.describe('listenAsync()', function() {
|
||||||
|
let httpFirst = new HttpServer()
|
||||||
|
let httpSecond = new HttpServer()
|
||||||
|
|
||||||
|
t.after(function() {
|
||||||
|
return Promise.all([
|
||||||
|
httpFirst.closeServer(),
|
||||||
|
httpSecond.closeServer(),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should reject successfully if port is busy', async function() {
|
||||||
|
let serverFirst = httpFirst.createServer(function() { })
|
||||||
|
let serverSecond = httpSecond.createServer(function() { })
|
||||||
|
|
||||||
|
await serverFirst.listenAsync(port)
|
||||||
|
|
||||||
|
await setTimeout(10)
|
||||||
|
|
||||||
|
let err = await assert.isRejected(serverSecond.listenAsync(port))
|
||||||
|
assert.strictEqual(err.code, 'EADDRINUSE')
|
||||||
|
|
||||||
|
assert.ok(serverFirst.listening)
|
||||||
|
assert.notOk(serverSecond.listening)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
286
test/log.test.mjs
Normal file
286
test/log.test.mjs
Normal file
|
@ -0,0 +1,286 @@
|
||||||
|
import { Eltro as t, assert, stub } from 'eltro'
|
||||||
|
import getLog from '../core/log.mjs'
|
||||||
|
|
||||||
|
t.describe('#constructor', function() {
|
||||||
|
t.afterEach(function() {
|
||||||
|
process.env.NODE_ENV = null
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should add name', function() {
|
||||||
|
const assertName = 'Stray Cat'
|
||||||
|
let logger = getLog(assertName)
|
||||||
|
assert.strictEqual(logger.fields.name, assertName)
|
||||||
|
|
||||||
|
process.env.NODE_ENV = 'production'
|
||||||
|
logger = getLog(assertName)
|
||||||
|
assert.strictEqual(logger.fields.name, assertName)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should add default stdout streams in normal environment', function() {
|
||||||
|
let logger = getLog('app', null)
|
||||||
|
assert.strictEqual(logger.streams.length, 4)
|
||||||
|
assert.strictEqual(logger.streams[0].stream, process.stdout)
|
||||||
|
assert.strictEqual(logger.streams[0].level, 20)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should add default file log stream in production environment', function() {
|
||||||
|
process.env.NODE_ENV = 'production'
|
||||||
|
|
||||||
|
let logger = getLog('app', null)
|
||||||
|
assert.strictEqual(logger.streams.length, 4)
|
||||||
|
assert.strictEqual(logger.streams[0].path, 'log.log')
|
||||||
|
assert.strictEqual(logger.streams[0].level, 30)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should not add default stream if empty array', function() {
|
||||||
|
let logger = getLog('app', [])
|
||||||
|
assert.strictEqual(logger.streams.length, 3)
|
||||||
|
|
||||||
|
process.env.NODE_ENV = 'production'
|
||||||
|
logger = getLog('app', [])
|
||||||
|
assert.strictEqual(logger.streams.length, 3)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should replace process.stdout with actual process', function() {
|
||||||
|
let logger = getLog('app', [{ stream: 'process.stdout', level: 'info' }])
|
||||||
|
assert.strictEqual(logger.streams.length, 4)
|
||||||
|
assert.strictEqual(logger.streams[0].stream, process.stdout)
|
||||||
|
|
||||||
|
process.env.NODE_ENV = 'production'
|
||||||
|
logger = getLog('app', [{ stream: 'process.stdout', level: 'info' }])
|
||||||
|
assert.strictEqual(logger.streams.length, 4)
|
||||||
|
assert.strictEqual(logger.streams[0].stream, process.stdout)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.describe('ringbuffer', function() {
|
||||||
|
let logger
|
||||||
|
|
||||||
|
t.beforeEach(function() {
|
||||||
|
logger = getLog('app', [])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should have ringbuffer for info', function() {
|
||||||
|
const assertMessage = 'Oitachi'
|
||||||
|
|
||||||
|
assert.strictEqual(logger.ringbuffer.records.length, 0)
|
||||||
|
logger.info(assertMessage)
|
||||||
|
assert.strictEqual(logger.ringbuffer.records.length, 1)
|
||||||
|
assert.strictEqual(logger.ringbuffer.records[0].level, 30)
|
||||||
|
assert.strictEqual(logger.ringbuffer.records[0].msg, assertMessage)
|
||||||
|
logger.debug(assertMessage)
|
||||||
|
assert.strictEqual(logger.ringbuffer.records.length, 1)
|
||||||
|
logger.warn(assertMessage)
|
||||||
|
assert.strictEqual(logger.ringbuffer.records.length, 2)
|
||||||
|
assert.strictEqual(logger.ringbuffer.records[1].level, 40)
|
||||||
|
assert.strictEqual(logger.ringbuffer.records[1].msg, assertMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should keep it limited to max 100 records', function() {
|
||||||
|
const assertPrefix = 'In memory of Keiten'
|
||||||
|
|
||||||
|
for (let i = 1; i <= 101; i++) {
|
||||||
|
logger.info(assertPrefix + i)
|
||||||
|
}
|
||||||
|
assert.strictEqual(logger.ringbuffer.records.length, 100)
|
||||||
|
assert.strictEqual(logger.ringbuffer.records[0].msg, assertPrefix + '2')
|
||||||
|
|
||||||
|
logger.info(assertPrefix)
|
||||||
|
|
||||||
|
assert.strictEqual(logger.ringbuffer.records.length, 100)
|
||||||
|
assert.strictEqual(logger.ringbuffer.records[0].msg, assertPrefix + '3')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.describe('ringbufferwarn', function() {
|
||||||
|
let logger
|
||||||
|
|
||||||
|
t.beforeEach(function() {
|
||||||
|
logger = getLog('app', [])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should have ringbufferwarn for info', function() {
|
||||||
|
const assertMessage = 'Oitachi'
|
||||||
|
|
||||||
|
assert.strictEqual(logger.ringbufferwarn.records.length, 0)
|
||||||
|
logger.warn(assertMessage)
|
||||||
|
assert.strictEqual(logger.ringbufferwarn.records.length, 1)
|
||||||
|
assert.strictEqual(logger.ringbufferwarn.records[0].level, 40)
|
||||||
|
assert.strictEqual(logger.ringbufferwarn.records[0].msg, assertMessage)
|
||||||
|
logger.info(assertMessage)
|
||||||
|
assert.strictEqual(logger.ringbufferwarn.records.length, 1)
|
||||||
|
logger.error(assertMessage)
|
||||||
|
assert.strictEqual(logger.ringbufferwarn.records.length, 2)
|
||||||
|
assert.strictEqual(logger.ringbufferwarn.records[1].level, 50)
|
||||||
|
assert.strictEqual(logger.ringbufferwarn.records[1].msg, assertMessage)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should keep it limited to max 100 records', function() {
|
||||||
|
const assertPrefix = 'In memory of Keiten'
|
||||||
|
|
||||||
|
for (let i = 1; i <= 101; i++) {
|
||||||
|
logger.warn(assertPrefix + i)
|
||||||
|
}
|
||||||
|
assert.strictEqual(logger.ringbufferwarn.records.length, 100)
|
||||||
|
assert.strictEqual(logger.ringbufferwarn.records[0].msg, assertPrefix + '2')
|
||||||
|
|
||||||
|
logger.warn(assertPrefix)
|
||||||
|
|
||||||
|
assert.strictEqual(logger.ringbufferwarn.records.length, 100)
|
||||||
|
assert.strictEqual(logger.ringbufferwarn.records[0].msg, assertPrefix + '3')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.describe('event', function() {
|
||||||
|
t.test('should call import if not in production', async function() {
|
||||||
|
let stubImport = stub()
|
||||||
|
stubImport.rejects(new Error('should not be seen'))
|
||||||
|
|
||||||
|
let logger = getLog('app', [], { import: stubImport })
|
||||||
|
|
||||||
|
let first = new Promise(function(res, rej) {
|
||||||
|
setImmediate(function() { logger.event.warn('text message here').then(res, rej) })
|
||||||
|
})
|
||||||
|
let second = new Promise(function(res, rej) {
|
||||||
|
setImmediate(function() { logger.event.warn('new message here').then(res, rej) })
|
||||||
|
})
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
first, second,
|
||||||
|
])
|
||||||
|
|
||||||
|
assert.notOk(stubImport.called)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should call import correctly if in production and fail only once', async function() {
|
||||||
|
process.env.NODE_ENV = 'production'
|
||||||
|
|
||||||
|
let stubImport = stub()
|
||||||
|
stubImport.rejects(new Error('should not be seen'))
|
||||||
|
|
||||||
|
let logger = getLog('app', [], { import: stubImport })
|
||||||
|
|
||||||
|
let first = new Promise(function(res, rej) {
|
||||||
|
setImmediate(function() { try { logger.event.warn('first').then(res, rej) } catch (err) { rej(err) } })
|
||||||
|
})
|
||||||
|
let second = new Promise(function(res, rej) {
|
||||||
|
setImmediate(function() { try { logger.event.warn('second').then(res, rej) } catch (err) { rej(err) } })
|
||||||
|
})
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
first, second,
|
||||||
|
])
|
||||||
|
|
||||||
|
assert.ok(stubImport.called)
|
||||||
|
assert.strictEqual(stubImport.callCount, 1)
|
||||||
|
assert.strictEqual(stubImport.firstCall[0], 'node-windows')
|
||||||
|
|
||||||
|
await new Promise(function(res, rej) {
|
||||||
|
setImmediate(function() { try { logger.event.warn('third').then(res, rej) } catch (err) { rej(err) } })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should call event on imported object correctly', async function() {
|
||||||
|
const assertName = 'It is going to be The Special'
|
||||||
|
let checkName = ''
|
||||||
|
let stubInfo = stub().returnWith(function(msg, code, cb) { setTimeout(cb, 20) })
|
||||||
|
let stubWarn = stub().returnWith(function(msg, code, cb) { setTimeout(cb, 20) })
|
||||||
|
let stubError = stub().returnWith(function(msg, code, cb) { setTimeout(cb, 20) })
|
||||||
|
process.env.NODE_ENV = 'production'
|
||||||
|
|
||||||
|
let stubImport = stub().resolves({
|
||||||
|
default: {
|
||||||
|
EventLogger: function(name) {
|
||||||
|
checkName = name
|
||||||
|
this.info = stubInfo
|
||||||
|
this.warn = stubWarn
|
||||||
|
this.error = stubError
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
let logger = getLog(assertName, [], { import: stubImport })
|
||||||
|
|
||||||
|
let first = new Promise(function(res, rej) {
|
||||||
|
setImmediate(function() { try { logger.event.info('first', 1010).then(res, rej) } catch (err) { rej(err) } })
|
||||||
|
})
|
||||||
|
let second = new Promise(function(res, rej) {
|
||||||
|
setImmediate(function() { try { logger.event.warn('second', 1020).then(res, rej) } catch (err) { rej(err) } })
|
||||||
|
})
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
first, second,
|
||||||
|
])
|
||||||
|
|
||||||
|
assert.strictEqual(checkName, assertName)
|
||||||
|
assert.ok(stubInfo.called)
|
||||||
|
assert.strictEqual(stubInfo.firstCall[0], 'first')
|
||||||
|
assert.strictEqual(stubInfo.firstCall[1], 1010)
|
||||||
|
assert.ok(stubWarn.called)
|
||||||
|
assert.strictEqual(stubWarn.firstCall[0], 'second')
|
||||||
|
assert.strictEqual(stubWarn.firstCall[1], 1020)
|
||||||
|
assert.notOk(stubError.called)
|
||||||
|
|
||||||
|
await new Promise(function(res, rej) {
|
||||||
|
setImmediate(function() { try { logger.event.error('third', 1030).then(res, rej) } catch (err) { rej(err) } })
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.ok(stubError.called)
|
||||||
|
assert.strictEqual(stubError.firstCall[0], 'third')
|
||||||
|
assert.strictEqual(stubError.firstCall[1], 1030)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should work even if it were to throw', async function() {
|
||||||
|
const assertName = 'It is going to be The Special'
|
||||||
|
let checkName = ''
|
||||||
|
let stubInfo = stub().returnWith(function() { throw new Error('not to be seen') })
|
||||||
|
let stubWarn = stub().returnWith(function() { throw new Error('not to be seen') })
|
||||||
|
let stubError = stub().returnWith(function() { throw new Error('not to be seen') })
|
||||||
|
process.env.NODE_ENV = 'production'
|
||||||
|
|
||||||
|
let stubImport = stub().resolves({
|
||||||
|
default: {
|
||||||
|
EventLogger: function(name) {
|
||||||
|
checkName = name
|
||||||
|
this.info = stubInfo
|
||||||
|
this.warn = stubWarn
|
||||||
|
this.error = stubError
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
let logger = getLog(assertName, [], { import: stubImport })
|
||||||
|
|
||||||
|
let first = new Promise(function(res, rej) {
|
||||||
|
setImmediate(function() { try { logger.event.info().then(res, rej) } catch (err) { rej(err) } })
|
||||||
|
})
|
||||||
|
let second = new Promise(function(res, rej) {
|
||||||
|
setImmediate(function() { try { logger.event.warn().then(res, rej) } catch (err) { rej(err) } })
|
||||||
|
})
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
first, second,
|
||||||
|
])
|
||||||
|
|
||||||
|
assert.strictEqual(checkName, assertName)
|
||||||
|
assert.ok(stubInfo.called)
|
||||||
|
assert.ok(stubWarn.called)
|
||||||
|
assert.notOk(stubError.called)
|
||||||
|
|
||||||
|
await new Promise(function(res, rej) {
|
||||||
|
setImmediate(function() { try { logger.event.error().then(res, rej) } catch (err) { rej(err) } })
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.ok(stubError.called)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should work without stub', async function() {
|
||||||
|
let res = await import('node-windows').catch(function() {})
|
||||||
|
if (!res) { return }
|
||||||
|
|
||||||
|
process.env.NODE_ENV = 'production'
|
||||||
|
let logger = getLog('service-core-unit-test', [])
|
||||||
|
|
||||||
|
await logger.event.info('Hello from service-core log.event unit test')
|
||||||
|
})
|
||||||
|
})
|
|
@ -1,6 +1,7 @@
|
||||||
import { Eltro as t, assert} from 'eltro'
|
import { Eltro as t, assert} from 'eltro'
|
||||||
import fs from 'fs/promises'
|
import fs from 'fs/promises'
|
||||||
import Util from '../core/util.mjs'
|
import Util from '../core/util.mjs'
|
||||||
|
import { defaults } from '../core/defaults.mjs'
|
||||||
|
|
||||||
const isWindows = process.platform === 'win32'
|
const isWindows = process.platform === 'win32'
|
||||||
|
|
||||||
|
@ -108,43 +109,162 @@ t.describe('#getApplications()', function() {
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 1234, port: 1234 } }), [])
|
assert.deepStrictEqual(util.getAppNames({ app: { provider: 1234, port: 1234 } }), [])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function getBase(extra = {}) {
|
||||||
|
return defaults({ app: extra }, { app: { provider: 'asdf', port: 1234, } })
|
||||||
|
}
|
||||||
|
|
||||||
t.test('should fail to find if https is defined but not a boolean', function() {
|
t.test('should fail to find if https is defined but not a boolean', function() {
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, } }), ['app'])
|
assert.deepStrictEqual(util.getAppNames(getBase()), ['app'])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, https: null } }), ['app'])
|
assert.deepStrictEqual(util.getAppNames(getBase({ https: null })), ['app'])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, https: false } }), ['app'])
|
assert.deepStrictEqual(util.getAppNames(getBase({ https: false })), ['app'])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, https: true } }), ['app'])
|
assert.deepStrictEqual(util.getAppNames(getBase({ https: true })), ['app'])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, https: 'asdf' } }), [])
|
assert.deepStrictEqual(util.getAppNames(getBase({ https: 'asdf' })), [])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, https: '1234' } }), [])
|
assert.deepStrictEqual(util.getAppNames(getBase({ https: '1234' })), [])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, https: 0 } }), [])
|
assert.deepStrictEqual(util.getAppNames(getBase({ https: 0 })), [])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, https: [] } }), [])
|
assert.deepStrictEqual(util.getAppNames(getBase({ https: [] })), [])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, https: {} } }), [])
|
assert.deepStrictEqual(util.getAppNames(getBase({ https: {} })), [])
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should fail to find if updateEvery is defined but not a valid number', function() {
|
t.test('should fail to find if updateEvery is defined but not a valid number', function() {
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, } }), ['app'])
|
assert.deepStrictEqual(util.getAppNames(getBase()), ['app'])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, updateEvery: null } }), ['app'])
|
assert.deepStrictEqual(util.getAppNames(getBase({ updateEvery: null })), ['app'])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, updateEvery: 5 } }), ['app'])
|
assert.deepStrictEqual(util.getAppNames(getBase({ updateEvery: 5 })), ['app'])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, updateEvery: 1000 } }), ['app'])
|
assert.deepStrictEqual(util.getAppNames(getBase({ updateEvery: 1000 })), ['app'])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, updateEvery: 'asdf' } }), [])
|
assert.deepStrictEqual(util.getAppNames(getBase({ updateEvery: 'asdf' })), [])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, updateEvery: '1234' } }), [])
|
assert.deepStrictEqual(util.getAppNames(getBase({ updateEvery: '1234' })), [])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, updateEvery: 0 } }), [])
|
assert.deepStrictEqual(util.getAppNames(getBase({ updateEvery: 0 })), ['app'])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, updateEvery: -5 } }), [])
|
assert.deepStrictEqual(util.getAppNames(getBase({ updateEvery: -1 })), [])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, updateEvery: [] } }), [])
|
assert.deepStrictEqual(util.getAppNames(getBase({ updateEvery: -5 })), [])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, updateEvery: {} } }), [])
|
assert.deepStrictEqual(util.getAppNames(getBase({ updateEvery: [] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ updateEvery: {} })), [])
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('should fail to find if waitUntilFail is defined but not a valid number', function() {
|
t.test('should fail to find if startWaitUntilFail is defined but not a valid number', function() {
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, } }), ['app'])
|
assert.deepStrictEqual(util.getAppNames(getBase()), ['app'])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, waitUntilFail: null } }), ['app'])
|
assert.deepStrictEqual(util.getAppNames(getBase({ startWaitUntilFail: null })), ['app'])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, waitUntilFail: 5 } }), [])
|
assert.deepStrictEqual(util.getAppNames(getBase({ startWaitUntilFail: 5 })), [])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, waitUntilFail: 15 } }), ['app'])
|
assert.deepStrictEqual(util.getAppNames(getBase({ startWaitUntilFail: 15 })), ['app'])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, waitUntilFail: 1000 } }), ['app'])
|
assert.deepStrictEqual(util.getAppNames(getBase({ startWaitUntilFail: 1000 })), ['app'])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, waitUntilFail: 'asdf' } }), [])
|
assert.deepStrictEqual(util.getAppNames(getBase({ startWaitUntilFail: 'asdf' })), [])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, waitUntilFail: '1234' } }), [])
|
assert.deepStrictEqual(util.getAppNames(getBase({ startWaitUntilFail: '1234' })), [])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, waitUntilFail: 0 } }), [])
|
assert.deepStrictEqual(util.getAppNames(getBase({ startWaitUntilFail: 0 })), [])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, waitUntilFail: -5 } }), [])
|
assert.deepStrictEqual(util.getAppNames(getBase({ startWaitUntilFail: -5 })), [])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, waitUntilFail: [] } }), [])
|
assert.deepStrictEqual(util.getAppNames(getBase({ startWaitUntilFail: [] })), [])
|
||||||
assert.deepStrictEqual(util.getAppNames({ app: { provider: 'asdf', port: 1234, waitUntilFail: {} } }), [])
|
assert.deepStrictEqual(util.getAppNames(getBase({ startWaitUntilFail: {} })), [])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should fail to find if heartbeatTimeout is defined but not a valid number', function() {
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase()), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatTimeout: null })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatTimeout: 5 })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatTimeout: 15 })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatTimeout: 1000 })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatTimeout: 'asdf' })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatTimeout: '1234' })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatTimeout: 0 })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatTimeout: -5 })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatTimeout: [] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatTimeout: {} })), [])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should fail to find if heartbeatAttempts is defined but not a valid number', function() {
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase()), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttempts: null })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttempts: 1 })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttempts: 15 })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttempts: 1000 })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttempts: 'asdf' })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttempts: '1234' })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttempts: 0 })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttempts: -5 })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttempts: [] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttempts: {} })), [])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should fail to find if heartbeatAttemptsWait is defined but not a valid number', function() {
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase()), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttemptsWait: null })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttemptsWait: 5 })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttemptsWait: 15 })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttemptsWait: 1000 })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttemptsWait: 'asdf' })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttemptsWait: '1234' })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttemptsWait: 0 })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttemptsWait: -5 })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttemptsWait: [] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatAttemptsWait: {} })), [])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should fail to find if heartbeatPath is defined but not a valid string', function() {
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase()), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatPath: null })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatPath: 5 })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatPath: 15 })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatPath: 1000 })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatPath: 'asdf' })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatPath: '1234' })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatPath: '/asdf' })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatPath: '/1234' })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatPath: 0 })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatPath: -5 })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatPath: [] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ heartbeatPath: {} })), [])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should fail to find if log is defined but not an array', function() {
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase()), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: null })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: 5 })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: 'asdf' })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: '1234' })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: 0 })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [] })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: {} })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: { length:1 } })), [])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should fail to find if log has an item but level and either stream or path ', function() {
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase()), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: null })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [null] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [5] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [15] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [1000] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: ['asdf'] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: ['1234'] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: ['/asdf'] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: ['/1234'] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [0] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [-5] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [[]] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{}] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: null, path: 'log' }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 5, path: 'log' }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 0, path: 'log' }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: [], path: 'log' }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: {}, path: 'log' }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: '', path: 'log' }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'asdf', path: 'log' }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'fatal', path: 'log' }] })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'error', path: 'log' }] })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'warn', path: 'log' }] })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'info', path: 'log' }] })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'debug', path: 'log' }] })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'trace', path: 'log' }] })), ['app'])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'info', path: '' }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'info', path: null }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'info', path: 5 }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'info', path: 0 }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'info', path: [] }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'info', path: {} }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'info', stream: '' }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'info', stream: null }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'info', stream: 5 }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'info', stream: 0 }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'info', stream: [] }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'info', stream: {} }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'info', stream: 'asdf' }] })), [])
|
||||||
|
assert.deepStrictEqual(util.getAppNames(getBase({ log: [{ level: 'info', stream: 'process.stdout' }] })), ['app'])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -227,6 +347,14 @@ t.describe('#verifyConfig()', function() {
|
||||||
t.describe('#extractFile()', function() {
|
t.describe('#extractFile()', function() {
|
||||||
var util = new Util(import.meta.url)
|
var util = new Util(import.meta.url)
|
||||||
|
|
||||||
|
t.beforeEach(function() {
|
||||||
|
return Promise.all([
|
||||||
|
fs.rm('./test/testapp/example.tar', { force: true }),
|
||||||
|
fs.rm('./test/testapp/file1.txt', { force: true }),
|
||||||
|
fs.rm('./test/testapp/file2.txt', { force: true }),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
t.afterEach(function() {
|
t.afterEach(function() {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
fs.rm('./test/testapp/example.tar', { force: true }),
|
fs.rm('./test/testapp/example.tar', { force: true }),
|
||||||
|
|
Loading…
Reference in a new issue