v0.3.2 — adopt estate CI: PHPUnit suite + reusable pipeline + governance workflows
- Convert 17 hand-rolled tests to PHPUnit TestCases (tests: stubs pattern) P0 security tests preserved: key-leak/encryption (KeyStoreTest), capture-allowlist/executor-path sentinel (CaptureWriterTest) - Add phpunit.xml.dist + update tests/bootstrap.php (Composer autoloader first) - Add phpunit/phpunit ^9.6 + yoast/phpunit-polyfills ^2.0 to require-dev - composer test -> vendor/bin/phpunit --configuration phpunit.xml.dist - ci.yml: thin caller of peptide-e2e reusable CI (tests: stubs, has_js: true, workflow_call trigger, permissions: contents: write) - deploy.yml: estate pattern caller of peptide-e2e deploy-app.yml@main (target_path: wp-content/plugins/pr-vision, gated on reusable CI) Pull-deploy on Hostinger stays as break-glass - Add cto-review.yml (Haiku-only, A/B panel dropped 2026-06-12) - Add main-push-audit.yml (direct-push tripwire) Agent-Session: claude-adopt-ci-20260616
This commit is contained in:
101
tests/unit/CronGuardTest.php
Normal file
101
tests/unit/CronGuardTest.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
/**
|
||||
* Tests for PRV_Cron_Guard: self-healing cron scheduling.
|
||||
*
|
||||
* @package PrVision
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers PRV_Cron_Guard
|
||||
*/
|
||||
class CronGuardTest extends TestCase {
|
||||
|
||||
protected function setUp(): void {
|
||||
prv_test_reset();
|
||||
}
|
||||
|
||||
public function test_ensure_scheduled_schedules_weekly_hook(): void {
|
||||
$this->assertFalse( wp_next_scheduled( PRV_CRON_HOOK ), 'guard/weekly: not scheduled before call' );
|
||||
|
||||
$guard = new PRV_Cron_Guard();
|
||||
$guard->ensure_scheduled();
|
||||
|
||||
$this->assertNotFalse( wp_next_scheduled( PRV_CRON_HOOK ), 'guard/weekly: prv_weekly_probe scheduled after ensure_scheduled()' );
|
||||
}
|
||||
|
||||
public function test_ensure_scheduled_schedules_prune_hook(): void {
|
||||
$this->assertFalse( wp_next_scheduled( PRV_Prune_Cron::PRUNE_HOOK ), 'guard/prune: not scheduled before call' );
|
||||
|
||||
$guard = new PRV_Cron_Guard();
|
||||
$guard->ensure_scheduled();
|
||||
|
||||
$this->assertNotFalse( wp_next_scheduled( PRV_Prune_Cron::PRUNE_HOOK ), 'guard/prune: prv_daily_prune scheduled after ensure_scheduled()' );
|
||||
}
|
||||
|
||||
public function test_ensure_scheduled_is_idempotent(): void {
|
||||
$guard = new PRV_Cron_Guard();
|
||||
$guard->ensure_scheduled();
|
||||
|
||||
$ts_weekly_1 = wp_next_scheduled( PRV_CRON_HOOK );
|
||||
$ts_prune_1 = wp_next_scheduled( PRV_Prune_Cron::PRUNE_HOOK );
|
||||
|
||||
$guard->ensure_scheduled(); // Second call.
|
||||
|
||||
$ts_weekly_2 = wp_next_scheduled( PRV_CRON_HOOK );
|
||||
$ts_prune_2 = wp_next_scheduled( PRV_Prune_Cron::PRUNE_HOOK );
|
||||
|
||||
$this->assertSame( $ts_weekly_1, $ts_weekly_2, 'guard/idempotent: weekly event timestamp unchanged after second call' );
|
||||
$this->assertSame( $ts_prune_1, $ts_prune_2, 'guard/idempotent: prune event timestamp unchanged after second call' );
|
||||
|
||||
$cron_events = $GLOBALS['prv_test_state']['cron_events'];
|
||||
$this->assertArrayHasKey( PRV_CRON_HOOK, $cron_events, 'guard/idempotent: exactly one weekly event entry' );
|
||||
$this->assertArrayHasKey( PRV_Prune_Cron::PRUNE_HOOK, $cron_events, 'guard/idempotent: exactly one prune event entry' );
|
||||
$this->assertCount( 2, $cron_events, 'guard/idempotent: only two cron event entries total' );
|
||||
}
|
||||
|
||||
public function test_guard_uses_same_recurrence_as_canonical_schedulers(): void {
|
||||
$GLOBALS['prv_test_state']['options'][ PRV_Config::CADENCE_KEY ] = 'weekly';
|
||||
PRV_Cron::schedule();
|
||||
$canonical_weekly = $GLOBALS['prv_test_state']['cron_events'][ PRV_CRON_HOOK ]['schedule'] ?? null;
|
||||
|
||||
prv_test_reset();
|
||||
PRV_Prune_Cron::schedule();
|
||||
$canonical_prune = $GLOBALS['prv_test_state']['cron_events'][ PRV_Prune_Cron::PRUNE_HOOK ]['schedule'] ?? null;
|
||||
|
||||
prv_test_reset();
|
||||
$GLOBALS['prv_test_state']['options'][ PRV_Config::CADENCE_KEY ] = 'weekly';
|
||||
$guard2 = new PRV_Cron_Guard();
|
||||
$guard2->ensure_scheduled();
|
||||
|
||||
$guard_weekly = $GLOBALS['prv_test_state']['cron_events'][ PRV_CRON_HOOK ]['schedule'] ?? null;
|
||||
$guard_prune = $GLOBALS['prv_test_state']['cron_events'][ PRV_Prune_Cron::PRUNE_HOOK ]['schedule'] ?? null;
|
||||
|
||||
$this->assertSame( $canonical_weekly, $guard_weekly, 'guard/recurrence: weekly matches canonical PRV_Cron::schedule()' );
|
||||
$this->assertSame( $canonical_prune, $guard_prune, 'guard/recurrence: prune matches canonical PRV_Prune_Cron::schedule()' );
|
||||
}
|
||||
|
||||
public function test_ensure_scheduled_noop_when_both_already_scheduled(): void {
|
||||
$GLOBALS['prv_test_state']['options'][ PRV_Config::CADENCE_KEY ] = 'weekly';
|
||||
PRV_Cron::schedule();
|
||||
PRV_Prune_Cron::schedule();
|
||||
$before = $GLOBALS['prv_test_state']['cron_events'];
|
||||
|
||||
$guard3 = new PRV_Cron_Guard();
|
||||
$guard3->ensure_scheduled();
|
||||
|
||||
$after = $GLOBALS['prv_test_state']['cron_events'];
|
||||
$this->assertSame( $before, $after, 'guard/noop: cron_events unchanged when all events already scheduled' );
|
||||
}
|
||||
|
||||
public function test_register_hooks_adds_init_action(): void {
|
||||
$guard4 = new PRV_Cron_Guard();
|
||||
$guard4->register_hooks();
|
||||
|
||||
$hooks = array_column( $GLOBALS['prv_test_state']['actions'], 'hook' );
|
||||
$this->assertContains( 'init', $hooks, 'guard/register_hooks: init action registered' );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user