CH-J Server Managerbainisteoireacht freastalaí SSH
Roghchlár
Foinse foilsithe

CH-J Server Manager

Brabhsáil comhadlanna agus comhaid chun feidhmchlár áirithe a scaoileadh.

Íosluchtaigh foinse ZIP
CH-J / Server Manager 368 Comhaid
core-20261017T201717Z-057348c4a70f Suimigh: Dáta gan taifeadadh · Tógtha:
smokeSystemMonitorUi.js Suimigh: Dáta gan taifeadadh 9.9 KB · 129 líne
Cód Íosluchtaigh comhad
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]
8const { app, BrowserWindow, ipcMain, protocol } = require("electron");
9const assert = require("node:assert/strict");
10const fs = require("node:fs");
11const os = require("node:os");
12const path = require("node:path");
13const { execFileSync, spawnSync } = require("node:child_process");
14const { hardenSession } = require("../src/main/bootstrap/createMainWindow");
15const { PluginRegistry } = require("../src/main/plugins/pluginRegistry");
16const { PluginRuntime } = require("../src/main/plugins/pluginRuntime");
17const { SessionManager } = require("../src/main/sessions/sessionManager");
18const { PrivilegedExecutor } = require("../src/main/sessions/privilegedExec");
19const { VirtualMemoryService } = require("../src/main/system/virtualMemoryService");
21const env = process.env;
22const windows = env.CHJ_SMOKE_WINDOWS === "1";
23const container = `chj-sysmon-ui-${process.pid}`;
24const root = fs.mkdtempSync(path.join(os.tmpdir(), "chj-sysmon-ui-"));
25const shots = process.argv.find((arg, index) => index > 1 && !arg.startsWith("-") && !arg.endsWith(".js")) || null;
26app.setPath("userData", root);
27protocol.registerSchemesAsPrivileged([{ scheme: "chj-plugin", privileges: { standard: true, secure: true, supportFetchAPI: true } }]);
28const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
29const errors = [];
30let window;
31let restoreWindows = async () => {};
32const js = (source) => window.webContents.executeJavaScript(source);
33async 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 || '')")}`);
38async function shot(name) { if (shots) { fs.mkdirSync(shots, { recursive: true }); fs.writeFileSync(path.join(shots, `${name}.png`), (await window.webContents.capturePage()).toPNG()); } }
39async function confirm() { await until("document.querySelector('#confirmDialog').open"); await js("document.querySelector('#confirmForm').requestSubmit()"); }
40async function sudo() { await until("document.querySelector('#sudoDialog').open"); await js("document.querySelector('#sudoPassword').value = 'AdminPass-1'; document.querySelector('#sudoForm').requestSubmit();"); }
42async 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`);
124function cleanup() { if (!windows) spawnSync("docker", ["rm", "-f", container]); fs.rmSync(root, { recursive: true, force: true }); }
125run().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-25678112a3d2ea3c7905e55c7900fd567d614dd445ff79f97fbd03faacca45c668b

CH-J Proprietary Software License 1.14 · Tá Foinse ar fáil faoin CH-J Proprietary Software License 1.14. Ní chuireann a infhaighteacht a athrú ar na téarmaí ceadúnais nó cearta breise a dheonú.

Cartlann SHA-256cf4455b698f0f28e456a37b1834976a0194d8486acb7101052d59a838745cca3
Comhaid