1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
<?php
{{ header }}
declare(strict_types=1);
{{ env_setup }}
// Load the e2e project autoloader (PHPUnit, test helpers).
require_once __DIR__ . '/vendor/autoload.php';
// Load the PHP binding package classes via its Composer autoloader.
// The package's autoloader is separate from the e2e project's autoloader
// since the php-ext type prevents direct composer path dependency.
$pkgAutoloader = __DIR__ . '/{{ pkg_path }}/vendor/autoload.php';
if (file_exists($pkgAutoloader)) {
require_once $pkgAutoloader;
}{% if uses_server_harness %}
// Spawn the app harness subprocess for server-pattern HTTP fixtures.
//
// The harness must be given the extension explicitly. run_tests.php runs this process
// under `-n` (no php.ini at all) plus an isolated ini, precisely so an ambient
// system-wide copy of the extension cannot win over the one under test -- which means a
// child spawned as a bare PHP_BINARY inherits no extension whatsoever and dies on the
// first `new App()` with "Class not found". run_tests.php exports the path it verified,
// so the harness loads the same file the tests do rather than re-deriving it.
$appHarnessBin = __DIR__ . '/app_harness.php';
if (file_exists($appHarnessBin)) {
$harnessExtPath = getenv('ALEF_PHP_EXTENSION_PATH');
$harnessCmd = ($harnessExtPath !== false && $harnessExtPath !== '')
? [PHP_BINARY, '-d', 'extension=' . $harnessExtPath, $appHarnessBin]
: [PHP_BINARY, $appHarnessBin];
$descriptors = [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => STDERR];
$proc = proc_open($harnessCmd, $descriptors, $pipes);
if (is_resource($proc)) {
// Read startup line from the app harness: "Harness listening on {host}:{port}"
$line = fgets($pipes[1]);
if ($line !== false) {
$line = trim($line);
// Extract host and port to set SUT_URL.
if (str_contains($line, 'Harness listening on')) {
$url = "http://{{ harness_host }}:{{ harness_port }}";
putenv('SUT_URL=' . $url);
$_ENV['SUT_URL'] = $url;
}
}
// Drain stdout in background is not possible in PHP; keep pipe open.
register_shutdown_function(static function () use ($proc, $pipes): void {
fclose($pipes[0]);
fclose($pipes[1]);
proc_close($proc);
});
}
}{% endif %}{% if has_file_fixtures %}
// Change to the configured test-documents directory so that fixture file
// paths like "pdf/fake_memo.pdf" resolve correctly when running phpunit
// from e2e/php/.
$_test_documents = __DIR__ . '/{{ test_documents_path }}';
if (is_dir($_test_documents)) {
chdir($_test_documents);
}{% endif %}{% if has_mock_server_fixtures %}
// Spawn the mock HTTP server binary for HTTP fixture tests.
$mockServerBin = __DIR__ . '/../rust/target/release/mock-server';
$fixturesDir = __DIR__ . '/../../fixtures';
if (file_exists($mockServerBin)) {
$descriptors = [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => STDERR];
$proc = proc_open([$mockServerBin, $fixturesDir], $descriptors, $pipes);
if (is_resource($proc)) {
// Read up to 8 lines to capture MOCK_SERVER_URL= and optionally MOCK_SERVERS=.
for ($i = 0; $i < 8; $i++) {
$line = fgets($pipes[1]);
if ($line === false) {
break;
}
$line = trim($line);
if (str_starts_with($line, 'MOCK_SERVER_URL=')) {
$url = substr($line, strlen('MOCK_SERVER_URL='));
putenv('MOCK_SERVER_URL=' . $url);
$_ENV['MOCK_SERVER_URL'] = $url;
} elseif (str_starts_with($line, 'MOCK_SERVERS=')) {
$jsonVal = substr($line, strlen('MOCK_SERVERS='));
putenv('MOCK_SERVERS=' . $jsonVal);
$_ENV['MOCK_SERVERS'] = $jsonVal;
$servers = json_decode($jsonVal, true);
if (is_array($servers)) {
foreach ($servers as $fid => $furl) {
$envKey = 'MOCK_SERVER_' . strtoupper($fid);
putenv($envKey . '=' . $furl);
$_ENV[$envKey] = $furl;
}
}
break;
} elseif (isset($url)) {
break;
}
}
// Drain stdout in background thread is not possible in PHP; keep pipe open.
register_shutdown_function(static function () use ($proc, $pipes): void {
fclose($pipes[0]);
proc_close($proc);
});
}
}{% endif %}