diff --git a/.gitignore b/.gitignore index 51df9ba..5e13e92 100644 --- a/.gitignore +++ b/.gitignore @@ -108,6 +108,4 @@ db.json package-lock.json daemon -app/* -manage/* dev/public/main.js diff --git a/core/application.mjs b/core/application.mjs index a7b5d5c..30c8a6c 100644 --- a/core/application.mjs +++ b/core/application.mjs @@ -13,6 +13,7 @@ export default class Application extends EventEmitter { Object.assign(this, { setInterval: opts.setInterval || setInterval, + fs: opts.fs || fs, }) this.db.addApplication(name) @@ -35,6 +36,7 @@ export default class Application extends EventEmitter { updateLog(message) { this.db.data.core[this.name].updater += message this.db.log.info(message) + return message } async update() { @@ -42,28 +44,127 @@ export default class Application extends EventEmitter { this.updating = true this.db.data.core[this.name].updater = '' + let cleanup = true + let folder = '' + let log = '' + let latest = null try { - this.updateLog(`Checking for latest version at ${new Date().toISOString().replace('T', ' ').split('.')[0]}. `) + log += this.updateLog(`Checking for latest version at ${new Date().toISOString().replace('T', ' ').split('.')[0]}. `) + '\n' - let latest = await this.provider.getLatestVersion() + latest = await this.provider.getLatestVersion() - this.updateLog(`Found ${latest.version}. `) + log += this.updateLog(`Found ${latest.version}. `) + '\n' if (this.db.data.core[this.name].latestInstalled === latest.version) { this.updateLog('Already up to date, nothing to do. ') + this.updating = false + return + } + + latest.id = latest.version + var found = this.db.get(this.db.data.core[this.name].versions, latest.id) + if (found) { + Object.keys(latest).forEach(function(key) { + found[key] = latest[key] + }) + latest = found + log = latest.log + log + } else { + this.db.upsert(this.db.data.core[this.name].versions, latest) + } + + if (latest.failtodownload && latest.failtodownload > 3) { + this.updateLog('Version failed to download too many times, skipping this version. ') + this.updating = false + return + } + if (latest.failtoinstall && latest.failtoinstall > 3) { + this.updateLog('Version failed to install too many times, skipping this version. ') + this.updating = false return } let target = this.util.getPathFromRoot(`./${this.name}/${latest.version}/file${this.util.getExtension(latest.filename)}`) + folder = this.util.getPathFromRoot(`./${this.name}/${latest.version}`) - await fs.mkdir(this.util.getPathFromRoot(`./${this.name}/${latest.version}`), { recursive: true }) + await this.fs.mkdir(folder, { recursive: true }) - this.updateLog(`Downloading ${latest.link} to ${target}. `) + log += this.updateLog(`Downloading ${latest.link} to ${target}. `) + '\n' await this.provider.downloadVersion(latest, target) + .catch(function(err) { + latest.failtodownload = (latest.failtodownload || 0) + 1 + return Promise.reject(err) + }) + + log += '\n' + this.updateLog(`Extracting ${target}. `) + '\n' + await this.util.extractFile(target, function(msg) { + log += msg + }).catch(function(err) { + latest.failtodownload = (latest.failtodownload || 0) + 1 + return Promise.reject(err) + }) + + if (!log.endsWith('\n')) { + log += '\n' + } + if (!log.endsWith('\n\n')) { + log += '\n' + } + + await this.fs.stat(this.util.getPathFromRoot(`./${this.name}/${latest.version}/index.mjs`)) + .catch((err) => { + latest.failtodownload = (latest.failtodownload || 0) + 1 + log += this.updateLog('Version did not include or was missing index.mjs. ') + '\n' + return Promise.reject(err) + }) + + cleanup = false + + let packageStat = await this.fs.stat(this.util.getPathFromRoot(`./${this.name}/${latest.version}/package.json`)) + .catch(function() { return null }) + + if (packageStat) { + log += this.updateLog(`running npm install --production. `) + '\n' + await this.util.runCommand( + 'npm.cmd', + ['install', '--production', '--no-optional', '--no-package-lock', '--no-audit', '--loglevel=notice'], + folder, + function(msg) { + log += msg + } + ).catch(function(err) { + latest.failtoinstall = (latest.failtoinstall || 0) + 1 + return Promise.reject(err) + }) + + if (!log.endsWith('\n')) { + log += '\n' + } + if (!log.endsWith('\n\n')) { + log += '\n' + } + + } else { + log += this.updateLog('Release did not contain package.json, skipping npm install. ') + '\n' + } } catch (err) { this.updating = false + log += this.updateLog(`Error: ${err.message}. `) + '\n' + if (folder && cleanup) { + await this.fs.rm(folder, { force: true, recursive: true }).catch((err) => { + this.updateLog(`Error while cleaning up: ${err.message}. `) + }) + } + if (latest) { + latest.log = log + } return Promise.reject(err) } + + log += this.updateLog(`Finished updating ${this.name} to version ${latest.version}.`) + '\n' + this.db.data.core[this.name].latestInstalled = latest.version + latest.log = log + this.updating = false } } \ No newline at end of file diff --git a/core/db.mjs b/core/db.mjs index 40506f6..40e1d60 100644 --- a/core/db.mjs +++ b/core/db.mjs @@ -48,8 +48,9 @@ export default function GetDB(config, log, orgFilename = 'db.json') { col[i] = item return } + } else { + item[db.id] = db.createId(col) } - item[db.id] = db.createId(col) col.push(item) } diff --git a/core/providers/git.mjs b/core/providers/git.mjs index a60da98..437a3fe 100644 --- a/core/providers/git.mjs +++ b/core/providers/git.mjs @@ -32,6 +32,7 @@ export default class GitProvider { version: item.name, link: asset.browser_download_url, filename: asset.name, + description: item.body, log: '', } } diff --git a/core/util.mjs b/core/util.mjs index 2cfaacc..9722f04 100644 --- a/core/util.mjs +++ b/core/util.mjs @@ -70,19 +70,25 @@ export default class Util { runCommand(command, options = [], folder = null, stream = function() {}) { return new Promise(function(res, rej) { - stream(`[Command] ${folder ? folder : ''}${command} ${options.join(' ')}\n`) + let fullcommand = path.join(folder ? folder : '', command) + if (command.indexOf('/') >= 0 || command.indexOf('\\') >= 0) { + fullcommand = command + } + stream(`[Command] ${fullcommand} ${options.join(' ')}\n`) let processor = spawn(command, options, { shell: true, cwd: folder, }) let timeOuter = setInterval(function() { - processor.stdin.write('n\n') + try { + processor.stdin.write('n\n') + } catch {} }, 250) processor.stdout.on('data', function(data) { - stream(data.toString()) + stream(data.toString().replace(/\r\n/g, '\n')) }) processor.stderr.on('data', function(data) { - stream(data.toString()) + stream(data.toString().replace(/\r\n/g, '\n')) }) processor.on('error', function(err) { clearInterval(timeOuter) diff --git a/package.json b/package.json index 24ff247..f7e84ca 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "patterns": [ "{core,test}/*" ], + "ignore": "test/testapp", "extensions": "js,mjs", "quiet": true, "inherit": true diff --git a/test/application.integration.test.mjs b/test/application.integration.test.mjs new file mode 100644 index 0000000..b83f375 --- /dev/null +++ b/test/application.integration.test.mjs @@ -0,0 +1,46 @@ +import { Eltro as t, assert, stub } from 'eltro' +import fs from 'fs/promises' +import lowdb from '../core/db.mjs' +import Application from '../core/application.mjs' +import GitProvider from '../core/providers/git.mjs' +import Util from '../core/util.mjs' + +const util = new Util(import.meta.url) +const logger = { + info: stub(), + warn: stub(), + error: stub(), +} + +t.timeout(10000).describe('Application update integration test', function() { + let db + let app + let provider + + t.before(function() { + return lowdb({ test: { } }, logger, util.getPathFromRoot('./db_test.json')).then(function(res) { + db = res + provider = new GitProvider({ url: 'https://git.nfp.is/api/v1/repos/thething/sc-helloworld/releases' }) + app = new Application(util, db, provider, 'testapp') + + return provider.getLatestVersion() + }).then(function(version) { + return fs.rm(`./test/testapp/${version.version}`, { force: true, recursive: true }) + }) + }) + + t.after(function() { + if (db.data.core.testapp.versions.length) { + return fs.rm(`./test/testapp/${db.data.core.testapp.versions[0].id}`, { force: true, recursive: true }) + } + }) + + t.test('should run update and install correctly', async function(){ + await app.update() + + assert.ok(db.data.core.testapp.latestInstalled) + await fs.stat(util.getPathFromRoot(`./testapp/${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/${db.data.core.testapp.latestInstalled}/node_modules`)) + }) +}) \ No newline at end of file diff --git a/test/application.test.mjs b/test/application.test.mjs index 7b5eb77..66bbf33 100644 --- a/test/application.test.mjs +++ b/test/application.test.mjs @@ -7,7 +7,7 @@ import Util from '../core/util.mjs' const util = new Util(import.meta.url) -var logger = { +const logger = { info: stub(), warn: stub(), error: stub(), @@ -163,12 +163,36 @@ t.timeout(250).describe('#update()', function() { let db let app let provider + let stubExtract + let stubRunCommand + let stubWrite + let stubFsMkdir + let stubFsRm + let stubFsStat t.beforeEach(function() { + util.extractFile = stubExtract = stub() + util.runCommand = stubRunCommand = stub() + + stubExtract.resolves() + stubRunCommand.resolves() + return lowdb({ test: { } }, logger, null).then(function(res) { db = res + db.write = stubWrite = stub() provider = createProvider() - app = new Application(util, db, provider, 'testapp') + app = new Application(util, db, provider, 'testapp', { + fs: { + mkdir: stubFsMkdir = stub(), + rm: stubFsRm = stub(), + stat: stubFsStat = stub(), + }, + }) + stubFsMkdir.resolves() + stubFsRm.resolves() + stubFsStat.resolves({}) + provider.downloadVersion.resolves() + provider.getLatestVersion.resolves({ version: '123456789', link: 'httplinkhere', filename: 'test.7z' }) }) }) @@ -203,12 +227,13 @@ t.timeout(250).describe('#update()', function() { db.data.core.testapp.updater = '' let err = await assert.isRejected(app.update()) - assert.strictEqual(err, assertError) + assert.strictEqual(app.updating, false) - + assert.strictEqual(err, assertError) assert.match(db.data.core.testapp.updater, /check/i) assert.match(db.data.core.testapp.updater, /version/i) assert.match(db.data.core.testapp.updater, new RegExp(new Date().toISOString().split('T')[0])) + assert.match(db.data.core.testapp.updater, new RegExp(assertError.message)) }) t.test('should call provider download latest correctly if new 7zip version', async function() { @@ -216,17 +241,16 @@ t.timeout(250).describe('#update()', function() { const assertLink = 'All of you' const assertVersion = { version: '123456789', link: assertLink, filename: 'test.7z' } const assertTarget = util.getPathFromRoot('./testapp/123456789/file.7z') - - await assert.isRejected(fs.stat('./test/testapp/123456789')) + assert.strictEqual(db.data.core.testapp.versions.length, 0) provider.getLatestVersion.resolves(assertVersion) provider.downloadVersion.rejects(assertError) db.data.core.testapp.updater = '' let err = await assert.isRejected(app.update()) - assert.strictEqual(err, assertError) + assert.strictEqual(app.updating, false) - + assert.strictEqual(err, assertError) assert.match(db.data.core.testapp.updater, /found/i) assert.match(db.data.core.testapp.updater, new RegExp(assertVersion.version)) assert.match(db.data.core.testapp.updater, /downloading/i) @@ -234,8 +258,29 @@ t.timeout(250).describe('#update()', function() { assert.match(db.data.core.testapp.updater, new RegExp(assertTarget.replace(/\\/g, '\\\\'))) assert.strictEqual(provider.downloadVersion.firstCall[0], assertVersion) assert.strictEqual(provider.downloadVersion.firstCall[1], assertTarget) + assert.match(db.data.core.testapp.updater, new RegExp(assertError.message)) - await fs.stat('./test/testapp/123456789') + assert.strictEqual(db.data.core.testapp.versions.length, 1) + assert.strictEqual(db.data.core.testapp.versions[0], assertVersion) + assert.ok(assertVersion.log) + assert.match(assertVersion.log, /\. \n/) + assert.match(assertVersion.log, new RegExp(assertError.message)) + assert.ok(assertVersion.log.endsWith('\n')) + assert.strictEqual(assertVersion.failtodownload, 1) + + assert.ok(stubFsMkdir.called) + assert.match(stubFsMkdir.firstCall[0], /123456789/) + assert.ok(stubFsMkdir.firstCall[1]?.recursive) + + // Test if subsequent calls increment counter + + err = await assert.isRejected(app.update()) + + assert.strictEqual(app.updating, false) + assert.strictEqual(err, assertError) + assert.strictEqual(db.data.core.testapp.versions.length, 1) + assert.strictEqual(db.data.core.testapp.versions[0], assertVersion) + assert.strictEqual(assertVersion.failtodownload, 2) }) t.test('should call provider download latest correctly if new 7zip version', async function() { @@ -243,17 +288,16 @@ t.timeout(250).describe('#update()', function() { const assertLink = 'All of you' const assertVersion = { version: '123456789', link: assertLink, filename: 'test.7z' } const assertTarget = util.getPathFromRoot('./testapp/123456789/file.7z') - - await assert.isRejected(fs.stat('./test/testapp/123456789')) + assert.strictEqual(db.data.core.testapp.versions.length, 0) provider.getLatestVersion.resolves(assertVersion) provider.downloadVersion.rejects(assertError) db.data.core.testapp.updater = '' let err = await assert.isRejected(app.update()) - assert.strictEqual(err, assertError) + assert.strictEqual(app.updating, false) - + assert.strictEqual(err, assertError) assert.match(db.data.core.testapp.updater, /found/i) assert.match(db.data.core.testapp.updater, new RegExp(assertVersion.version)) assert.match(db.data.core.testapp.updater, /downloading/i) @@ -261,8 +305,265 @@ t.timeout(250).describe('#update()', function() { assert.match(db.data.core.testapp.updater, new RegExp(assertTarget.replace(/\\/g, '\\\\'))) assert.strictEqual(provider.downloadVersion.firstCall[0], assertVersion) assert.strictEqual(provider.downloadVersion.firstCall[1], assertTarget) + assert.match(db.data.core.testapp.updater, new RegExp(assertError.message)) - await fs.stat('./test/testapp/123456789') + assert.strictEqual(db.data.core.testapp.versions.length, 1) + assert.strictEqual(db.data.core.testapp.versions[0], assertVersion) + assert.ok(assertVersion.log) + assert.match(assertVersion.log, /\. \n/) + assert.match(assertVersion.log, new RegExp(assertError.message)) + assert.ok(assertVersion.log.endsWith('\n')) + assert.strictEqual(assertVersion.failtodownload, 1) + + assert.ok(stubFsRm.called) + assert.match(stubFsRm.firstCall[0], /123456789/) + assert.ok(stubFsRm.firstCall[1]?.recursive) + assert.ok(stubFsRm.firstCall[1]?.force) + + // Test if subsequent calls increment counter + + err = await assert.isRejected(app.update()) + + assert.strictEqual(app.updating, false) + assert.strictEqual(err, assertError) + assert.strictEqual(db.data.core.testapp.versions.length, 1) + assert.strictEqual(db.data.core.testapp.versions[0], assertVersion) + assert.strictEqual(assertVersion.failtodownload, 2) + }) + + t.test('should call extract on util correctly', async function() { + const assertExtractText = 'Reverdations of Success' + const assertError = new Error('Dai Gekisen') + const assertTarget = util.getPathFromRoot('./testapp/123456789/file.7z') + + stubExtract.returnWith(function(target, stream) { + stream(assertExtractText) + return Promise.reject(assertError) + }) + assert.strictEqual(db.data.core.testapp.versions.length, 0) + + let err = await assert.isRejected(app.update()) + + assert.strictEqual(app.updating, false) + assert.strictEqual(err, assertError) + assert.strictEqual(app.updating, false) + assert.strictEqual(stubExtract.firstCall[0], assertTarget) + + assert.notOk(stubWrite.called) + assert.match(db.data.core.testapp.updater, new RegExp('extracting[^.]+file\.7z', 'i')) + assert.match(db.data.core.testapp.updater, new RegExp(assertError.message)) + + assert.ok(stubFsRm.called) + assert.match(stubFsRm.firstCall[0], /123456789/) + assert.ok(stubFsRm.firstCall[1]?.recursive) + assert.ok(stubFsRm.firstCall[1]?.force) + + assert.strictEqual(db.data.core.testapp.versions.length, 1) + let version = db.data.core.testapp.versions[0] + assert.ok(version.log) + assert.match(version.log, /\. \n/) + assert.match(version.log, new RegExp('extracting[^.]+file\.7z', 'i')) + assert.match(version.log, new RegExp(assertError.message)) + assert.match(version.log, new RegExp(assertExtractText)) + assert.ok(version.log.endsWith('\n')) + assert.strictEqual(version.failtodownload, 1) + + // Test if subsequent calls increment counter + + err = await assert.isRejected(app.update()) + + assert.strictEqual(app.updating, false) + assert.strictEqual(err, assertError) + assert.strictEqual(db.data.core.testapp.versions.length, 1) + assert.strictEqual(db.data.core.testapp.versions[0], version) + assert.strictEqual(version.failtodownload, 2) + }) + + t.test('should not call npm install if stat fails to find index.mjs', async function() { + const assertError = new Error('File not found') + const assertTarget = util.getPathFromRoot('./testapp/123456789/index.mjs') + stubRunCommand.rejects(new Error('should not be seen')) + stubFsStat.rejects(assertError) + assert.strictEqual(db.data.core.testapp.versions.length, 0) + + let err = await assert.isRejected(app.update()) + + assert.strictEqual(app.updating, false) + assert.ok(stubExtract.called) + assert.strictEqual(err, assertError) + assert.strictEqual(stubFsStat.firstCall[0], assertTarget) + assert.match(db.data.core.testapp.updater, /index\.mjs/i) + assert.match(db.data.core.testapp.updater, /missing/i) + + assert.strictEqual(db.data.core.testapp.versions.length, 1) + let version = db.data.core.testapp.versions[0] + assert.ok(version.log) + assert.match(version.log, /index\.mjs/i) + assert.match(version.log, /missing/i) + assert.ok(version.log.endsWith('\n')) + assert.strictEqual(version.failtodownload, 1) + + // Test if subsequent calls increment counter + + err = await assert.isRejected(app.update()) + + assert.strictEqual(app.updating, false) + assert.strictEqual(err, assertError) + assert.strictEqual(db.data.core.testapp.versions.length, 1) + assert.strictEqual(db.data.core.testapp.versions[0], version) + assert.strictEqual(version.failtodownload, 2) + }) + + t.test('should not call npm install if package.json is missing but shuld pass', async function() { + const assertError = new Error('File not found') + const assertTarget = util.getPathFromRoot('./testapp/123456789/package.json') + stubRunCommand.rejects(new Error('should not be seen')) + stubFsStat.returnWith(function(path) { + if (path.endsWith('package.json')) { + return Promise.reject(assertError) + } + return Promise.resolve({}) + }) + assert.strictEqual(db.data.core.testapp.versions.length, 0) + + await app.update() + + assert.strictEqual(app.updating, false) + + assert.strictEqual(stubFsStat.callCount, 2) + assert.strictEqual(stubFsStat.secondCall[0], assertTarget) + assert.ok(stubExtract.called) + assert.notOk(stubRunCommand.called) + assert.match(db.data.core.testapp.updater, /package\.json/i) + assert.match(db.data.core.testapp.updater, /contain/i) + + assert.strictEqual(db.data.core.testapp.versions.length, 1) + let version = db.data.core.testapp.versions[0] + assert.ok(version.log) + assert.match(version.log, /package\.json/i) + assert.match(version.log, /contain/i) + assert.ok(version.log.endsWith('\n')) + assert.ok(db.data.core.testapp.latestInstalled) + assert.match(version.log, /finished/i) + assert.match(version.log, /updating/i) + + // Test if subsequent calls do nothing + + provider.downloadVersion.reset() + + await app.update() + + assert.strictEqual(db.data.core.testapp.versions.length, 1) + assert.notOk(provider.downloadVersion.called) + assert.match(db.data.core.testapp.updater, /already/i) + assert.match(db.data.core.testapp.updater, /nothing/i) + }) + + t.test('should otherwise call npm install correctly', async function() { + const assertExtractText = 'Egao no Hikair ni Tsutsumarete' + const assertNpmText = 'Dadadadash' + const assertVersion = { version: '123456789', link: 'somelinkhere', filename: 'test.7z' } + const assertError = new Error('Nagisa') + const assertTarget = util.getPathFromRoot('./testapp/123456789') + provider.getLatestVersion.resolves(assertVersion) + assert.strictEqual(db.data.core.testapp.versions.length, 0) + assert.notOk(stubWrite.called) + + stubExtract.returnWith(function(target, stream) { + stream(assertExtractText) + return Promise.resolve() + }) + stubRunCommand.returnWith(function(command, options, folder, stream) { + stream(assertNpmText) + return Promise.reject(assertError) + }) + + let err = await assert.isRejected(app.update()) + + assert.strictEqual(app.updating, false) + assert.strictEqual(err, assertError) + assert.strictEqual(stubRunCommand.firstCall[0], 'npm.cmd') + assert.ok(stubRunCommand.firstCall[1]) + assert.strictEqual(stubRunCommand.firstCall[1][0], 'install') + assert.ok(stubRunCommand.firstCall[1].includes('--production'), 'should have --production') + assert.ok(stubRunCommand.firstCall[1].includes('--no-optional'), 'should have --no-optional') + assert.ok(stubRunCommand.firstCall[1].includes('--no-package-lock'), 'should have --no-package-lock') + assert.ok(stubRunCommand.firstCall[1].includes('--no-audit'), 'should have --no-audit') + assert.strictEqual(stubRunCommand.firstCall[2], assertTarget) + + assert.notOk(stubFsRm.called) + + assert.match(db.data.core.testapp.updater, /npm/i) + assert.match(db.data.core.testapp.updater, /install/i) + assert.strictEqual(db.data.core.testapp.versions.length, 1) + assert.strictEqual(db.data.core.testapp.versions[0], assertVersion) + assert.ok(assertVersion.log) + assert.match(assertVersion.log, /\. \n/) + assert.match(assertVersion.log, new RegExp(assertExtractText)) + assert.match(assertVersion.log, new RegExp(assertNpmText)) + assert.match(assertVersion.log, new RegExp(assertError.message)) + assert.match(assertVersion.log, /npm/i) + assert.match(assertVersion.log, /install/i) + assert.ok(assertVersion.log.endsWith('\n')) + assert.strictEqual(assertVersion.failtoinstall, 1) + + // Test if subsequent calls increment counter + + err = await assert.isRejected(app.update()) + + assert.strictEqual(app.updating, false) + assert.strictEqual(err, assertError) + assert.strictEqual(db.data.core.testapp.versions.length, 1) + assert.strictEqual(db.data.core.testapp.versions[0], assertVersion) + assert.strictEqual(assertVersion.failtoinstall, 2) + }) + + t.test('should update latest installed correctly', async function() { + const assertVersion = { version: '123456789', link: 'httplinkhere', filename: 'test.7z' } + provider.getLatestVersion.resolves(assertVersion) + assert.notStrictEqual(db.data.core.testapp.latestInstalled, assertVersion.version) + assert.strictEqual(db.data.core.testapp.versions.length, 0) + + await app.update() + + assert.strictEqual(app.updating, false) + assert.strictEqual(db.data.core.testapp.latestInstalled, assertVersion.version) + assert.strictEqual(db.data.core.testapp.versions.length, 1) + assert.strictEqual(db.data.core.testapp.versions[0], assertVersion) + assert.ok(assertVersion.log) + assert.match(assertVersion.log, /found/i) + assert.match(assertVersion.log, new RegExp(assertVersion.version)) + assert.match(assertVersion.log, /downloading/i) + assert.match(assertVersion.log, new RegExp('extracting[^.]+file\.7z', 'i')) + assert.match(assertVersion.log, /finished/i) + assert.match(assertVersion.log, /updating/i) + }) + + t.test('should update existing version if found', async function() { + const assertNewLink = 'THE last pain' + const assertNewFilename = 'The place of hope.7z' + const oldLog = 'The Smell of Sea\n' + const assertVersion = { version: '123456789', link: 'httplinkhere', filename: 'test.7z', log: oldLog } + + assertVersion.id = assertVersion.version + db.upsert(db.data.core.testapp.versions, assertVersion) + + provider.getLatestVersion.resolves({ version: assertVersion.version, link: assertNewLink, filename: assertNewFilename }) + assert.strictEqual(db.data.core.testapp.versions.length, 1) + + await app.update() + + assert.strictEqual(app.updating, false) + assert.strictEqual(db.data.core.testapp.versions.length, 1) + assert.strictEqual(db.data.core.testapp.versions[0], assertVersion) + assert.ok(assertVersion.log) + assert.ok(assertVersion.log.startsWith(oldLog)) + assert.match(assertVersion.log, /found/i) + assert.match(assertVersion.log, new RegExp(assertVersion.version)) + assert.match(assertVersion.log, /downloading/i) + assert.match(assertVersion.log, new RegExp('extracting[^.]+file\.7z', 'i')) + assert.match(assertVersion.log, /finished/i) + assert.match(assertVersion.log, /updating/i) }) t.test('should do nothing if latestInstalled matches version', async function() { @@ -274,8 +575,44 @@ t.timeout(250).describe('#update()', function() { db.data.core.testapp.latestInstalled = assertVersion.version await app.update() + + assert.strictEqual(app.updating, false) assert.notOk(provider.downloadVersion.called) assert.match(db.data.core.testapp.updater, /already/i) assert.match(db.data.core.testapp.updater, /nothing/i) }) + + t.test('should do nothing it exists and failtodownload is higher than 3', async function() { + const assertError = new Error('should not be seen') + const assertVersion = { version: '999.888.777.666', filename: 'test.7z' } + provider.getLatestVersion.resolves(assertVersion) + provider.downloadVersion.rejects(assertError) + 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 }) + + await app.update() + + assert.strictEqual(app.updating, false) + assert.notOk(provider.downloadVersion.called) + assert.match(db.data.core.testapp.updater, /many/i) + assert.match(db.data.core.testapp.updater, /fail/i) + assert.match(db.data.core.testapp.updater, /skip/i) + }) + + t.test('should do nothing it exists and failtoinstall is higher than 3', async function() { + const assertError = new Error('should not be seen') + const assertVersion = { version: '999.888.777.666', filename: 'test.7z' } + provider.getLatestVersion.resolves(assertVersion) + provider.downloadVersion.rejects(assertError) + 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 }) + + await app.update() + + assert.strictEqual(app.updating, false) + assert.notOk(provider.downloadVersion.called) + assert.match(db.data.core.testapp.updater, /many/i) + assert.match(db.data.core.testapp.updater, /fail/i) + assert.match(db.data.core.testapp.updater, /skip/i) + }) }) diff --git a/test/db.test.mjs b/test/db.test.mjs index 2e5e721..3eea1f4 100644 --- a/test/db.test.mjs +++ b/test/db.test.mjs @@ -271,3 +271,17 @@ t.test('should have basic database-like functions with string-like name of colle assert.strictEqual(dbSec.data.myarr.length, 1) assert.strictEqual(dbSec.get('myarr', assertItem1.id), null) }) + +t.test('#upsert() should work properly', async function() { + let db = await lowdb({}, logger, null) + db.data.test = { + items: [] + } + + db.upsert(db.data.test.items, { id: '1234', text: '1' }) + db.upsert(db.data.test.items, { id: '1234', text: '2' }) + + assert.strictEqual(db.data.test.items.length, 1) + assert.strictEqual(db.data.test.items[0].id, '1234') + assert.strictEqual(db.data.test.items[0].text, '2') +}) diff --git a/test/providers/git.integration.test.mjs b/test/providers/git.integration.test.mjs index 6b00b84..e6d036a 100644 --- a/test/providers/git.integration.test.mjs +++ b/test/providers/git.integration.test.mjs @@ -15,6 +15,7 @@ t.timeout(5000).describe('Git integration', function() { let version = await provider.getLatestVersion() assert.ok(version) assert.ok(version.version) + assert.ok(version.description) assert.ok(version.link) assert.match(version.link, /\/attachments\//) }) diff --git a/test/util.test.mjs b/test/util.test.mjs index 2253a01..15520b8 100644 --- a/test/util.test.mjs +++ b/test/util.test.mjs @@ -233,6 +233,9 @@ t.describe('#extractFile()', function() { t.test('should stream the process of extracting', async function() { let output = '' await util.extractFile(util.getPathFromRoot('./testapp/example.tar.gz'), function(msg) { output += msg + '\n' }) - console.log(output) + + assert.match(output, /Extracting archive\:.+example.tar.gz/) + assert.match(output, /1 file, 123 bytes/) + assert.strictEqual(output.indexOf('\r\n'), -1) }) })