Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,13 @@ miniwebapp-aot-bisect:
./script/miniwebapp-aot-bisect.sh

# HTTP smoke: phpc serve + curl for 001-SimpleWeb and 002-StaticWeb (issue #298)
.PHONY: examples-web-smoke examples-web-smoke-prebuild examples-aot-smoke deploy-smoke
.PHONY: examples-web-smoke examples-sessions-smoke examples-web-smoke-prebuild examples-aot-smoke deploy-smoke
examples-web-smoke:
./script/examples-web-smoke.sh

examples-sessions-smoke:
./script/examples-web-smoke.sh --sessions-only

examples-web-smoke-prebuild:
./script/examples-web-smoke-prebuild.sh

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ mkdir my-app && ./phpc init my-app # phpc.json + public/index.php scaffold (se
./phpc run -r 'echo 1;' # VM mode (or: php bin/vm.php -r 'echo 1;')
./phpc run -q 'name=Dev' examples/001-SimpleWeb/example.php # web example without TCP
make web-smoke # lint shipped examples + 003-MiniWebApp tree, VM smoke 001-SimpleWeb
make examples-web-smoke # phpc serve + curl for 001-SimpleWeb, 002-StaticWeb, and 004-ApiJson
make examples-web-smoke # phpc serve + curl for 001–004 and 005-SessionsWeb (SESSIONS_WEB_SMOKE_GATE=1 default)
make examples-aot-smoke # phpc build + CLI execute for 000–004 when LLVM ready (#667)
make deploy-smoke # phpc deploy + PHPC_DEPLOY_ROOT CGI for 001/002 when LLVM ready (#718)
./phpc serve examples/001-SimpleWeb # http://127.0.0.1:8080/ (or: make serve)
Expand Down
12 changes: 11 additions & 1 deletion bin/serve.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

use PHPCompiler\Runtime;
use PHPCompiler\VM\OutputBuffer;
use PHPCompiler\VM\ScriptExit;
use PHPCompiler\ext\standard\VmSession;
use PHPCompiler\Web\DevServer;
use PHPCompiler\Web\ProjectBootstrap;
Expand All @@ -40,8 +41,8 @@
}

ob_start();
$runtime = new Runtime();
try {
$runtime = new Runtime();
Superglobals::populateFromEnvironment(
$runtime->vmContext,
$cgiEnv['QUERY_STRING'] ?? '',
Expand All @@ -52,6 +53,15 @@
$block = $runtime->parseAndCompile($code, $script);
$runtime->run($block);
$output = ob_get_clean();
if (VmSession::isActive()) {
VmSession::writeClose($runtime->vmContext);
}
} catch (ScriptExit $e) {
ob_end_clean();
$output = '';
if (VmSession::isActive()) {
VmSession::writeClose($runtime->vmContext);
}
} catch (\Throwable $e) {
ob_end_clean();
throw $e;
Expand Down
1 change: 1 addition & 0 deletions docs/local-ci-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ Defaults are exported from [`script/ci-defaults.env`](../script/ci-defaults.env)
|----------|---------|--------|-------|
| `MINIWEBAPP_VM_CLI_GATE` | `1` | `ci-fast.sh` | PHPUnit `MiniWebApp*VmCli` matrix ([#597](https://github.com/PurHur/php-compiler/issues/597)) |
| `MINIWEBAPP_SERVE_GATE` | `1` | `ci-local.sh`, `ci-fast.sh` | `ServeTest` `@group miniwebapp` ([#641](https://github.com/PurHur/php-compiler/issues/641)) |
| `SESSIONS_WEB_SMOKE_GATE` | `1` | `ci-fast.sh`, `ci-local.sh` | `examples-web-smoke.sh --sessions-only` / 005 cookie flash curls ([#1887](https://github.com/PurHur/php-compiler/issues/1887)) |
| `MINIWEBAPP_WEB_SMOKE_GATE` | `1` | `ci-local.sh` | `examples-web-smoke.sh --miniwebapp-only` ([#664](https://github.com/PurHur/php-compiler/issues/664)) |
| `MINIWEBAPP_WEB_SMOKE_AOT_GATE` | `1` | `ci-local.sh` | `ci_run_miniwebapp_web_smoke_aot` → `examples-web-smoke.sh --miniwebapp-only --aot` ([#1523](https://github.com/PurHur/php-compiler/issues/1523), [#833](https://github.com/PurHur/php-compiler/issues/833)) |
| `MINIWEBAPP_AOT_LINK_GATE` | `1` | `ci-local.sh` (PHPUnit `@group aot-link`) | `ExamplesCompileTest` 003 native link ([#754](https://github.com/PurHur/php-compiler/issues/754)) |
Expand Down
2 changes: 1 addition & 1 deletion examples/005-SessionsWeb/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ The last response should include `Flash: Saved`.

## Related

- [#1887](https://github.com/PurHur/php-compiler/issues/1887) — `examples-web-smoke` gate
- [#1887](https://github.com/PurHur/php-compiler/issues/1887) — `SESSIONS_WEB_SMOKE_GATE=1` (default): `make examples-sessions-smoke`, `ci-fast.sh`, `ExamplesCompileTest::test005SessionsWebServeFlashRoundTrip`
- [#1893](https://github.com/PurHur/php-compiler/issues/1893) — deploy + `PHPC_DEPLOY_ROOT` smoke
5 changes: 3 additions & 2 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ curl -s -b "$jar" -c "$jar" -X POST -d 'message=Saved' 'http://127.0.0.1:8080/ex
curl -s -b "$jar" 'http://127.0.0.1:8080/example.php'
```

AOT link/execute: [#1891](https://github.com/PurHur/php-compiler/issues/1891). `examples-web-smoke` gate: [#1887](https://github.com/PurHur/php-compiler/issues/1887).
AOT link/execute: [#1891](https://github.com/PurHur/php-compiler/issues/1891). VM session curls: `SESSIONS_WEB_SMOKE_GATE=1` (default) in `ci-fast.sh` / `ci-local.sh` — `make examples-sessions-smoke` or `examples-web-smoke.sh --sessions-only` ([#1887](https://github.com/PurHur/php-compiler/issues/1887)).

### 002-StaticWeb

Expand Down Expand Up @@ -139,7 +139,8 @@ Before a PR that touches examples or `bin/serve.php`:

```console
make web-smoke # lint examples/*/example.php + 003 lint --all + VM ?name= smoke
make examples-web-smoke # phpc serve + curl GET/POST (001-SimpleWeb, 002-StaticWeb, 004-ApiJson)
make examples-web-smoke # phpc serve + curl GET/POST (001–004 + 005 session flash when SESSIONS_WEB_SMOKE_GATE=1)
make examples-sessions-smoke # 005-SessionsWeb cookie jar only (#1887)
make examples-aot-smoke # phpc build + CLI execute (000–004; skips when LLVM missing; 003 execute green #764)
```

Expand Down
17 changes: 17 additions & 0 deletions script/ci-common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,23 @@ ci_guard_jit_compliance() {
"$PHP_BIN" "${PHP_OPTS[@]}" script/check-jit-compliance-ran.php "$junit_path" "$llvm_dir"
}

# Shell curl harness for 005-SessionsWeb session flash (issue #1887).
ci_run_sessions_web_smoke() {
if [[ "${SESSIONS_WEB_SMOKE_GATE:-1}" != "1" ]]; then
return 0
fi
if [[ -n "${PHP_COMPILER_SKIP_SERVE_TESTS:-}" ]]; then
echo "examples-web-smoke (005): skipped (PHP_COMPILER_SKIP_SERVE_TESTS is set)"
return 0
fi
if ! ci_can_bind_loopback; then
echo "examples-web-smoke (005): skipped (cannot bind loopback TCP)"
return 0
fi
echo "examples-web-smoke (005): SessionsWeb cookie curls (SESSIONS_WEB_SMOKE_GATE=1 default, #1887)..."
"$_CI_SCRIPT_DIR/examples-web-smoke.sh" --sessions-only
}

# Shell curl harness for 003-MiniWebApp PATH_INFO routes (issue #633).
ci_run_miniwebapp_web_smoke() {
if [[ -n "${PHP_COMPILER_SKIP_SERVE_TESTS:-}" ]]; then
Expand Down
1 change: 1 addition & 0 deletions script/ci-defaults.env
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export PHP_COMPILER_VM_RSS_GUARD="${PHP_COMPILER_VM_RSS_GUARD:-1}"
export MINIWEBAPP_SERVE_GATE="${MINIWEBAPP_SERVE_GATE:-1}"
export MINIWEBAPP_WEB_SMOKE_GATE="${MINIWEBAPP_WEB_SMOKE_GATE:-1}"
export MINIWEBAPP_WEB_SMOKE_AOT_GATE="${MINIWEBAPP_WEB_SMOKE_AOT_GATE:-1}" # default on (#1523, #833)
export SESSIONS_WEB_SMOKE_GATE="${SESSIONS_WEB_SMOKE_GATE:-1}" # default on (#1887); 005-SessionsWeb cookie curls
export MINIWEBAPP_AOT_LINK_GATE="${MINIWEBAPP_AOT_LINK_GATE:-1}"
export MINIWEBAPP_AOT_EXECUTE_GATE="${MINIWEBAPP_AOT_EXECUTE_GATE:-1}" # default on (#747)
export MINIWEBAPP_JIT_PROJECT_GATE="${MINIWEBAPP_JIT_PROJECT_GATE:-0}" # opt-in (#587)
Expand Down
2 changes: 2 additions & 0 deletions script/ci-fast.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ if [[ -z "${PHP_COMPILER_SKIP_SERVE_TESTS:-}" ]]; then
echo "PHPUnit (fast): MiniWebApp ServeTest (MINIWEBAPP_SERVE_GATE=1 default, #470, #641)..."
ci_run_phpunit --filter ServeTest --group miniwebapp --fail-on-skipped "$@"
fi

ci_run_sessions_web_smoke
fi

# Always lint 003-MiniWebApp even when callers pass --filter (issue #570, #539).
Expand Down
2 changes: 2 additions & 0 deletions script/ci-local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ if [[ -z "${PHP_COMPILER_SKIP_SERVE_TESTS:-}" ]]; then
if [[ "${MINIWEBAPP_WEB_SMOKE_GATE:-1}" == "1" ]]; then
ci_run_miniwebapp_web_smoke
fi

ci_run_sessions_web_smoke
fi

if ci_llvm_ready; then
Expand Down
116 changes: 115 additions & 1 deletion script/examples-web-smoke.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,31 @@ PHPC="${ROOT}/phpc"

usage() {
cat <<'EOF'
Usage: script/examples-web-smoke.sh [--aot] [--miniwebapp-only]
Usage: script/examples-web-smoke.sh [--aot] [--miniwebapp-only] [--sessions-only]

VM mode (default): phpc serve per example docroot.
--aot: use phpc serve --aot when <docroot>/.phpc/bin/app exists; skip otherwise.
003-MiniWebApp: home + hello PATH_INFO + contact POST when stdout has MiniWebApp (#833, #676).
--miniwebapp-only: curl only examples/003-MiniWebApp (MINIWEBAPP_WEB_SMOKE_GATE — #633).
--sessions-only: curl only examples/005-SessionsWeb (SESSIONS_WEB_SMOKE_GATE — #1887).

Environment:
PHP_COMPILER_SKIP_SERVE_TESTS=1 exit 0 without running HTTP checks
PHP_COMPILER_MAX_BODY optional; 003 oversized POST check uses 1024 when unset (#705)
MINIWEBAPP_AOT_EXECUTE_GATE=1 fail instead of skip when 003 AOT probe empty (#747, #676)
MINIWEBAPP_WEB_SMOKE_AOT_GATE=1 require 003 --aot curls to pass (#833)
SESSIONS_WEB_SMOKE_GATE=1 include 005 session flash curls in default run (#1887)
EOF
}

AOT=0
MINIWEBAPP_ONLY=0
SESSIONS_ONLY=0
while [[ $# -gt 0 ]]; do
case "$1" in
--aot) AOT=1; shift ;;
--miniwebapp-only) MINIWEBAPP_ONLY=1; shift ;;
--sessions-only) SESSIONS_ONLY=1; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "examples-web-smoke: unknown argument: $1" >&2; usage >&2; exit 1 ;;
esac
Expand Down Expand Up @@ -171,6 +175,56 @@ curl_expect_post_not_200() {
echo "examples-web-smoke: ${label}: ok (HTTP ${status})"
}

curl_expect_200_cookies() {
local label="$1"
local url="$2"
local jar="$3"
shift 3
local needles=("$@")
local body status
body="$(mktemp)"
status="$(curl -sS -o "$body" -w '%{http_code}' -b "$jar" -c "$jar" \
--connect-timeout 5 --max-time 15 "$url" || echo "000")"
if [[ "$status" != "200" ]]; then
echo "examples-web-smoke: ${label}: expected HTTP 200, got ${status}" >&2
echo " url: ${url}" >&2
cat "$body" >&2 || true
rm -f "$body"
return 1
fi
for needle in "${needles[@]}"; do
if ! grep -qF "$needle" "$body"; then
echo "examples-web-smoke: ${label}: response missing needle: ${needle}" >&2
echo " url: ${url}" >&2
cat "$body" >&2 || true
rm -f "$body"
return 1
fi
done
rm -f "$body"
echo "examples-web-smoke: ${label}: ok"
}

curl_expect_303_post_cookies() {
local label="$1"
local url="$2"
local jar="$3"
local post_body="$4"
local body status
body="$(mktemp)"
status="$(curl -sS -o "$body" -w '%{http_code}' -b "$jar" -c "$jar" \
-X POST -d "$post_body" --connect-timeout 5 --max-time 15 "$url" || echo "000")"
if [[ "$status" != "303" ]]; then
echo "examples-web-smoke: ${label}: expected HTTP 303, got ${status}" >&2
echo " url: ${url}" >&2
cat "$body" >&2 || true
rm -f "$body"
return 1
fi
rm -f "$body"
echo "examples-web-smoke: ${label}: ok"
}

resolve_llvm_dir() {
if [[ -n "${PHP_COMPILER_LLVM_PATH:-}" ]]; then
if [[ -f "${PHP_COMPILER_LLVM_PATH}/libLLVM-9.so.1" ]]; then
Expand Down Expand Up @@ -313,6 +367,55 @@ run_miniwebapp_oversized_post_smoke() {
trap - RETURN
}

run_sessions_web_smoke() {
local docroot="${ROOT}/examples/005-SessionsWeb"
if [[ ! -d "$docroot" ]]; then
echo "examples-web-smoke: 005-SessionsWeb: skip (missing docroot)"
return 0
fi
if [[ "$AOT" -eq 1 ]]; then
echo "examples-web-smoke: 005-SessionsWeb: skip --aot (VM only until #1891)"
return 0
fi

local port pid jar
jar="$(mktemp)"
port="$(find_free_port)"
echo "examples-web-smoke: 005-SessionsWeb on 127.0.0.1:${port} (VM session flash)"
"${PHPC}" serve "127.0.0.1:${port}" "$docroot" >/dev/null 2>&1 &
pid=$!

stop_serve() {
kill "$pid" 2>/dev/null || true
local waited=0
while kill -0 "$pid" 2>/dev/null && ((waited < 40)); do
sleep 0.05
waited=$((waited + 1))
done
if kill -0 "$pid" 2>/dev/null; then
kill -9 "$pid" 2>/dev/null || true
fi
wait "$pid" 2>/dev/null || true
}
trap stop_serve RETURN

wait_for_serve "$port"

local base="http://127.0.0.1:${port}"
curl_expect_200_cookies "005-SessionsWeb / GET empty" "${base}/example.php" "$jar" \
"No flash message yet"
curl_expect_303_post_cookies "005-SessionsWeb / POST flash" "${base}/example.php" \
"$jar" "message=Saved"
curl_expect_200_cookies "005-SessionsWeb / GET flash" "${base}/example.php" "$jar" \
"Flash: Saved"
curl_expect_200_cookies "005-SessionsWeb / GET after flash" "${base}/example.php" "$jar" \
"No flash message yet"

rm -f "$jar"
stop_serve
trap - RETURN
}

run_docroot_smoke() {
local name="$1"
local docroot="${ROOT}/${2}"
Expand Down Expand Up @@ -391,8 +494,15 @@ run_docroot_smoke() {
mode_label="VM"
[[ "$AOT" -eq 1 ]] && mode_label="--aot"
[[ "$MINIWEBAPP_ONLY" -eq 1 ]] && mode_label="${mode_label}; --miniwebapp-only"
[[ "$SESSIONS_ONLY" -eq 1 ]] && mode_label="${mode_label}; --sessions-only"
echo "examples-web-smoke: starting (${mode_label})"

if [[ "${SESSIONS_ONLY}" -eq 1 ]]; then
run_sessions_web_smoke
echo "examples-web-smoke: ok"
exit 0
fi

if [[ "${MINIWEBAPP_ONLY}" -eq 0 ]]; then
run_docroot_smoke "001-SimpleWeb" "examples/001-SimpleWeb" \
"GET|GET example.php?name=Smoke|/example.php?name=Smoke|-|Hello;Smoke" \
Expand All @@ -405,6 +515,10 @@ if [[ "${MINIWEBAPP_ONLY}" -eq 0 ]]; then

run_docroot_smoke "004-ApiJson" "examples/004-ApiJson" \
'GET|GET example.php|/example.php|-|"ok":true;php-compiler'

if [[ "${SESSIONS_WEB_SMOKE_GATE:-1}" == "1" ]]; then
run_sessions_web_smoke
fi
fi

MINIWEBAPP=examples/003-MiniWebApp
Expand Down
28 changes: 27 additions & 1 deletion test/unit/CiScriptsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,33 @@ public function testCiFastDoesNotRunMiniWebAppWebSmokeGate(): void
$fast = dirname(__DIR__, 2).'/script/ci-fast.sh';
$body = (string) file_get_contents($fast);
$this->assertStringNotContainsString('ci_run_miniwebapp_web_smoke', $body);
$this->assertStringNotContainsString('examples-web-smoke.sh', $body);
$this->assertStringNotContainsString('examples-web-smoke.sh --miniwebapp-only', $body);
}

public function testCiFastRunsSessionsWebSmokeGate(): void
{
$fast = dirname(__DIR__, 2).'/script/ci-fast.sh';
$body = (string) file_get_contents($fast);
$this->assertStringContainsString('ci_run_sessions_web_smoke', $body);

$common = (string) file_get_contents(dirname(__DIR__, 2).'/script/ci-common.sh');
$this->assertStringContainsString('SESSIONS_WEB_SMOKE_GATE', $common);
$this->assertStringContainsString('--sessions-only', $common);
}

public function testCiDefaultsEnvDefinesSessionsWebSmokeGateOn(): void
{
$defaults = (string) file_get_contents(dirname(__DIR__, 2).'/script/ci-defaults.env');
$this->assertStringContainsString(
'SESSIONS_WEB_SMOKE_GATE="${SESSIONS_WEB_SMOKE_GATE:-1}"',
$defaults
);
}

public function testCiLocalRunsSessionsWebSmokeGate(): void
{
$local = (string) file_get_contents(dirname(__DIR__, 2).'/script/ci-local.sh');
$this->assertStringContainsString('ci_run_sessions_web_smoke', $local);
}

public function testCiFastHonorsMiniWebAppServeGate(): void
Expand Down
Loading