Skip to content

Commit 90de8b4

Browse files
committed
Add phpseclib, Psalm, PHPStan nightly tests
1 parent 2ca142e commit 90de8b4

File tree

3 files changed

+321
-103
lines changed

3 files changed

+321
-103
lines changed

.github/jit_check.php

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
register_shutdown_function(function () {
4+
$status = opcache_get_status(false);
5+
var_dump($status);
6+
7+
if ($status["memory_usage"]["free_memory"] < 10*1024*1024) {
8+
fwrite(STDERR, "Not enough free opcache memory!".PHP_EOL);
9+
}
10+
if ($status["interned_strings_usage"]["free_memory"] < 1*1024*1024) {
11+
fwrite(STDERR, "Not enough free interned strings memory!".PHP_EOL);
12+
}
13+
if ($status["jit"]["buffer_free"] < 10*1024*1024) {
14+
fwrite(STDERR, "Not enough free JIT memory!".PHP_EOL);
15+
}
16+
if (!$status["jit"]["on"]) {
17+
fwrite(STDERR, "JIT is not enabled!".PHP_EOL);
18+
}
19+
20+
unset($status);
21+
while (gc_collect_cycles());
22+
});
23+
24+
$argc--;
25+
array_shift($argv);
26+
27+
$_SERVER['argc']--;
28+
array_shift($_SERVER['argv']);
29+
30+
require $argv[0];

.github/nightly.php

+258
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
<?php
2+
3+
putenv("ASAN_OPTIONS=exitcode=139");
4+
putenv("SYMFONY_DEPRECATIONS_HELPER=max[total]=999");
5+
putenv("PHPSECLIB_ALLOW_JIT=1");
6+
7+
function printMutex(string $result): void {
8+
flock(STDOUT, LOCK_EX);
9+
fwrite(STDOUT, $result.PHP_EOL);
10+
flock(STDOUT, LOCK_UN);
11+
}
12+
13+
function e(string $cmd, string $extra = ''): string {
14+
exec("bash -c ".escapeshellarg("$cmd 2>&1"), $result, $code);
15+
$result = implode("\n", $result);
16+
if ($code) {
17+
printMutex("An error occurred while executing $cmd (status $code, extra info $extra): $result");
18+
die(1);
19+
}
20+
return $result;
21+
}
22+
23+
$parallel = (int) ($argv[1] ?? 0);
24+
$parallel = $parallel ?: ((int)`nproc`);
25+
$parallel = $parallel ?: 8;
26+
27+
$repos = [];
28+
29+
$repos["phpunit"] = [
30+
"https://github.com/sebastianbergmann/phpunit.git",
31+
"main",
32+
null,
33+
["./phpunit"],
34+
1
35+
];
36+
37+
$repos["wordpress"] = [
38+
"https://github.com/WordPress/wordpress-develop.git",
39+
"",
40+
function (): void {
41+
$f = file_get_contents('wp-tests-config-sample.php');
42+
$f = str_replace('youremptytestdbnamehere', 'test', $f);
43+
$f = str_replace('yourusernamehere', 'root', $f);
44+
$f = str_replace('yourpasswordhere', 'root', $f);
45+
file_put_contents('wp-tests-config.php', $f);
46+
},
47+
["vendor/bin/phpunit"],
48+
1
49+
];
50+
51+
foreach (['amp', 'cache', 'dns', 'file', 'http', 'parallel', 'parser', 'pipeline', 'process', 'serialization', 'socket', 'sync', 'websocket-client', 'websocket-server'] as $repo) {
52+
$repos["amphp-$repo"] = ["https://github.com/amphp/$repo.git", "", null, ["vendor/bin/phpunit"], 1];
53+
}
54+
55+
$repos["laravel"] = [
56+
"https://github.com/laravel/framework.git",
57+
"master",
58+
function (): void {
59+
$c = file_get_contents("tests/Filesystem/FilesystemTest.php");
60+
$c = str_replace("public function testSharedGet()", "#[\\PHPUnit\\Framework\\Attributes\\Group('skip')]\n public function testSharedGet()", $c);
61+
file_put_contents("tests/Filesystem/FilesystemTest.php", $c);
62+
},
63+
["vendor/bin/phpunit", "--exclude-group", "skip"],
64+
1
65+
];
66+
67+
foreach (['async', 'cache', 'child-process', 'datagram', 'dns', 'event-loop', 'promise', 'promise-stream', 'promise-timer', 'stream'] as $repo) {
68+
$repos["reactphp-$repo"] = ["https://github.com/reactphp/$repo.git", "", null, ["vendor/bin/phpunit"], 1];
69+
}
70+
71+
$repos["revolt"] = ["https://github.com/revoltphp/event-loop.git", "", null, ["vendor/bin/phpunit"], 2];
72+
73+
$repos["symfony"] = [
74+
"https://github.com/symfony/symfony.git",
75+
"",
76+
function (): void {
77+
e("php ./phpunit install");
78+
79+
// Test causes a heap-buffer-overflow but I cannot reproduce it locally...
80+
$c = file_get_contents("src/Symfony/Component/HtmlSanitizer/Tests/HtmlSanitizerCustomTest.php");
81+
$c = str_replace("public function testSanitizeDeepNestedString()", "/** @group skip */\n public function testSanitizeDeepNestedString()", $c);
82+
file_put_contents("src/Symfony/Component/HtmlSanitizer/Tests/HtmlSanitizerCustomTest.php", $c);
83+
// Buggy FFI test in Symfony, see https://github.com/symfony/symfony/issues/47668
84+
$c = file_get_contents("src/Symfony/Component/VarDumper/Tests/Caster/FFICasterTest.php");
85+
$c = str_replace("*/\n public function testCastNonTrailingCharPointer()", "* @group skip\n */\n public function testCastNonTrailingCharPointer()", $c);
86+
file_put_contents("src/Symfony/Component/VarDumper/Tests/Caster/FFICasterTest.php", $c);
87+
},
88+
function (): iterable {
89+
$it = new RecursiveDirectoryIterator("src/Symfony");
90+
/** @var SplFileInfo $file */
91+
foreach(new RecursiveIteratorIterator($it) as $file) {
92+
if ($file->getBasename() == 'phpunit.xml.dist') {
93+
yield [
94+
getcwd()."/phpunit",
95+
dirname($file->getRealPath()),
96+
"--exclude-group",
97+
"tty,benchmark,intl-data,transient",
98+
"--exclude-group",
99+
"skip"
100+
];
101+
}
102+
}
103+
},
104+
1
105+
];
106+
107+
$finalStatus = 0;
108+
$parentPids = [];
109+
110+
$waitOne = function () use (&$finalStatus, &$parentPids): void {
111+
$res = pcntl_wait($status);
112+
if ($res === -1) {
113+
printMutex("An error occurred while waiting with waitpid!");
114+
$finalStatus = $finalStatus ?: 1;
115+
return;
116+
}
117+
if (!isset($parentPids[$res])) {
118+
printMutex("Unknown PID $res returned!");
119+
$finalStatus = $finalStatus ?: 1;
120+
return;
121+
}
122+
$desc = $parentPids[$res];
123+
unset($parentPids[$res]);
124+
if (pcntl_wifexited($status)) {
125+
$status = pcntl_wexitstatus($status);
126+
printMutex("Child task $desc exited with status $status");
127+
if ($status !== 0) {
128+
$finalStatus = $status;
129+
}
130+
} elseif (pcntl_wifstopped($status)) {
131+
$status = pcntl_wstopsig($status);
132+
printMutex("Child task $desc stopped by signal $status");
133+
$finalStatus = 1;
134+
} elseif (pcntl_wifsignaled($status)) {
135+
$status = pcntl_wtermsig($status);
136+
printMutex("Child task $desc terminated by signal $status");
137+
$finalStatus = 1;
138+
}
139+
};
140+
141+
$waitAll = function () use ($waitOne, &$parentPids): void {
142+
while ($parentPids) {
143+
$waitOne();
144+
}
145+
};
146+
147+
printMutex("Cloning repos...");
148+
149+
foreach ($repos as $dir => [$repo, $branch, $prepare, $command, $repeat]) {
150+
$pid = pcntl_fork();
151+
if ($pid) {
152+
$parentPids[$pid] = "clone $dir";
153+
continue;
154+
}
155+
156+
chdir(sys_get_temp_dir());
157+
if ($branch) {
158+
$branch = "--branch $branch";
159+
}
160+
e("git clone $repo $branch --depth 1 $dir");
161+
162+
exit(0);
163+
}
164+
165+
$waitAll();
166+
167+
printMutex("Done cloning repos!");
168+
169+
printMutex("Preparing repos (max $parallel processes)...");
170+
foreach ($repos as $dir => [$repo, $branch, $prepare, $command, $repeat]) {
171+
chdir(sys_get_temp_dir()."/$dir");
172+
$rev = e("git rev-parse HEAD", $dir);
173+
174+
$pid = pcntl_fork();
175+
if ($pid) {
176+
$parentPids[$pid] = "prepare $dir ($rev)";
177+
if (count($parentPids) >= $parallel) {
178+
$waitOne();
179+
}
180+
continue;
181+
}
182+
183+
e("composer i --ignore-platform-reqs", $dir);
184+
if ($prepare) {
185+
$prepare();
186+
}
187+
188+
exit(0);
189+
}
190+
$waitAll();
191+
192+
printMutex("Done preparing repos!");
193+
194+
printMutex("Running tests (max $parallel processes)...");
195+
foreach ($repos as $dir => [$repo, $branch, $prepare, $command, $repeat]) {
196+
chdir(sys_get_temp_dir()."/$dir");
197+
$rev = e("git rev-parse HEAD", $dir);
198+
199+
if ($command instanceof Closure) {
200+
$commands = iterator_to_array($command());
201+
} else {
202+
$commands = [$command];
203+
}
204+
205+
foreach ($commands as $idx => $cmd) {
206+
$cmd = array_merge([
207+
'php',
208+
'--repeat',
209+
$repeat,
210+
'-f',
211+
__DIR__.'/jit_check.php',
212+
], $cmd);
213+
214+
$cmdStr = implode(" ", $cmd);
215+
216+
$pid = pcntl_fork();
217+
if ($pid) {
218+
$parentPids[$pid] = "test $dir ($rev): $cmdStr";
219+
if (count($parentPids) >= $parallel) {
220+
$waitOne();
221+
}
222+
continue;
223+
}
224+
225+
$output = sys_get_temp_dir()."/out_{$dir}_$idx.txt";
226+
227+
$p = proc_open($cmd, [
228+
["pipe", "r"],
229+
["file", $output, "a"],
230+
["file", $output, "a"]
231+
], $pipes, sys_get_temp_dir()."/$dir");
232+
233+
if ($p === false) {
234+
printMutex("Failure starting $cmdStr");
235+
exit(1);
236+
}
237+
238+
$final = 0;
239+
$status = proc_close($p);
240+
if ($status !== 0) {
241+
if ($status > 128) {
242+
$final = $status;
243+
}
244+
printMutex(
245+
"$dir ($rev): $cmdStr terminated with status $status:".PHP_EOL
246+
.file_get_contents($output).PHP_EOL
247+
);
248+
}
249+
250+
exit($final);
251+
}
252+
}
253+
254+
$waitAll();
255+
256+
printMutex("All done!");
257+
258+
die($finalStatus);

0 commit comments

Comments
 (0)