mirror of
https://github.com/UNITRONIX/BetterDesk.git
synced 2026-09-10 17:45:42 +00:00
29d03492fb
Harden native, agent and Docker lifecycle paths with tracked update verification, rollback and preflight checks, safe uninstall semantics, and health verification. Add shared protocol tests, installer CI gates, and lifecycle documentation. Thanks: INSOLVE (Honorary); Marco Jakobs (@jacotec); MyNameisStitch (@MyNameisStitch); Redspin (@playerumpknow)
121 lines
4.0 KiB
JavaScript
121 lines
4.0 KiB
JavaScript
'use strict';
|
|
|
|
const fs = require('fs');
|
|
const os = require('os');
|
|
const path = require('path');
|
|
const { upsertEnvKey } = require('../lib/envMerge');
|
|
|
|
function loadUpdateService({ dataDir, branch }) {
|
|
jest.resetModules();
|
|
if (branch !== undefined) {
|
|
process.env.UPDATE_GITHUB_BRANCH = branch;
|
|
} else {
|
|
delete process.env.UPDATE_GITHUB_BRANCH;
|
|
}
|
|
|
|
jest.doMock('../config/config', () => ({
|
|
isDocker: false,
|
|
dataDir,
|
|
appVersion: '3.0.0-test',
|
|
keysPath: path.join(dataDir, 'keys'),
|
|
}));
|
|
|
|
// eslint-disable-next-line global-require
|
|
return require('../services/updateService');
|
|
}
|
|
|
|
describe('envMerge upsertEnvKey', () => {
|
|
test('appends missing UPDATE_GITHUB_BRANCH key', () => {
|
|
const out = upsertEnvKey('PORT=5000\n', 'UPDATE_GITHUB_BRANCH', 'dev');
|
|
expect(out).toContain('UPDATE_GITHUB_BRANCH=dev');
|
|
});
|
|
|
|
test('replaces existing UPDATE_GITHUB_BRANCH key', () => {
|
|
const out = upsertEnvKey('UPDATE_GITHUB_BRANCH=main\nPORT=5000\n', 'UPDATE_GITHUB_BRANCH', 'dev');
|
|
expect(out).toContain('UPDATE_GITHUB_BRANCH=dev');
|
|
expect(out).not.toMatch(/UPDATE_GITHUB_BRANCH=main/);
|
|
});
|
|
});
|
|
|
|
describe('updateService update channel', () => {
|
|
let tmpRoot;
|
|
let dataDir;
|
|
|
|
beforeEach(() => {
|
|
tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'bd-update-channel-'));
|
|
dataDir = path.join(tmpRoot, 'data');
|
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.resetModules();
|
|
jest.dontMock('../config/config');
|
|
delete process.env.UPDATE_GITHUB_BRANCH;
|
|
fs.rmSync(tmpRoot, { recursive: true, force: true });
|
|
});
|
|
|
|
test('defaults to stable main branch', () => {
|
|
const updateService = loadUpdateService({ dataDir });
|
|
expect(updateService.getUpdateChannelInfo()).toEqual(expect.objectContaining({
|
|
channel: 'stable',
|
|
branch: 'main',
|
|
}));
|
|
});
|
|
|
|
test('maps dev branch to development channel', () => {
|
|
const updateService = loadUpdateService({ dataDir, branch: 'dev' });
|
|
expect(updateService.getUpdateChannelInfo()).toMatchObject({
|
|
channel: 'development',
|
|
branch: 'dev',
|
|
});
|
|
});
|
|
|
|
test('rejects invalid channel id', () => {
|
|
const updateService = loadUpdateService({ dataDir });
|
|
expect(() => updateService.setUpdateChannel('beta')).toThrow(/Invalid update channel/i);
|
|
});
|
|
|
|
test('UPDATE_CHANNELS exposes stable and development', () => {
|
|
const updateService = loadUpdateService({ dataDir });
|
|
expect(updateService.UPDATE_CHANNELS.stable.branch).toBe('main');
|
|
expect(updateService.UPDATE_CHANNELS.development.branch).toBe('dev');
|
|
});
|
|
|
|
test('reports insufficient disk space before an update', () => {
|
|
const updateService = loadUpdateService({ dataDir });
|
|
if (typeof fs.statfsSync !== 'function') {
|
|
expect(updateService.checkUpdateDiskSpace(dataDir).supported).toBe(false);
|
|
return;
|
|
}
|
|
|
|
const statfs = jest.spyOn(fs, 'statfsSync').mockReturnValue({
|
|
bavail: 1,
|
|
bsize: 4096,
|
|
});
|
|
try {
|
|
const result = updateService.checkUpdateDiskSpace(dataDir);
|
|
expect(result.supported).toBe(true);
|
|
expect(result.sufficient).toBe(false);
|
|
expect(result.availableBytes).toBe(4096);
|
|
} finally {
|
|
statfs.mockRestore();
|
|
}
|
|
});
|
|
|
|
test('does not block updates when filesystem statistics are unusable', () => {
|
|
const updateService = loadUpdateService({ dataDir });
|
|
if (typeof fs.statfsSync !== 'function') return;
|
|
|
|
const statfs = jest.spyOn(fs, 'statfsSync').mockReturnValue({});
|
|
try {
|
|
expect(updateService.checkUpdateDiskSpace(dataDir)).toMatchObject({
|
|
supported: false,
|
|
sufficient: null,
|
|
availableBytes: null,
|
|
});
|
|
} finally {
|
|
statfs.mockRestore();
|
|
}
|
|
});
|
|
});
|