Files
orca/src/main/crash-reporting/process-gone-classification.test.ts
T

435 lines
11 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import {
shouldRecordProcessGoneCrash as classifyProcessGoneCrash,
shouldRecoverRendererAfterProcessGone
} from './process-gone-classification'
type ProcessGoneClassificationInput = Parameters<typeof classifyProcessGoneCrash>[0]
function shouldRecordProcessGoneCrash({
platform = 'darwin',
...event
}: Omit<ProcessGoneClassificationInput, 'platform'> & {
platform?: NodeJS.Platform
}): boolean {
return classifyProcessGoneCrash({ platform, ...event })
}
describe('shouldRecordProcessGoneCrash', () => {
it('suppresses killed process exits during expected lifecycle teardown', () => {
expect(
shouldRecordProcessGoneCrash({
source: 'renderer',
processType: 'renderer',
reason: 'killed',
exitCode: 15,
expectedTeardown: 'renderer-reload'
})
).toBe(false)
expect(
shouldRecordProcessGoneCrash({
source: 'child',
processType: 'GPU',
reason: 'killed',
exitCode: 15,
expectedTeardown: 'app-shutdown'
})
).toBe(false)
expect(
shouldRecordProcessGoneCrash({
source: 'renderer',
processType: 'renderer',
reason: 'killed',
exitCode: 9,
expectedTeardown: 'app-shutdown'
})
).toBe(false)
})
it('records real crash reasons during expected renderer-only teardown', () => {
expect(
shouldRecordProcessGoneCrash({
source: 'renderer',
processType: 'renderer',
reason: 'crashed',
exitCode: 5,
expectedTeardown: 'renderer-reload'
})
).toBe(true)
expect(
shouldRecordProcessGoneCrash({
source: 'renderer',
processType: 'renderer',
reason: 'oom',
exitCode: null,
expectedTeardown: 'renderer-reload'
})
).toBe(true)
})
it('suppresses crash-shaped GPU child exits during expected app shutdown', () => {
expect(
shouldRecordProcessGoneCrash({
source: 'child',
processType: 'GPU',
reason: 'crashed',
exitCode: 5,
expectedTeardown: 'app-shutdown'
})
).toBe(false)
})
it('still records crash-shaped non-GPU child exits during expected app shutdown', () => {
expect(
shouldRecordProcessGoneCrash({
source: 'child',
processType: 'Utility',
reason: 'crashed',
exitCode: 5,
expectedTeardown: 'app-shutdown'
})
).toBe(true)
})
it('still records crash-shaped renderer exits during expected app shutdown', () => {
expect(
shouldRecordProcessGoneCrash({
source: 'renderer',
processType: 'renderer',
reason: 'crashed',
exitCode: 5,
expectedTeardown: 'app-shutdown'
})
).toBe(true)
})
it('skips SIGTERM killed events outside expected lifecycle teardown', () => {
expect(
shouldRecordProcessGoneCrash({
source: 'renderer',
processType: 'renderer',
reason: 'killed',
exitCode: 15,
expectedTeardown: 'none'
})
).toBe(false)
})
it('skips Windows control termination killed events outside expected lifecycle teardown', () => {
expect(
shouldRecordProcessGoneCrash({
source: 'renderer',
reason: 'killed',
exitCode: -1073741510,
expectedTeardown: 'none'
})
).toBe(false)
expect(
shouldRecordProcessGoneCrash({
source: 'child',
reason: 'killed',
exitCode: 1073807364,
expectedTeardown: 'none'
})
).toBe(false)
})
it('skips recoverable Chromium child process exits', () => {
expect(
shouldRecordProcessGoneCrash({
source: 'child',
processType: 'GPU',
reason: 'crashed',
exitCode: -2147483645,
expectedTeardown: 'none'
})
).toBe(false)
expect(
shouldRecordProcessGoneCrash({
source: 'child',
processType: 'gpu',
reason: 'killed',
exitCode: 1,
expectedTeardown: 'none'
})
).toBe(false)
expect(
shouldRecordProcessGoneCrash({
source: 'child',
processType: 'GPU',
reason: 'abnormal-exit',
exitCode: 512,
expectedTeardown: 'none'
})
).toBe(false)
expect(
shouldRecordProcessGoneCrash({
source: 'child',
processType: 'GPU',
reason: 'abnormal-exit',
exitCode: 8704,
expectedTeardown: 'none'
})
).toBe(false)
expect(
shouldRecordProcessGoneCrash({
source: 'child',
processType: 'Utility',
serviceName: 'network.mojom.NetworkService',
reason: 'killed',
exitCode: 9,
expectedTeardown: 'none'
})
).toBe(false)
expect(
shouldRecordProcessGoneCrash({
source: 'child',
processType: 'Utility',
serviceName: 'network.mojom.NetworkService',
reason: 'crashed',
exitCode: -1,
expectedTeardown: 'none'
})
).toBe(false)
expect(
shouldRecordProcessGoneCrash({
source: 'child',
processType: 'Utility',
serviceName: 'audio.mojom.AudioService',
reason: 'killed',
exitCode: 1,
expectedTeardown: 'none'
})
).toBe(false)
expect(
shouldRecordProcessGoneCrash({
source: 'child',
processType: 'Utility',
serviceName: 'audio.mojom.AudioService',
reason: 'crashed',
exitCode: -1,
expectedTeardown: 'none'
})
).toBe(false)
expect(
shouldRecordProcessGoneCrash({
source: 'child',
processType: 'Utility',
serviceName: 'video_capture.mojom.VideoCaptureService',
reason: 'killed',
exitCode: 1,
expectedTeardown: 'none'
})
).toBe(false)
})
it('still records unknown child process crashes', () => {
expect(
shouldRecordProcessGoneCrash({
source: 'child',
processType: 'Utility',
serviceName: 'com.orca.unexpected',
reason: 'crashed',
exitCode: 5,
expectedTeardown: 'none'
})
).toBe(true)
})
it('still records severe Chromium child process failures', () => {
expect(
shouldRecordProcessGoneCrash({
source: 'child',
processType: 'GPU',
reason: 'oom',
exitCode: 1,
expectedTeardown: 'none'
})
).toBe(true)
expect(
shouldRecordProcessGoneCrash({
source: 'child',
processType: 'Utility',
serviceName: 'network.mojom.NetworkService',
reason: 'launch-failed',
exitCode: -1,
expectedTeardown: 'none'
})
).toBe(true)
expect(
shouldRecordProcessGoneCrash({
source: 'child',
processType: 'Utility',
serviceName: 'video_capture.mojom.VideoCaptureService',
reason: 'launch-failed',
exitCode: -1,
expectedTeardown: 'none'
})
).toBe(true)
})
it('suppresses namespace-encoded SIGTERM kills from the recent Linux cluster', () => {
expect(
shouldRecordProcessGoneCrash({
platform: 'linux',
source: 'renderer',
processType: 'renderer',
reason: 'killed',
exitCode: 61696,
expectedTeardown: 'none'
})
).toBe(false)
})
it('keeps wait status 61696 reportable outside the exact Linux killed boundary', () => {
const processGone = {
source: 'renderer' as const,
processType: 'renderer',
reason: 'killed',
exitCode: 61696,
expectedTeardown: 'none' as const
}
expect(shouldRecordProcessGoneCrash({ ...processGone, platform: 'darwin' })).toBe(true)
expect(shouldRecordProcessGoneCrash({ ...processGone, platform: 'win32' })).toBe(true)
expect(
shouldRecordProcessGoneCrash({
...processGone,
platform: 'linux',
reason: 'abnormal-exit'
})
).toBe(true)
})
it('still records renderer launch failures for diagnostics', () => {
expect(
shouldRecordProcessGoneCrash({
source: 'renderer',
processType: 'renderer',
reason: 'launch-failed',
exitCode: 18,
expectedTeardown: 'none'
})
).toBe(true)
})
it('records non-SIGTERM killed process exits outside expected lifecycle teardown', () => {
expect(
shouldRecordProcessGoneCrash({
platform: 'linux',
source: 'renderer',
processType: 'renderer',
reason: 'killed',
exitCode: 9,
expectedTeardown: 'none'
})
).toBe(true)
})
it('records Windows renderer killed exit 1 outside expected lifecycle teardown only', () => {
expect(
shouldRecordProcessGoneCrash({
source: 'renderer',
processType: 'renderer',
reason: 'killed',
exitCode: 1,
expectedTeardown: 'none'
})
).toBe(true)
expect(
shouldRecordProcessGoneCrash({
source: 'renderer',
processType: 'renderer',
reason: 'killed',
exitCode: 1,
expectedTeardown: 'renderer-reload'
})
).toBe(false)
expect(
shouldRecordProcessGoneCrash({
source: 'renderer',
processType: 'renderer',
reason: 'killed',
exitCode: 1,
expectedTeardown: 'app-shutdown'
})
).toBe(false)
})
it('records non-SIGTERM child-process killed events during renderer-only reloads', () => {
expect(
shouldRecordProcessGoneCrash({
source: 'child',
processType: 'Utility',
serviceName: 'com.orca.unexpected',
reason: 'killed',
exitCode: 9,
expectedTeardown: 'renderer-reload'
})
).toBe(true)
})
})
describe('shouldRecoverRendererAfterProcessGone', () => {
it('recovers unexpected killed renderers', () => {
expect(
shouldRecoverRendererAfterProcessGone({
reason: 'killed',
expectedTeardown: 'none'
})
).toBe(true)
})
it('does not recover expected renderer reload teardown', () => {
expect(
shouldRecoverRendererAfterProcessGone({
reason: 'killed',
expectedTeardown: 'renderer-reload'
})
).toBe(false)
})
it('recovers real renderer crashes during renderer reload windows', () => {
expect(
shouldRecoverRendererAfterProcessGone({
reason: 'oom',
expectedTeardown: 'renderer-reload'
})
).toBe(true)
})
it('does not recover during app shutdown', () => {
expect(
shouldRecoverRendererAfterProcessGone({
reason: 'crashed',
expectedTeardown: 'app-shutdown'
})
).toBe(false)
})
it('recovers transient renderer launch failures', () => {
expect(
shouldRecoverRendererAfterProcessGone({
reason: 'launch-failed',
expectedTeardown: 'none'
})
).toBe(true)
expect(
shouldRecoverRendererAfterProcessGone({
reason: 'launch-failed',
expectedTeardown: 'renderer-reload'
})
).toBe(true)
})
it('does not recover renderer integrity failures', () => {
expect(
shouldRecoverRendererAfterProcessGone({
reason: 'integrity-failure',
expectedTeardown: 'none'
})
).toBe(false)
})
})