Skip to content

Commit 45be38f

Browse files
committed
Comment out obsolete test in php-crash and refactor
1 parent 29df355 commit 45be38f

File tree

1 file changed

+127
-133
lines changed

1 file changed

+127
-133
lines changed

packages/php-wasm/node/src/test/php-crash.spec.ts

Lines changed: 127 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -6,176 +6,170 @@ import {
66
PHP,
77
} from '@php-wasm/universal';
88
import { loadNodeRuntime } from '../lib';
9-
import { jspi } from 'wasm-feature-detect';
9+
// import { jspi } from 'wasm-feature-detect';
1010

11-
// @TODO Prevent crash on PHP versions 5.6, 7.2, 8.2
1211
const phpVersions =
13-
'PHP' in process.env ? [process.env['PHP']!] : ['7.3', '7.4', '8.0', '8.1'];
14-
describe.each(phpVersions)('PHP %s – process crash', async (phpVersion) => {
15-
let php: PHP;
16-
let unhandledRejection: any;
17-
beforeEach(async () => {
18-
php = new PHP(await loadNodeRuntime(phpVersion as any));
19-
await setPhpIniEntries(php, { allow_url_fopen: 1 });
20-
vi.restoreAllMocks();
21-
22-
// Tolerate an unhandled rejection as long as we catch the error we're testing
23-
process.on('unhandledRejection', unhandledRejectionHandler);
24-
});
12+
'PHP' in process.env ? [process.env['PHP']!] : SupportedPHPVersions;
2513

26-
afterEach(async () => {
27-
php.exit();
28-
});
14+
describe.each(phpVersions)('PHP %s – ', async (phpVersion) => {
15+
describe('process crash', () => {
16+
let php: PHP;
17+
// let unhandledRejection: any;
2918

30-
function unhandledRejectionHandler(error: any) {
31-
unhandledRejection = error;
32-
}
19+
// function unhandledRejectionHandler(error: any) {
20+
// unhandledRejection = error;
21+
// }
3322

34-
afterEach(async () => {
35-
// Make sure the process exits and give any unhandled rejections a chance to be caught
36-
php.exit();
37-
await new Promise((resolve) => setTimeout(resolve, 100));
38-
process.off('unhandledRejection', unhandledRejectionHandler);
39-
});
23+
beforeEach(async () => {
24+
php = new PHP(await loadNodeRuntime(phpVersion as any));
25+
await setPhpIniEntries(php, { allow_url_fopen: 1 });
26+
vi.restoreAllMocks();
27+
});
4028

41-
if (!(await jspi())) {
42-
it('Does not crash due to an unhandled Asyncify error ', async () => {
43-
let caughtError;
29+
afterEach(async () => {
30+
// Make sure the process exits and give any unhandled rejections a chance to be caught
31+
php.exit();
32+
await new Promise((resolve) => setTimeout(resolve, 100));
33+
// process.off('unhandledRejection', unhandledRejectionHandler);
34+
});
4435

36+
// if (!(await jspi())) {
37+
// it('Does not crash due to an unhandled Asyncify error ', async () => {
38+
// let caughtError;
39+
40+
// try {
41+
// /**
42+
// * PHP is intentionally built without network support for __clone()
43+
// * because it's an extremely unlikely place for any network activity
44+
// * and not supporting it allows us to test the error handling here.
45+
// *
46+
// * `clone $x` will throw an asynchronous error out when attempting
47+
// * to do a network call ("unreachable" WASM instruction executed).
48+
// * This test should gracefully catch and handle that error.
49+
// *
50+
// * A failure to do so will crash the entire process
51+
// */
52+
// await php.run({
53+
// code: `<?php
54+
// class Top {
55+
// function __clone() {
56+
// file_get_contents("http://127.0.0.1");
57+
// }
58+
// }
59+
// $x = new Top();
60+
// clone $x;
61+
// `,
62+
// });
63+
// } catch (error: unknown) {
64+
// caughtError = error;
65+
// if (error instanceof Error) {
66+
// expect(
67+
// (error as any).cause?.message || error.message
68+
// ).toMatch(
69+
// /Aborted|Program terminated with exit\(1\)|unreachable|null function or function signature|out of bounds/
70+
// );
71+
// }
72+
// }
73+
74+
// // Accept either a caught error or an unhandled rejection
75+
// if (!caughtError && !unhandledRejection) {
76+
// expect.fail(
77+
// 'php.run should have thrown an error or caused an unhandled rejection'
78+
// );
79+
// }
80+
// });
81+
// }
82+
83+
it('Does not crash due to an unhandled non promise error ', async () => {
84+
// Tolerate an unhandled rejections
85+
86+
let caughtError;
4587
try {
46-
/**
47-
* PHP is intentionally built without network support for __clone()
48-
* because it's an extremely unlikely place for any network activity
49-
* and not supporting it allows us to test the error handling here.
50-
*
51-
* `clone $x` will throw an asynchronous error out when attempting
52-
* to do a network call ("unreachable" WASM instruction executed).
53-
* This test should gracefully catch and handle that error.
54-
*
55-
* A failure to do so will crash the entire process
56-
*/
88+
const spy = vi.spyOn(php[__private__dont__use], 'ccall');
89+
expect(spy.getMockName()).toEqual('ccall');
90+
spy.mockImplementation((c_func) => {
91+
if (c_func === 'wasm_sapi_handle_request') {
92+
throw new Error('test');
93+
}
94+
});
95+
5796
await php.run({
5897
code: `<?php
59-
class Top {
60-
function __clone() {
61-
file_get_contents("http://127.0.0.1");
62-
}
63-
}
64-
$x = new Top();
65-
clone $x;
98+
function top() {
99+
file_get_contents("http://127.0.0.1");
100+
}
101+
top();
66102
`,
67103
});
68104
} catch (error: unknown) {
69105
caughtError = error;
70106
if (error instanceof Error) {
71-
expect(
72-
(error as any).cause?.message || error.message
73-
).toMatch(
74-
/Aborted|Program terminated with exit\(1\)|unreachable|null function or function signature|out of bounds/
75-
);
107+
expect(error.message).toMatch('test');
76108
}
77109
}
78-
79-
// Accept either a caught error or an unhandled rejection
80-
if (!caughtError && !unhandledRejection) {
81-
expect.fail(
82-
'php.run should have thrown an error or caused an unhandled rejection'
83-
);
110+
if (!caughtError) {
111+
expect.fail('php.run should have thrown an error');
84112
}
85113
});
86-
}
87-
88-
it('Does not crash due to an unhandled non promise error ', async () => {
89-
// Tolerate an unhandled rejections
90-
91-
let caughtError;
92-
try {
93-
const spy = vi.spyOn(php[__private__dont__use], 'ccall');
94-
expect(spy.getMockName()).toEqual('ccall');
95-
spy.mockImplementation((c_func) => {
96-
if (c_func === 'wasm_sapi_handle_request') {
97-
throw new Error('test');
98-
}
99-
});
100-
101-
await php.run({
102-
code: `<?php
103-
function top() {
104-
file_get_contents("http://127.0.0.1");
105-
}
106-
top();
107-
`,
108-
});
109-
} catch (error: unknown) {
110-
caughtError = error;
111-
if (error instanceof Error) {
112-
expect(error.message).toMatch('test');
114+
115+
it('Does not leak memory when creating and destroying instances', async () => {
116+
if (!global.gc) {
117+
console.error(
118+
`\u001b[33mAlert! node must be run with --expose-gc to test properly!\u001b[0m\n` +
119+
`\u001b[33mnx can pass the switch with:\u001b[0m\n` +
120+
`\u001b[33m\tnode --expose-gc node_modules/nx/bin/nx\u001b[0m`
121+
);
113122
}
114-
}
115-
if (!caughtError) {
116-
expect.fail('php.run should have thrown an error');
117-
}
118-
});
119123

120-
it('Does not leak memory when creating and destroying instances', async () => {
121-
if (!global.gc) {
122-
console.error(
123-
`\u001b[33mAlert! node must be run with --expose-gc to test properly!\u001b[0m\n` +
124-
`\u001b[33mnx can pass the switch with:\u001b[0m\n` +
125-
`\u001b[33m\tnode --expose-gc node_modules/nx/bin/nx\u001b[0m`
126-
);
127-
}
124+
expect(global).toHaveProperty('gc');
125+
expect(global.gc).toBeDefined();
128126

129-
expect(global).toHaveProperty('gc');
130-
expect(global.gc).toBeDefined();
127+
let refCount = 0;
131128

132-
let refCount = 0;
129+
const registry = new FinalizationRegistry(() => --refCount);
133130

134-
const registry = new FinalizationRegistry(() => --refCount);
131+
const concurrent = 25;
132+
const steps = 5;
135133

136-
const concurrent = 25;
137-
const steps = 5;
134+
const delay = (ms: number) =>
135+
new Promise((accept) => setTimeout(accept, ms));
138136

139-
const delay = (ms: number) =>
140-
new Promise((accept) => setTimeout(accept, ms));
137+
for (let i = 0; i < steps; i++) {
138+
const instances = new Set<PHP>();
141139

142-
for (let i = 0; i < steps; i++) {
143-
const instances = new Set<PHP>();
140+
for (let j = 0; j < concurrent; j++) {
141+
instances.add(
142+
new PHP(await loadNodeRuntime(phpVersion as any))
143+
);
144+
}
144145

145-
for (let j = 0; j < concurrent; j++) {
146-
instances.add(
147-
new PHP(await loadNodeRuntime(phpVersion as any))
148-
);
149-
}
146+
refCount += instances.size;
150147

151-
refCount += instances.size;
148+
for (const instance of instances) {
149+
registry.register(instance, null);
150+
await instance
151+
.run({ code: `<?php 2+2;` })
152+
.then(() => instance.exit())
153+
.catch(() => {});
154+
}
152155

153-
for (const instance of instances) {
154-
registry.register(instance, null);
155-
await instance
156-
.run({ code: `<?php 2+2;` })
157-
.then(() => instance.exit())
158-
.catch(() => {});
159-
}
156+
instances.clear();
160157

161-
instances.clear();
158+
await delay(10);
159+
if (global.gc) {
160+
global.gc();
161+
}
162+
}
162163

163-
await delay(10);
164+
await delay(100);
164165
if (global.gc) {
165166
global.gc();
166167
}
167-
}
168-
169-
await delay(100);
170-
if (global.gc) {
171-
global.gc();
172-
}
173168

174-
expect(refCount).lessThanOrEqual(10);
175-
}, 500_000);
176-
});
169+
expect(refCount).lessThanOrEqual(10);
170+
}, 500_000);
171+
});
177172

178-
describe.each(SupportedPHPVersions)('PHP %s', (phpVersion) => {
179173
describe('emscripten options', () => {
180174
it('calls quit callback', async () => {
181175
let result = '';

0 commit comments

Comments
 (0)