fix(ci): include EXT/LIB integration fixtures

master
韩天峰 7 hours ago
parent c0328df9e6
commit f56b209d5c
  1. 5
      .github/integration/README.md
  2. 57
      .github/integration/ext/lifecycle/host/request.php
  3. 24
      .github/integration/ext/lifecycle/src/extension.php
  4. 16
      .github/integration/lib/consumer/main.php
  5. 0
      .github/integration/lib/provider/project.yml
  6. 29
      .github/integration/lib/provider/src/library.php
  7. 2
      bin/run-integration-tests.php

@ -1,7 +1,8 @@
# EXT/LIB integration tests
This suite protects build-mode boundaries rather than duplicating the PHP
syntax coverage in `tests/compiler`.
This suite lives below `.github` because repository test fixtures with a `.php`
suffix are intentionally ignored below `tests/`. It protects build-mode
boundaries rather than duplicating the PHP syntax coverage in `tests/compiler`.
- `ext/lifecycle` builds a real Zend extension and loads it through CLI,
`php -S`, and PHP-FPM. The long-running hosts alternate implementations of

@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
$request = PHP_SAPI === 'cli'
? (int) getenv('TYPEPHP_INTEGRATION_REQUEST')
: (int) ($_GET['request'] ?? 0);
// Alternate the implementation attached to the same request-local symbols.
// A stale pointer surviving RSHUTDOWN will either call the preceding request's
// implementation, access released memory, or crash the long-running host.
if ($request % 2 === 0) {
final class TypePhpIntegrationRequestValue
{
public function __construct(private int $value)
{
}
public function render(): string
{
return 'even:' . $this->value;
}
}
function typephp_integration_request_transform(string $value): string
{
return 'even-handler[' . $value . ']';
}
} else {
final class TypePhpIntegrationRequestValue
{
public function __construct(private int $value)
{
}
public function render(): string
{
return 'odd:' . $this->value;
}
}
function typephp_integration_request_transform(string $value): string
{
return 'odd-handler[' . $value . ']';
}
}
header('Content-Type: application/json');
echo json_encode([
'request' => $request,
'results' => [
typephp_integration_probe($request),
typephp_integration_probe($request),
],
'main_registered' => function_exists('main'),
'pid' => getmypid(),
], JSON_THROW_ON_ERROR);

@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
function typephp_integration_probe(int $request): string
{
static $calls = 0;
++$calls;
// DateTimeImmutable and its format() method are internal, module-lifetime
// symbols. The host class/function below are rebuilt for every request and
// therefore exercise the request-lifetime class/function cache domain.
$date = new DateTimeImmutable('@' . $request);
$value = new TypePhpIntegrationRequestValue($request);
return $calls . '@' . $date->format('U') . '|'
. typephp_integration_request_transform($value->render());
}
// main() belongs to the embedded bin entry path. An extension must neither
// register it as a PHP function nor invoke it from RINIT.
function main(): void
{
throw new RuntimeException('ext mode invoked bin main()');
}

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
use TypePhpIntegration\Library\Counter;
use function TypePhpIntegration\Library\add;
function main(): void
{
echo add(19, 23), "\n";
$counter = new Counter();
$counter->add(3);
$counter->add(4);
echo 'counter=', $counter->value, "\n";
}

@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace {
// lib mode owns an embedded module but must not execute the bin entrypoint.
// This declaration must also be omitted from the published import stub.
function main(): void
{
throw new RuntimeException('lib mode invoked bin main()');
}
}
namespace TypePhpIntegration\Library {
function add(int $left, int $right): int
{
return $left + $right;
}
final class Counter
{
public int $value = 0;
public function add(int $delta): int
{
return $this->value += $delta;
}
}
}

@ -13,7 +13,7 @@ use RuntimeException;
use Throwable;
const TYPEPHP_INTEGRATION_ROOT = __DIR__ . '/..';
const TYPEPHP_INTEGRATION_TEST_ROOT = TYPEPHP_INTEGRATION_ROOT . '/tests/integration';
const TYPEPHP_INTEGRATION_TEST_ROOT = TYPEPHP_INTEGRATION_ROOT . '/.github/integration';
final class IntegrationFailure extends RuntimeException
{

Loading…
Cancel
Save