mirror of
https://github.com/Orkas-AI/Orkas.git
synced 2026-11-07 06:16:03 -10:00
Report known Linux GUI diagnostics without hiding unexpected failures
Retain raw Electron stderr and classify only bounded baseline D-Bus, font-cache and documented Sharp/GLib signatures on Linux. Unknown output, warning loops, timeouts and failed GUI cases remain fatal. Run diagnostic contract regressions in every native platform lane. Validation: 34 owning cases passed; macOS native lane passed 1,258 tests and five real GUI checks with zero GUI diagnostic findings. Fixed-range synchronization postcheck passed. The initial Linux jobs passed 1,221 native tests and all five GUI assertions but failed on unclassified environment diagnostics; their full logs are retained and compared with the successful main baseline.
This commit is contained in:
1 parent
c834f42984
commit
a7d4d2541a
4 files changed
+92
-4
No files matched your search
@@ -20,6 +20,7 @@ if (!['win32', 'darwin', 'linux'].includes(process.platform)) {
|
||||
// runs after dependency provisioning in the platform-specific Windows and
|
||||
// Linux lanes because it requires downloaded FFmpeg, model, and native payloads.
|
||||
const commonSuites = [
|
||||
'test/main/util/inspect-canary-logs.test.ts',
|
||||
'src/core-agent/test/oauth-flow.test.ts',
|
||||
'src/core-agent/test/tools.test.ts',
|
||||
'src/core-agent/test/process-session.test.ts',
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// Linux source builds retain these diagnostics in the successful main baseline
|
||||
// (GitHub Actions run 34550610580). They are warnings, not clean-runtime evidence.
|
||||
// Sharp documents the GLib collision at https://sharp.pixelplumbing.com/install/#electron-and-linux.
|
||||
const chromium = String.raw`\[\d+:\d+/\d+\.\d+:ERROR:`;
|
||||
const knownLinux = [
|
||||
['dbus-address', new RegExp(`^${chromium}dbus/bus\\.cc:\\d+\\] Failed to connect to the bus: Could not parse server address: Unknown address type \\(examples of valid types are "tcp" and on UNIX "unix"\\)$`), 20],
|
||||
['dbus-owner', new RegExp(`^${chromium}dbus/object_proxy\\.cc:\\d+\\] Failed to call method: org\\.freedesktop\\.DBus\\.NameHasOwner: object_path= /org/freedesktop/DBus: unknown error type: ?$`), 10],
|
||||
['sharp-linux', /^\(node:\d+\) \[SharpElectronLinux\] Warning: Binaries provided by Electron for use on Linux may be incompatible with sharp - see https:\/\/sharp\.pixelplumbing\.com\/install#electron-and-linux$/, 1],
|
||||
['sharp-trace', /^\(Use `electron --trace-warnings \.\.\.` to show where the warning was created\)$/, 1],
|
||||
['glib-sharp', new RegExp(`^${chromium}content/browser/browser_main_loop\\.cc:\\d+\\] GLib-GObject: g_object_(?:ref|unref): assertion 'G_IS_OBJECT \\(object\\)' failed$`), 100],
|
||||
['system-font-mtime', /^Unable to revert mtime: \/usr\/share\/fonts(?:\/truetype(?:\/(?:dejavu|lato|liberation|noto))?)?$/, 20],
|
||||
];
|
||||
|
||||
export function reviewInspectStderr(stderr, platform = process.platform) {
|
||||
const warnings = {};
|
||||
let unexpected = 0;
|
||||
for (const line of stderr.split(/\r?\n/)) {
|
||||
if (!line.trim()) continue;
|
||||
const match = platform === 'linux' && knownLinux.find(([, pattern]) => pattern.test(line));
|
||||
if (!match) { unexpected++; continue; }
|
||||
const [name, , limit] = match;
|
||||
warnings[name] = (warnings[name] || 0) + 1;
|
||||
if (warnings[name] > limit) unexpected++;
|
||||
}
|
||||
// A trace hint or GLib error without the specific Sharp warning is unexplained.
|
||||
if (!warnings['sharp-linux']) unexpected += (warnings['glib-sharp'] || 0) + (warnings['sharp-trace'] || 0);
|
||||
return { warnings, unexpected };
|
||||
}
|
||||
|
||||
export function inspectCanaryExitCode(code, timedOut, report) {
|
||||
return code || (timedOut || report.unexpected ? 1 : 0);
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import * as fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { reviewInspectStderr, inspectCanaryExitCode } from './inspect-canary-logs.mjs';
|
||||
|
||||
const here = path.dirname(fileURLToPath(import.meta.url));
|
||||
const pcDir = path.resolve(here, '../..');
|
||||
@@ -22,9 +23,15 @@ const child = spawn(require('electron'), [path.join(here, 'electron-main.mjs')],
|
||||
cwd: pcDir, env, stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true,
|
||||
});
|
||||
let stderrBytes = 0;
|
||||
let stderrText = '';
|
||||
let timedOut = false;
|
||||
child.stdout.on('data', chunk => process.stdout.write(chunk));
|
||||
child.stderr.on('data', chunk => { stderrBytes += chunk.length; process.stderr.write(chunk); });
|
||||
child.stderr.setEncoding('utf8');
|
||||
child.stderr.on('data', chunk => {
|
||||
stderrBytes += Buffer.byteLength(chunk);
|
||||
if (stderrBytes <= 1024 * 1024) stderrText += chunk;
|
||||
process.stderr.write(chunk);
|
||||
});
|
||||
const stop = () => child.kill('SIGTERM');
|
||||
const signals = ['SIGINT', 'SIGTERM', 'SIGHUP'];
|
||||
for (const signal of signals) process.on(signal, stop);
|
||||
@@ -35,9 +42,13 @@ try {
|
||||
child.once('close', code => resolve(code ?? 1));
|
||||
});
|
||||
if (timedOut) process.stderr.write('[inspect-canary] GUI host exceeded the 180s deadline\n');
|
||||
// All child output is retained above. Unclassified stderr fails closed.
|
||||
if (stderrBytes) process.stderr.write('[inspect-canary] process log review failed: unexpected stderr\n');
|
||||
process.exitCode = code || (timedOut || stderrBytes ? 1 : 0);
|
||||
// All child output stays visible. Only bounded, reviewed Linux baseline
|
||||
// diagnostics receive warning classifications; unknown output fails closed.
|
||||
const report = reviewInspectStderr(stderrText);
|
||||
if (stderrBytes > 1024 * 1024) report.unexpected++;
|
||||
process.stdout.write(`[inspect-canary] process log review: ${JSON.stringify(report)}\n`);
|
||||
if (report.unexpected) process.stderr.write('[inspect-canary] process log review failed: unexpected stderr\n');
|
||||
process.exitCode = inspectCanaryExitCode(code, timedOut, report);
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
for (const signal of signals) process.off(signal, stop);
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { reviewInspectStderr, inspectCanaryExitCode } from '../../gui/inspect-canary-logs.mjs';
|
||||
|
||||
const sharp = '(node:4439) [SharpElectronLinux] Warning: Binaries provided by Electron for use on Linux may be incompatible with sharp - see https://sharp.pixelplumbing.com/install#electron-and-linux';
|
||||
const glib = "[4439:0911/032713.835182:ERROR:content/browser/browser_main_loop.cc:274] GLib-GObject: g_object_ref: assertion 'G_IS_OBJECT (object)' failed";
|
||||
const dbus = '[4439:0911/032713.202218:ERROR:dbus/bus.cc:405] Failed to connect to the bus: Could not parse server address: Unknown address type (examples of valid types are "tcp" and on UNIX "unix")';
|
||||
const owner = '[4439:0911/032710.232165:ERROR:dbus/object_proxy.cc:572] Failed to call method: org.freedesktop.DBus.NameHasOwner: object_path= /org/freedesktop/DBus: unknown error type: ';
|
||||
const trace = '(Use `electron --trace-warnings ...` to show where the warning was created)';
|
||||
|
||||
describe('GUI canary process diagnostics', () => {
|
||||
it('reports reviewed Linux baseline diagnostics separately from functional success', () => {
|
||||
const report = reviewInspectStderr([dbus, owner, sharp, trace, glib, 'Unable to revert mtime: /usr/share/fonts/truetype/noto'].join('\r\n'), 'linux');
|
||||
expect(report).toEqual({ unexpected: 0, warnings: {
|
||||
'dbus-address': 1, 'dbus-owner': 1, 'sharp-linux': 1, 'sharp-trace': 1, 'glib-sharp': 1, 'system-font-mtime': 1,
|
||||
} });
|
||||
expect(inspectCanaryExitCode(0, false, report)).toBe(0);
|
||||
expect(inspectCanaryExitCode(2, false, report)).toBe(2);
|
||||
expect(inspectCanaryExitCode(0, true, report)).toBe(1);
|
||||
});
|
||||
|
||||
it.each(['darwin', 'win32'])('keeps Linux diagnostics fatal on %s', platform => {
|
||||
expect(reviewInspectStderr(sharp, platform).unexpected).toBe(1);
|
||||
});
|
||||
|
||||
it.each([
|
||||
'GUI test Electron runner failed: Error', 'Segmentation fault',
|
||||
'Unable to revert mtime: /private/user-file', `${glib} and another error`,
|
||||
dbus.replace('Could not parse server address', 'Permission denied'),
|
||||
])('rejects unknown output and near matches: %s', message => {
|
||||
const report = reviewInspectStderr(`${sharp}\n${message}`, 'linux');
|
||||
expect(report.unexpected).toBeGreaterThan(0);
|
||||
expect(inspectCanaryExitCode(0, false, report)).toBe(1);
|
||||
});
|
||||
|
||||
it('rejects an unbounded warning loop and unexplained GLib or trace output', () => {
|
||||
expect(reviewInspectStderr(`${sharp}\n${Array(101).fill(glib).join('\n')}`, 'linux').unexpected).toBe(1);
|
||||
expect(reviewInspectStderr(glib, 'linux').unexpected).toBe(1);
|
||||
expect(reviewInspectStderr(trace, 'linux').unexpected).toBe(1);
|
||||
});
|
||||
|
||||
it('accepts a clean process without platform exceptions', () => {
|
||||
expect(reviewInspectStderr('\n', 'darwin')).toEqual({ warnings: {}, unexpected: 0 });
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user