Skip to content

Commit 0f20c02

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

File tree

1 file changed

+129
-133
lines changed

1 file changed

+129
-133
lines changed

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

Lines changed: 129 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -6,176 +6,172 @@ 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';
10+
11+
/* eslint-disable comment-length/limit-single-line-comments */
1012

11-
// @TODO Prevent crash on PHP versions 5.6, 7.2, 8.2
1213
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-
});
14+
'PHP' in process.env ? [process.env['PHP']!] : SupportedPHPVersions;
2515

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

30-
function unhandledRejectionHandler(error: any) {
31-
unhandledRejection = error;
32-
}
21+
// function unhandledRejectionHandler(error: any) {
22+
// unhandledRejection = error;
23+
// }
3324

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-
});
25+
beforeEach(async () => {
26+
php = new PHP(await loadNodeRuntime(phpVersion as any));
27+
await setPhpIniEntries(php, { allow_url_fopen: 1 });
28+
vi.restoreAllMocks();
29+
});
4030

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

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

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-
}
126+
expect(global).toHaveProperty('gc');
127+
expect(global.gc).toBeDefined();
128128

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

132-
let refCount = 0;
131+
const registry = new FinalizationRegistry(() => --refCount);
133132

134-
const registry = new FinalizationRegistry(() => --refCount);
133+
const concurrent = 25;
134+
const steps = 5;
135135

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

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

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

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

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

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-
}
158+
instances.clear();
160159

161-
instances.clear();
160+
await delay(10);
161+
if (global.gc) {
162+
global.gc();
163+
}
164+
}
162165

163-
await delay(10);
166+
await delay(100);
164167
if (global.gc) {
165168
global.gc();
166169
}
167-
}
168-
169-
await delay(100);
170-
if (global.gc) {
171-
global.gc();
172-
}
173170

174-
expect(refCount).lessThanOrEqual(10);
175-
}, 500_000);
176-
});
171+
expect(refCount).lessThanOrEqual(10);
172+
}, 500_000);
173+
});
177174

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

0 commit comments

Comments
 (0)