Skip to content

Commit ee3195b

Browse files
committed
Add Worker_TaskTest.
1 parent 061feda commit ee3195b

File tree

1 file changed

+237
-0
lines changed

1 file changed

+237
-0
lines changed
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
<?php
2+
/**
3+
* Class Google\Site_Kit\Tests\Core\Email_Reporting\Worker_TaskTest
4+
*
5+
* @package Google\Site_Kit\Tests\Core\Email_Reporting
6+
*/
7+
8+
namespace Google\Site_Kit\Tests\Core\Email_Reporting;
9+
10+
use Google\Site_Kit\Context;
11+
use Google\Site_Kit\Core\Email_Reporting\Email_Log;
12+
use Google\Site_Kit\Core\Email_Reporting\Email_Log_Batch_Query;
13+
use Google\Site_Kit\Core\Email_Reporting\Email_Reporting_Scheduler;
14+
use Google\Site_Kit\Core\Email_Reporting\Max_Execution_Limiter;
15+
use Google\Site_Kit\Core\Email_Reporting\Worker_Task;
16+
use Google\Site_Kit\Core\User\Email_Reporting_Settings;
17+
use Google\Site_Kit\Tests\TestCase;
18+
19+
class Worker_TaskTest extends TestCase {
20+
21+
/**
22+
* @var Email_Reporting_Scheduler|\PHPUnit_Framework_MockObject_MockObject
23+
*/
24+
private $scheduler;
25+
26+
/**
27+
* @var Email_Log_Batch_Query|\PHPUnit_Framework_MockObject_MockObject
28+
*/
29+
private $batch_query;
30+
31+
/**
32+
* @var Max_Execution_Limiter|\PHPUnit_Framework_MockObject_MockObject
33+
*/
34+
private $limiter;
35+
36+
/**
37+
* @var array
38+
*/
39+
private $created_post_ids = array();
40+
41+
public function set_up() {
42+
parent::set_up();
43+
44+
$this->scheduler = $this->createMock( Email_Reporting_Scheduler::class );
45+
$this->batch_query = $this->createMock( Email_Log_Batch_Query::class );
46+
$this->limiter = $this->createMock( Max_Execution_Limiter::class );
47+
$this->created_post_ids = array();
48+
}
49+
50+
public function tear_down() {
51+
foreach ( $this->created_post_ids as $post_id ) {
52+
wp_delete_post( $post_id, true );
53+
}
54+
55+
if ( post_type_exists( Email_Log::POST_TYPE ) && function_exists( 'unregister_post_type' ) ) {
56+
unregister_post_type( Email_Log::POST_TYPE );
57+
}
58+
59+
foreach ( array( Email_Log::STATUS_SENT, Email_Log::STATUS_FAILED, Email_Log::STATUS_SCHEDULED ) as $status ) {
60+
if ( isset( $GLOBALS['wp_post_statuses'][ $status ] ) ) {
61+
unset( $GLOBALS['wp_post_statuses'][ $status ] );
62+
}
63+
}
64+
65+
foreach (
66+
array(
67+
Email_Log::META_REPORT_FREQUENCY,
68+
Email_Log::META_BATCH_ID,
69+
Email_Log::META_SEND_ATTEMPTS,
70+
Email_Log::META_ERROR_DETAILS,
71+
Email_Log::META_REPORT_REFERENCE_DATES,
72+
) as $meta_key
73+
) {
74+
if ( function_exists( 'unregister_meta_key' ) ) {
75+
unregister_meta_key( 'post', Email_Log::POST_TYPE, $meta_key );
76+
}
77+
}
78+
79+
parent::tear_down();
80+
}
81+
82+
public function test_acquires_and_clears_lock() {
83+
$task = new Worker_Task( $this->limiter, $this->batch_query, $this->scheduler );
84+
$transient_name = 'googlesitekit_email_reporting_worker_lock_weekly';
85+
$initiator_stamp = time();
86+
87+
$this->limiter->expects( $this->once() )
88+
->method( 'should_abort' )
89+
->with( $initiator_stamp )
90+
->willReturn( false );
91+
92+
$this->batch_query->expects( $this->once() )
93+
->method( 'is_complete' )
94+
->with( 'batch-lock' )
95+
->willReturn( true );
96+
97+
$this->batch_query->expects( $this->never() )
98+
->method( 'get_pending_ids' );
99+
100+
$task->handle_callback_action( 'batch-lock', Email_Reporting_Settings::FREQUENCY_WEEKLY, $initiator_stamp );
101+
102+
$this->assertFalse( get_transient( $transient_name ), 'Transient lock should be cleared after execution.' );
103+
}
104+
105+
public function test_existing_lock_short_circuits_worker() {
106+
$task = new Worker_Task( $this->limiter, $this->batch_query, $this->scheduler );
107+
$transient_name = 'googlesitekit_email_reporting_worker_lock_monthly';
108+
set_transient( $transient_name, time(), MINUTE_IN_SECONDS );
109+
110+
$this->limiter->expects( $this->never() )->method( 'should_abort' );
111+
$this->batch_query->expects( $this->never() )->method( 'is_complete' );
112+
113+
$task->handle_callback_action( 'batch-lock', Email_Reporting_Settings::FREQUENCY_MONTHLY, time() );
114+
115+
$this->assertNotFalse( get_transient( $transient_name ), 'Existing lock should remain untouched when worker skips execution.' );
116+
}
117+
118+
public function test_exits_without_rescheduling_when_complete() {
119+
$task = new Worker_Task( $this->limiter, $this->batch_query, $this->scheduler );
120+
121+
$this->limiter->method( 'should_abort' )->willReturn( false );
122+
123+
$this->batch_query->expects( $this->once() )
124+
->method( 'is_complete' )
125+
->willReturn( true );
126+
127+
$this->scheduler->expects( $this->never() )
128+
->method( 'schedule_worker' );
129+
130+
$task->handle_callback_action( 'batch-complete', Email_Reporting_Settings::FREQUENCY_WEEKLY, time() );
131+
}
132+
133+
public function test_schedules_follow_up_for_pending_ids() {
134+
$task = new Worker_Task( $this->limiter, $this->batch_query, $this->scheduler );
135+
$initiator_stamp = time();
136+
$pending_ids = array( 11, 22 );
137+
$expected_delay = 11 * MINUTE_IN_SECONDS;
138+
$captured_delay = null;
139+
140+
$this->limiter->expects( $this->exactly( 5 ) )
141+
->method( 'should_abort' )
142+
->with( $initiator_stamp )
143+
->willReturnOnConsecutiveCalls( false, false, false, false, false );
144+
145+
$this->batch_query->expects( $this->once() )
146+
->method( 'is_complete' )
147+
->willReturn( false );
148+
149+
$this->batch_query->expects( $this->once() )
150+
->method( 'get_pending_ids' )
151+
->willReturn( $pending_ids );
152+
153+
$this->batch_query->expects( $this->exactly( count( $pending_ids ) ) )
154+
->method( 'increment_attempt' )
155+
->withConsecutive( array( $pending_ids[0] ), array( $pending_ids[1] ) );
156+
157+
$this->scheduler->expects( $this->once() )
158+
->method( 'schedule_worker' )
159+
->with(
160+
'batch-follow-up',
161+
Email_Reporting_Settings::FREQUENCY_WEEKLY,
162+
$initiator_stamp,
163+
$this->callback(
164+
function ( $delay ) use ( $initiator_stamp, &$captured_delay, $expected_delay ) {
165+
$captured_delay = $delay;
166+
return $delay >= $expected_delay;
167+
}
168+
)
169+
);
170+
171+
$task->handle_callback_action( 'batch-follow-up', Email_Reporting_Settings::FREQUENCY_WEEKLY, $initiator_stamp );
172+
173+
$this->assertNotNull( $captured_delay, 'Follow-up delay should be captured for assertion.' );
174+
}
175+
176+
public function test_increments_attempts_for_pending_posts() {
177+
$this->register_email_log_dependencies();
178+
179+
$real_query = new Email_Log_Batch_Query();
180+
$limiter = $this->createMock( Max_Execution_Limiter::class );
181+
$limiter->method( 'should_abort' )->willReturn( false );
182+
183+
$task = new Worker_Task( $limiter, $real_query, $this->scheduler );
184+
185+
$batch_id = 'batch-real';
186+
$scheduled_id = $this->create_log_post( $batch_id, Email_Log::STATUS_SCHEDULED, 0 );
187+
$retry_failed = $this->create_log_post( $batch_id, Email_Log::STATUS_FAILED, 2 );
188+
$max_failed = $this->create_log_post( $batch_id, Email_Log::STATUS_FAILED, Email_Log_Batch_Query::MAX_ATTEMPTS );
189+
$completed_sent = $this->create_log_post( $batch_id, Email_Log::STATUS_SENT, 1 );
190+
191+
$this->scheduler->expects( $this->once() )
192+
->method( 'schedule_worker' )
193+
->with(
194+
$batch_id,
195+
Email_Reporting_Settings::FREQUENCY_WEEKLY,
196+
$this->isType( 'int' ),
197+
$this->greaterThanOrEqual( 11 * MINUTE_IN_SECONDS )
198+
);
199+
200+
$task->handle_callback_action( $batch_id, Email_Reporting_Settings::FREQUENCY_WEEKLY, time() );
201+
202+
$this->assertSame( 1, (int) get_post_meta( $scheduled_id, Email_Log::META_SEND_ATTEMPTS, true ), 'Scheduled post attempts should increment.' );
203+
$this->assertSame( 3, (int) get_post_meta( $retry_failed, Email_Log::META_SEND_ATTEMPTS, true ), 'Retriable failed post attempts should increment.' );
204+
$this->assertSame( Email_Log_Batch_Query::MAX_ATTEMPTS, (int) get_post_meta( $max_failed, Email_Log::META_SEND_ATTEMPTS, true ), 'Posts at max attempts should not change.' );
205+
$this->assertSame( 1, (int) get_post_meta( $completed_sent, Email_Log::META_SEND_ATTEMPTS, true ), 'Completed posts should remain untouched.' );
206+
}
207+
208+
private function create_log_post( $batch_id, $status, $attempts ) {
209+
$post_id = wp_insert_post(
210+
array(
211+
'post_type' => Email_Log::POST_TYPE,
212+
'post_status' => $status,
213+
'post_title' => 'Worker Log ' . uniqid(),
214+
'meta_input' => array(
215+
Email_Log::META_BATCH_ID => $batch_id,
216+
Email_Log::META_REPORT_FREQUENCY => Email_Reporting_Settings::FREQUENCY_WEEKLY,
217+
Email_Log::META_SEND_ATTEMPTS => $attempts,
218+
),
219+
)
220+
);
221+
222+
$this->created_post_ids[] = $post_id;
223+
224+
return $post_id;
225+
}
226+
227+
private function register_email_log_dependencies() {
228+
if ( post_type_exists( Email_Log::POST_TYPE ) ) {
229+
return;
230+
}
231+
232+
$email_log = new Email_Log( new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ) );
233+
$register_method = new \ReflectionMethod( Email_Log::class, 'register_email_log' );
234+
$register_method->setAccessible( true );
235+
$register_method->invoke( $email_log );
236+
}
237+
}

0 commit comments

Comments
 (0)