PluginProbe
ووسلام – همگام سازی ووکامرس و باسلام / 1.10.14
ووسلام – همگام سازی ووکامرس و باسلام v1.10.14
1.10.19 1.10.20 1.10.18 1.10.17 1.10.15 1.10.14 1.10.13 1.10.12 1.10.10 1.10.9 1.10.8 1.10.7 1.10.6 1.10.5 1.10.4 1.10.3 1.10.2 1.10.1 1.10.0 1.9.2 1.9.1 1.9.0 1.8.8 1.8.5 1.8.6 All 53 releases
sync-basalam / tests / JobsRunnerTest.php

JobsRunnerTest.php in ووسلام – همگام سازی ووکامرس و باسلام 1.10.14, at tests/JobsRunnerTest.php

252 lines 8.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace SyncBasalam\Tests;
4
5 use PHPUnit\Framework\TestCase;
6 use SyncBasalam\JobsRunner;
7
8 class JobsRunnerTest extends TestCase
9 {
10 private const ASYNC_ACTION = 'sync_basalam_run_jobs_async';
11 private const DISPATCH_LOCK = 'sync_basalam_jobs_runner_async_dispatch_lock';
12
13 private $originalRequest;
14 private $originalCookie;
15
16 protected function setUp(): void
17 {
18 $this->originalRequest = $_REQUEST;
19 $this->originalCookie = $_COOKIE;
20
21 $_REQUEST = [];
22 $_COOKIE = [];
23
24 $GLOBALS['sync_basalam_jobs_runner_test_state'] = [
25 'actions' => [],
26 'did_actions' => [],
27 'doing_ajax' => false,
28 'transients' => [],
29 'transient_reads' => [],
30 'transient_writes' => [],
31 'filter_values' => [],
32 'events' => [],
33 'remote_requests' => [],
34 ];
35 }
36
37 protected function tearDown(): void
38 {
39 $_REQUEST = $this->originalRequest;
40 $_COOKIE = $this->originalCookie;
41
42 unset($GLOBALS['sync_basalam_jobs_runner_test_state']);
43 }
44
45 public function testRegistersDispatcherOnInitAndNeverOnShutdown(): void
46 {
47 $runner = $this->newRunner();
48 $actions = $this->state()['actions'];
49
50 self::assertArrayHasKey('init', $actions);
51 self::assertSame([$runner, 'maybeDispatchAsyncRequest'], $actions['init'][0]['callback']);
52 self::assertSame(10, $actions['init'][0]['priority']);
53 self::assertSame(0, $actions['init'][0]['accepted_args']);
54 self::assertArrayNotHasKey('shutdown', $actions);
55
56 self::assertSame(
57 [$runner, 'maybeDispatchAsyncRequest'],
58 $actions['sync_basalam_job_created'][0]['callback']
59 );
60 self::assertSame(0, $actions['sync_basalam_job_created'][0]['accepted_args']);
61 self::assertSame([$runner, 'handleAsyncRequest'], $actions['wp_ajax_' . self::ASYNC_ACTION][0]['callback']);
62 self::assertSame(
63 [$runner, 'handleAsyncRequest'],
64 $actions['wp_ajax_nopriv_' . self::ASYNC_ACTION][0]['callback']
65 );
66 }
67
68 public function testEligibleQueueIsConfirmedBeforeWritingLockAndDispatching(): void
69 {
70 $jobManager = new FakeJobManager([true]);
71 $runner = $this->newRunner($jobManager);
72
73 $_COOKIE = ['wordpress_test_cookie' => 'cookie-value'];
74 $runner->maybeDispatchAsyncRequest();
75
76 self::assertSame(
77 ['get_transient', 'has_pending_jobs', 'set_transient', 'remote_post'],
78 $this->state()['events']
79 );
80 self::assertSame([120], $jobManager->timeouts);
81 self::assertSame(
82 [[
83 'name' => self::DISPATCH_LOCK,
84 'value' => 1,
85 'expiration' => 1,
86 ]],
87 $this->state()['transient_writes']
88 );
89
90 $requests = $this->state()['remote_requests'];
91 self::assertCount(1, $requests);
92 self::assertSame(
93 'https://example.test/wp-admin/admin-ajax.php?action=' . self::ASYNC_ACTION,
94 $requests[0]['url']
95 );
96 self::assertSame(0.01, $requests[0]['args']['timeout']);
97 self::assertFalse($requests[0]['args']['blocking']);
98 self::assertSame(self::ASYNC_ACTION, $requests[0]['args']['body']['action']);
99 self::assertSame('test-nonce-for-' . self::ASYNC_ACTION, $requests[0]['args']['body']['nonce']);
100 self::assertSame($_COOKIE, $requests[0]['args']['cookies']);
101 }
102
103 public function testEmptyQueueDoesNotWriteLockOrDispatch(): void
104 {
105 $jobManager = new FakeJobManager([false]);
106 $runner = $this->newRunner($jobManager);
107
108 $runner->maybeDispatchAsyncRequest();
109
110 self::assertSame(['get_transient', 'has_pending_jobs'], $this->state()['events']);
111 self::assertSame([120], $jobManager->timeouts);
112 self::assertSame([], $this->state()['transient_writes']);
113 self::assertSame([], $this->state()['remote_requests']);
114 }
115
116 public function testJobCreatedAfterAnEmptyInitCanStillDispatch(): void
117 {
118 $jobManager = new FakeJobManager([false, true]);
119 $runner = $this->newRunner($jobManager);
120
121 // The init probe sees no work and must not reserve the dispatch lock.
122 $runner->maybeDispatchAsyncRequest();
123 self::assertSame([], $this->state()['transient_writes']);
124
125 // A job created later in the same request must still wake the runner.
126 $runner->maybeDispatchAsyncRequest();
127
128 self::assertSame([120, 120], $jobManager->timeouts);
129 self::assertCount(1, $this->state()['transient_writes']);
130 self::assertCount(1, $this->state()['remote_requests']);
131 }
132
133 public function testExistingLockSkipsQueueCheckAndDispatch(): void
134 {
135 $GLOBALS['sync_basalam_jobs_runner_test_state']['transients'][self::DISPATCH_LOCK] = 1;
136 $jobManager = new FakeJobManager([true]);
137 $runner = $this->newRunner($jobManager);
138
139 $runner->maybeDispatchAsyncRequest();
140
141 self::assertSame(['get_transient'], $this->state()['events']);
142 self::assertSame([], $jobManager->timeouts);
143 self::assertSame([], $this->state()['transient_writes']);
144 self::assertSame([], $this->state()['remote_requests']);
145 }
146
147 public function testSelfAsyncRequestReturnsBeforeQueueAndLockChecks(): void
148 {
149 $GLOBALS['sync_basalam_jobs_runner_test_state']['doing_ajax'] = true;
150 $_REQUEST['action'] = self::ASYNC_ACTION;
151
152 $jobManager = new FakeJobManager([true]);
153 $httpBlockService = new FakeHttpBlockService(false);
154 $runner = $this->newRunner($jobManager, $httpBlockService);
155
156 $runner->maybeDispatchAsyncRequest();
157
158 self::assertSame(0, $httpBlockService->calls);
159 $this->assertNoQueueLockOrDispatchActivity($jobManager);
160 }
161
162 public function testHttpBlockReturnsBeforeQueueAndLockChecks(): void
163 {
164 $jobManager = new FakeJobManager([true]);
165 $httpBlockService = new FakeHttpBlockService(true);
166 $runner = $this->newRunner($jobManager, $httpBlockService);
167
168 $runner->maybeDispatchAsyncRequest();
169
170 self::assertSame(1, $httpBlockService->calls);
171 $this->assertNoQueueLockOrDispatchActivity($jobManager);
172 }
173
174 public function testShutdownGuardPreventsEveryDispatchSideEffect(): void
175 {
176 $GLOBALS['sync_basalam_jobs_runner_test_state']['did_actions']['shutdown'] = 1;
177
178 $jobManager = new FakeJobManager([true]);
179 $httpBlockService = new FakeHttpBlockService(false);
180 $runner = $this->newRunner($jobManager, $httpBlockService);
181
182 $runner->maybeDispatchAsyncRequest();
183
184 self::assertSame(0, $httpBlockService->calls);
185 $this->assertNoQueueLockOrDispatchActivity($jobManager);
186 }
187
188 private function newRunner(
189 ?FakeJobManager $jobManager = null,
190 ?FakeHttpBlockService $httpBlockService = null
191 ): JobsRunner {
192 return new JobsRunner(
193 $jobManager ?? new FakeJobManager(),
194 new \stdClass(),
195 new \stdClass(),
196 $httpBlockService ?? new FakeHttpBlockService(false)
197 );
198 }
199
200 private function assertNoQueueLockOrDispatchActivity(FakeJobManager $jobManager): void
201 {
202 self::assertSame([], $jobManager->timeouts);
203 self::assertSame([], $this->state()['transient_reads']);
204 self::assertSame([], $this->state()['transient_writes']);
205 self::assertSame([], $this->state()['remote_requests']);
206 }
207
208 private function state(): array
209 {
210 return $GLOBALS['sync_basalam_jobs_runner_test_state'];
211 }
212 }
213
214 class FakeJobManager
215 {
216 public $timeouts = [];
217
218 private $pendingResults;
219
220 public function __construct(array $pendingResults = [])
221 {
222 $this->pendingResults = $pendingResults;
223 }
224
225 public function hasPendingOrStaleProcessingJobs(int $timeout): bool
226 {
227 $GLOBALS['sync_basalam_jobs_runner_test_state']['events'][] = 'has_pending_jobs';
228 $this->timeouts[] = $timeout;
229
230 return (bool) array_shift($this->pendingResults);
231 }
232 }
233
234 class FakeHttpBlockService
235 {
236 public $calls = 0;
237
238 private $blocked;
239
240 public function __construct(bool $blocked)
241 {
242 $this->blocked = $blocked;
243 }
244
245 public function SyncBasalamHttpBlock()
246 {
247 $this->calls++;
248
249 return $this->blocked;
250 }
251 }
252