Publicētais avots
Lejupielādēt avota ZIP
CH-J Server Manager
Pārlūkot mapes un failus konkrētai lietojumprogrammas izdošanai.
CH-J / Server Manager
368 faili
core-20261017T201717Z-057348c4a70f
Pievienots: Datums nav reģistrēts · Būvēts:
1
"use strict";2
// End-to-end UI check of chj.system-monitor with the real plugin runtime and preload.3
// Linux (default): disposable privileged Docker container (image CHJ_USERS_IMAGE, default chj-users-it-debian);4
// creates and deletes a swap file on a loop-mounted ext4 through the UI forms (sudo dialog).5
// Windows: CHJ_SMOKE_WINDOWS=1 with CHJ_USERS_WINDOWS_HOST/_USER/_FINGERPRINT and _PASSWORD or _KEY;6
// sets a manual pagefile (pending restart only) and restores automatic management. Never restarts Windows.7
// Run: npx electron scripts/smokeSystemMonitorUi.js [screenshot-dir]8
const { app, BrowserWindow, ipcMain, protocol } = require("electron");9
const assert = require("node:assert/strict");10
const fs = require("node:fs");11
const os = require("node:os");12
const path = require("node:path");13
const { execFileSync, spawnSync } = require("node:child_process");14
const { hardenSession } = require("../src/main/bootstrap/createMainWindow");15
const { PluginRegistry } = require("../src/main/plugins/pluginRegistry");16
const { PluginRuntime } = require("../src/main/plugins/pluginRuntime");17
const { SessionManager } = require("../src/main/sessions/sessionManager");18
const { PrivilegedExecutor } = require("../src/main/sessions/privilegedExec");19
const { VirtualMemoryService } = require("../src/main/system/virtualMemoryService");21
const env = process.env;22
const windows = env.CHJ_SMOKE_WINDOWS === "1";23
const container = `chj-sysmon-ui-${process.pid}`;24
const root = fs.mkdtempSync(path.join(os.tmpdir(), "chj-sysmon-ui-"));25
const shots = process.argv.find((arg, index) => index > 1 && !arg.startsWith("-") && !arg.endsWith(".js")) || null;26
app.setPath("userData", root);27
protocol.registerSchemesAsPrivileged([{ scheme: "chj-plugin", privileges: { standard: true, secure: true, supportFetchAPI: true } }]);28
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));29
const errors = [];30
let window;31
let restoreWindows = async () => {};32
const js = (source) => window.webContents.executeJavaScript(source);33
async function until(source, timeout = 60000) {34
const started = Date.now();35
while (Date.now() - started < timeout) { if (await js(`(() => { try { return (${source}); } catch { return false; } })()`)) return; await delay(100); }36
throw new Error(`UI condition timed out: ${source}\nstatus: ${await js("document.querySelector('#status').textContent + ' | ' + (document.querySelector('#vmStatus')?.textContent || '')")}`);37
}38
async function shot(name) { if (shots) { fs.mkdirSync(shots, { recursive: true }); fs.writeFileSync(path.join(shots, `${name}.png`), (await window.webContents.capturePage()).toPNG()); } }39
async function confirm() { await until("document.querySelector('#confirmDialog').open"); await js("document.querySelector('#confirmForm').requestSubmit()"); }40
async function sudo() { await until("document.querySelector('#sudoDialog').open"); await js("document.querySelector('#sudoPassword').value = 'AdminPass-1'; document.querySelector('#sudoForm').requestSubmit();"); }42
async function run() {43
let profile; let password = "";44
if (windows) {45
profile = { id: "w", label: "Windows", host: env.CHJ_USERS_WINDOWS_HOST, port: 22, username: env.CHJ_USERS_WINDOWS_USER, authMethod: env.CHJ_USERS_WINDOWS_KEY ? "privateKey" : "password", privateKeyPath: env.CHJ_USERS_WINDOWS_KEY };46
password = env.CHJ_USERS_WINDOWS_PASSWORD || "";47
} else {48
execFileSync("docker", ["run", "-d", "--rm", "--privileged", "--name", container, "-p", "127.0.0.1::22", env.CHJ_USERS_IMAGE || "chj-users-it-debian"]);49
await delay(1500);50
spawnSync("docker", ["exec", container, "sh", "-c", "mkdir -p /swap && truncate -s 3G /img && mkfs.ext4 -q /img && mount -o loop /img /swap && : > /etc/fstab"]);51
const port = Number(execFileSync("docker", ["port", container, "22/tcp"], { encoding: "utf8" }).trim().split(":").pop());52
profile = { id: "l", label: "Linux test", host: "127.0.0.1", port, username: "admin", authMethod: "password" };53
password = "AdminPass-1";54
}55
await app.whenReady(); hardenSession();56
const hostKeys = new Map();57
if (windows) hostKeys.set(profile.port, Buffer.from(`${env.CHJ_USERS_WINDOWS_FINGERPRINT}=`, "base64").toString("hex"));58
const profileService = { get: () => profile, getHostKey: (_h, p) => hostKeys.get(p) || null, trustHostKey: (_h, p, fp) => hostKeys.set(p, fp), getStoredPassword: () => password, markUsed() {} };59
const sessionManager = new SessionManager({ profileService, latencyMonitor: { start: () => () => {} } });60
try { await sessionManager.connect({ sessionId: "ui", profileId: profile.id }); }61
catch (error) { sessionManager.trustPending({ sessionId: "ui", profileId: profile.id, fingerprint: error.fingerprint }); await sessionManager.connect({ sessionId: "ui", profileId: profile.id }); }62
const virtualMemory = new VirtualMemoryService({ sessionManager, privilegedExecutor: new PrivilegedExecutor({ sessionManager }) });63
const original = windows ? await virtualMemory.read("ui") : null;64
// Restores automatic pagefile management even when an assertion fails.65
restoreWindows = async () => { if (windows && original?.automatic) { const now = await virtualMemory.read("ui"); if (now.automatic !== true) await virtualMemory.manage("ui", { action: "automatic" }); } };66
const registry = new PluginRegistry(root, null, { bundledRoot: path.join(__dirname, "../src/main/firstPartyPlugins") });67
const runtime = new PluginRuntime({ BrowserWindow, registry, sessionManager, virtualMemory, preload: path.join(__dirname, "../src/preload/pluginPreload.js"), getMainWindow: () => null, isVaultUnlocked: () => true });68
runtime.registerIpc(ipcMain);69
runtime.open("chj.system-monitor");70
window = runtime.windows.get("chj.system-monitor");71
window.webContents.on("console-message", (event) => { if (event.level === "error") errors.push(event.message); });72
window.setSize(1320, 1000);73
await until("document.querySelector('#status').textContent.includes('Aktualizováno')");74
await delay(5600);75
await until("document.querySelector('#cpu').textContent.includes('%')", 20000);76
if (windows) {77
assert.equal(await js("document.querySelector('#swapLabel').textContent"), "Pagefile");78
assert.equal(await js("document.querySelector('#kernelLabel').textContent"), "Sestavení");79
assert.equal(await js("document.querySelector('#load').textContent"), "nedostupné", "no fake load average");80
} else {81
assert.equal(await js("document.querySelector('#diskLabel').textContent"), "Disk /");82
}83
await js("document.querySelector('#memorySection').open = true");84
await delay(400);85
assert.ok(await js("document.querySelectorAll('#ramStack i').length >= 4"), "RAM breakdown rendered");86
await shot(windows ? "s01-windows-overview" : "s01-linux-overview");87
await js("document.querySelector('#memorySection').scrollIntoView()");88
await shot(windows ? "s02-windows-memory" : "s02-linux-memory");89
await js("document.querySelector('#manageVmButton').click()");90
await until("document.querySelector('#vmDialog').open && document.querySelector('#vmContent table')");91
await shot(windows ? "s03-windows-manage" : "s03-linux-manage");92
if (windows) {93
await js("document.querySelector('#pfInitialValue').value = '1024'; document.querySelector('#pfMaximumValue').value = '2048'; Array.from(document.querySelectorAll('#vmContent button')).find(b => b.textContent.includes('Uložit')).click();");94
await confirm();95
await until("document.querySelector('#vmStatus').textContent.toLowerCase().includes('čeká na restart')", 120000);96
assert.match(await js("document.querySelector('#vmContent').textContent"), /Čeká na restart/);97
await shot("s04-windows-pending");98
if (original.automatic) {99
await js("Array.from(document.querySelectorAll('#vmContent button')).find(b => b.textContent.includes('automatickou')).click()");100
await confirm();101
await until("document.querySelector('#vmStatus').textContent.includes('Uloženo')", 120000);102
const restored = await virtualMemory.read("ui");103
assert.equal(restored.automatic, true); assert.equal(restored.restartPending, false, "reverting clears the pending state");104
}105
} else {106
await js("document.querySelector('#swapDir').value = '/swap'; document.querySelector('#swapName').value = 'ui-swap'; document.querySelector('#swapSizeValue').value = '256'; document.querySelector('#swapSizeUnit').value = 'MiB'; document.querySelector('#swapPersist').checked = true;");107
await js("Array.from(document.querySelectorAll('#vmContent button')).find(b => b.textContent.includes('Vytvořit')).click()");108
await confirm(); await sudo();109
await until("document.querySelector('#vmStatus').textContent.includes('Provedeno')", 120000);110
assert.match(spawnSync("docker", ["exec", container, "cat", "/proc/swaps"], { encoding: "utf8" }).stdout, /\/swap\/ui-swap/);111
await until("document.querySelector('#vmContent').textContent.includes('/swap/ui-swap')");112
await shot("s04-linux-created");113
await js("Array.from(document.querySelectorAll('#vmContent tr')).find(r => r.textContent.includes('/swap/ui-swap')).querySelector('button.danger').click()");114
await confirm(); await sudo();115
await until("document.querySelector('#vmStatus').textContent.includes('Provedeno')", 120000);116
assert.doesNotMatch(spawnSync("docker", ["exec", container, "cat", "/proc/swaps"], { encoding: "utf8" }).stdout, /ui-swap/);117
assert.equal(spawnSync("docker", ["exec", container, "cat", "/etc/fstab"], { encoding: "utf8" }).stdout, "");118
}119
assert.deepEqual(errors, [], "no renderer errors");120
await sessionManager.disconnectAll();121
console.log(`chj.system-monitor ${windows ? "Windows" : "Linux"} UI smoke passed`);122
}124
function cleanup() { if (!windows) spawnSync("docker", ["rm", "-f", container]); fs.rmSync(root, { recursive: true, force: true }); }125
run().then(() => { cleanup(); app.exit(0); }, async (error) => {126
console.error(error);127
try { await restoreWindows(); } catch (restoreError) { console.error("Pagefile restore failed", restoreError); }128
cleanup(); app.exit(1);129
});SHA-256
78112a3d2ea3c7905e55c7900fd567d614dd445ff79f97fbd03faacca45c668bCH-J Proprietary Software License 1.14 · Avots ir sniegts saskaņā ar CH-J Proprietary Software License 1.14. Tā pieejamība nemaina licences noteikumus un nepiešķir papildu tiesības.
Arhīvs SHA-256
cf4455b698f0f28e456a37b1834976a0194d8486acb7101052d59a838745cca3