query(). * * @var string[] */ private array $queries = array(); protected function setUp(): void { parent::setUp(); $this->queries = array(); // Local mock: the reaper also uses get_col(), which the shared // BaseTestCase mock does not declare. $this->wpdb = $this->getMockBuilder( \stdClass::class ) ->addMethods( array( 'prepare', 'get_var', 'get_results', 'get_col', 'insert', 'query', 'get_row', 'update' ) ) ->getMock(); $this->wpdb->prefix = 'wp_'; $this->wpdb->insert_id = 0; $this->wpdb->last_error = ''; $GLOBALS['wpdb'] = $this->wpdb; $this->wpdb->method( 'prepare' )->willReturnCallback( static function ( $sql, ...$args ) { return $sql . ' /* ' . implode( ',', array_map( 'strval', $args ) ) . ' */'; } ); Functions\when( 'apply_filters' )->returnArg( 2 ); \PRAutoBlogger_Run_State::flush_cache(); \PRAutoBlogger_Run_Stage_State::flush_cache(); } protected function tearDown(): void { \PRAutoBlogger_Run_State::flush_cache(); \PRAutoBlogger_Run_Stage_State::flush_cache(); unset( $GLOBALS['wpdb'] ); parent::tearDown(); } /** * Retention 0 (or negative) means "keep forever": the pruner must not * issue any UPDATE. */ public function test_zero_retention_keeps_payloads_forever(): void { $this->stub_get_option( array( 'prautoblogger_request_json_retention_days' => 0, ) ); $this->wpdb->method( 'get_var' )->willReturn( null ); // No state tables. $this->wpdb->method( 'get_col' )->willReturn( array() ); $this->wpdb->expects( $this->never() )->method( 'query' ); $stats = \PRAutoBlogger_Run_Reaper::reap(); $this->assertSame( 0, $stats['payloads_pruned'] ); } /** * With the default setting the pruner NULLs request_json older than R * days on the generation log (and stage payloads when that table * exists). The sweeps only touch 'running'/open rows. */ public function test_reap_prunes_and_sweeps_with_setting_backed_window(): void { $this->stub_get_option( array( 'prautoblogger_request_json_retention_days' => PRAUTOBLOGGER_DEFAULT_REQUEST_JSON_RETENTION_DAYS, ) ); // Both state tables exist. $this->wpdb->method( 'get_var' )->willReturnCallback( static function ( $sql ) { if ( false !== strpos( (string) $sql, 'run_stages' ) ) { return 'wp_prautoblogger_run_stages'; } return 'wp_prautoblogger_runs'; } ); $this->wpdb->method( 'get_col' )->willReturn( array() ); // No stuck runs. $this->wpdb->method( 'query' )->willReturnCallback( function ( $sql ) { $this->queries[] = (string) $sql; return 2; } ); $stats = \PRAutoBlogger_Run_Reaper::reap(); $all_sql = implode( "\n", $this->queries ); $this->assertStringContainsString( 'request_json = NULL', $all_sql ); $this->assertStringContainsString( 'meta_json = NULL', $all_sql ); $this->assertStringContainsString( "status = 'failed'", $all_sql ); $this->assertStringContainsString( "WHERE status = 'running' AND updated_at <", $all_sql ); $this->assertSame( 4, $stats['payloads_pruned'] ); // 2 rows x 2 tables. } }