| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- import { test, before, after } from 'node:test'
- import assert from 'node:assert/strict'
- import { EventEmitter } from 'node:events'
- import Module, { createRequire } from 'node:module'
- import { mkdtempSync, writeFileSync, rmSync } from 'node:fs'
- import { get } from 'node:http'
- import { join } from 'node:path'
- import { tmpdir } from 'node:os'
- import { bundleDesktopUpdater } from '../scripts/bundle-desktop-updater.mjs'
- import { DesktopAutoUpdateManager } from './auto-update-manager.mjs'
- const directory = mkdtempSync(join(tmpdir(), 'yaoyao-native-update-'))
- const bundle = join(directory, 'electron-updater.cjs')
- before(async () => bundleDesktopUpdater(bundle))
- after(() => rmSync(directory, { recursive: true, force: true }))
- const deferred = () => { let resolve, reject; const promise = new Promise((yes, no) => { resolve = yes; reject = no }); return { promise, resolve, reject } }
- const httpGet = (url, headers) => new Promise((resolve, reject) => {
- get(url, { headers, agent: false }, response => {
- const chunks = []; response.on('data', chunk => chunks.push(chunk)); response.on('error', reject)
- response.on('end', () => resolve({ status: response.statusCode, text: Buffer.concat(chunks).toString() }))
- }).on('error', reject)
- })
- function fixture(t) {
- const native = new EventEmitter(), transferred = deferred(), calls = []
- let feed
- native.setFeedURL = value => { feed = value }
- native.quitAndInstall = () => calls.push('install')
- native.checkForUpdates = () => {
- void (async () => {
- assert.equal((await httpGet(feed.url)).status, 401)
- const metadata = await httpGet(feed.url, feed.headers)
- assert.equal(metadata.status, 200)
- const zip = await httpGet(JSON.parse(metadata.text).url)
- assert.equal(zip.text, 'fixture ZIP bytes')
- transferred.resolve()
- })().catch(transferred.reject)
- }
- const load = Module._load
- let driver
- try {
- Module._load = (name, ...args) => name === 'electron' ? { autoUpdater: native } : load(name, ...args)
- const { MacUpdater } = createRequire(import.meta.url)(bundle)
- driver = new MacUpdater(null, { version: '0.4.62', quit: () => assert.fail('unexpected quit') })
- } finally { Module._load = load }
- driver.logger = { info() {}, warn() {}, error() {}, debug() {} }
- const file = join(directory, 'update.zip'); writeFileSync(file, 'fixture ZIP bytes')
- driver.checkForUpdates = async () => ({ isUpdateAvailable: true, updateInfo: { version: '0.4.63' } })
- driver.downloadUpdate = () => driver.updateDownloaded({ info: { size: 17 }, url: new URL('https://fixture.invalid/update.zip') }, { version: '0.4.63', downloadedFile: file })
- const manager = new DesktopAutoUpdateManager({ driver, version: '0.4.62', prepareInstall: async () => calls.push('cleanup') })
- t.after(async () => {
- clearTimeout(manager.stagingTimer); clearTimeout(manager.restartTimer); manager.stopChecking()
- if (driver.server?.listening) await new Promise(done => driver.server.close(done))
- native.removeAllListeners()
- })
- return { native, driver, manager, transferred, calls }
- }
- test('bundled Mac updater waits for native validation after the real ZIP proxy transfer', async t => {
- const h = fixture(t)
- await h.manager.check(); const downloading = h.manager.download()
- await h.transferred.promise
- assert.equal(h.manager.snapshot().phase, 'preparing')
- assert.equal(h.driver.squirrelDownloadedUpdate, false)
- await h.manager.install(); assert.deepEqual(h.calls, [])
- assert.throws(() => h.driver.quitAndInstall(), /not ready/)
- h.native.emit('update-downloaded'); await downloading
- assert.equal(h.manager.snapshot().phase, 'ready')
- assert.equal(h.native.listenerCount('update-downloaded'), 1)
- await h.manager.install(); await h.manager.install()
- assert.deepEqual(h.calls, ['cleanup', 'install'])
- })
- test('native signature rejection leaves no restart action and cleans temporary listeners', async t => {
- const h = fixture(t)
- await h.manager.check(); const downloading = h.manager.download()
- await h.transferred.promise
- h.native.emit('error', new Error('signature validation failed'))
- await downloading
- assert.equal(h.manager.snapshot().phase, 'failed')
- assert.equal(h.manager.snapshot().retryable, false)
- assert.equal(h.native.listenerCount('update-downloaded'), 1)
- h.native.emit('update-downloaded'); await h.manager.install()
- assert.deepEqual(h.calls, [])
- })
|