Commits
Tarun Sukhani authored 474143c8c8e
feat: playAutotest task — headless test orchestration via FirePhoque (PF-90) Phase 4 addition. playAutotest mirrors play autotest's two-JVM orchestration: 1. POST /@kill to free the port from any prior instance. 2. Wipe tmp/ and test-result/. 3. Build extra sysprops from -PrunUnit / -PrunFunctional / -PrunSelenium / -PwebclientTimeout flags (matching --unit / --functional / --selenium / --timeout in the Python CLI). 4. Start Play in test mode in a background process via ProcessBuilder, redirecting stdout/stderr to logs/system.out. 5. Poll system.out for "Server is up and running" (60s timeout, bails if process dies first). 6. Start FirePhoque in foreground with its own classpath (modules/testrunner/conf, play-testrunner.jar, firephoque/*.jar) and main play.modules.testrunner.FirePhoque. inheritIO so the user sees test progress in real time. 7. Read test-result/result.passed or result.failed. 8. POST /@kill to terminate Play gracefully. 9. Throw GradleException on failure or non-completion; otherwise exit 0. Mirrors framework/pym/play/commands/autotest.py exactly. Cannot be a single JavaExec because two JVMs need to be coordinated; implemented as a custom DefaultTask using ProcessBuilder directly since Gradle's ExecOperations.exec is blocking. Verified against /tmp/play4-verify (cleaned up): orchestration works end-to-end -- Play starts in test mode, FirePhoque connects to /@tests.list, plugin correctly detects no result file and throws GradleException, plugin's finally block kills the Play process cleanly. Full happy-path (FirePhoque-driven test execution producing result.passed) needs a real app with proper static-asset routes for the testrunner UI; will be exercised in Phase 7 when migrating jclaw and the other consumer apps. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>