3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
13 * Ensure that various queue implementations comply with the interface
17 class CRM_Queue_QueueTest
extends CiviUnitTestCase
{
19 /* ----------------------- Queue providers ----------------------- */
21 /* Define a list of queue providers which should be tested */
24 * Return a list of persistent and transient queue providers.
26 public function getQueueSpecs() {
31 'name' => 'test-queue-sql',
37 'name' => 'test-queue-mem',
42 'type' => 'SqlParallel',
43 'name' => 'test-queue-sqlparallel',
52 public function setUp(): void
{
54 $this->queueService
= CRM_Queue_Service
::singleton(TRUE);
57 public function tearDown(): void
{
58 CRM_Utils_Time
::resetTime();
60 $tablesToTruncate = ['civicrm_queue_item', 'civicrm_queue'];
61 $this->quickCleanup($tablesToTruncate);
66 * Create a few queue items; alternately enqueue and dequeue various
68 * @dataProvider getQueueSpecs
71 public function testBasicUsage($queueSpec) {
72 $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_queue');
73 $this->queue
= $this->queueService
->create($queueSpec);
74 $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_queue');
75 $this->assertTrue($this->queue
instanceof CRM_Queue_Queue
);
76 $this->assertEquals($queueSpec['name'], $this->queue
->getSpec('name'));
77 $this->assertEquals($queueSpec['type'], $this->queue
->getSpec('type'));
79 $this->queue
->createItem([
82 $this->queue
->createItem([
85 $this->queue
->createItem([
89 $this->assertEquals(3, $this->queue
->numberOfItems());
90 $item = $this->queue
->claimItem();
91 $this->assertEquals('a', $item->data
['test-key']);
92 $this->queue
->deleteItem($item);
94 $this->assertEquals(2, $this->queue
->numberOfItems());
95 $item = $this->queue
->claimItem();
96 $this->assertEquals('b', $item->data
['test-key']);
97 $this->queue
->deleteItem($item);
99 $this->queue
->createItem([
103 $this->assertEquals(2, $this->queue
->numberOfItems());
104 $item = $this->queue
->claimItem();
105 $this->assertEquals('c', $item->data
['test-key']);
106 $this->queue
->deleteItem($item);
108 $this->assertEquals(1, $this->queue
->numberOfItems());
109 $item = $this->queue
->claimItem();
110 $this->assertEquals('d', $item->data
['test-key']);
111 $this->queue
->deleteItem($item);
113 $this->assertEquals(0, $this->queue
->numberOfItems());
117 * Claim an item from the queue and release it back for subsequent processing.
119 * @dataProvider getQueueSpecs
122 public function testManualRelease($queueSpec) {
123 $this->queue
= $this->queueService
->create($queueSpec);
124 $this->assertTrue($this->queue
instanceof CRM_Queue_Queue
);
126 $this->queue
->createItem([
130 $item = $this->queue
->claimItem();
131 $this->assertEquals('a', $item->data
['test-key']);
132 $this->assertEquals(1, $this->queue
->numberOfItems());
133 $this->queue
->releaseItem($item);
135 $this->assertEquals(1, $this->queue
->numberOfItems());
136 $item = $this->queue
->claimItem();
137 $this->assertEquals('a', $item->data
['test-key']);
138 $this->queue
->deleteItem($item);
140 $this->assertEquals(0, $this->queue
->numberOfItems());
144 * Test that item leases expire at the expected time.
146 * @dataProvider getQueueSpecs
150 public function testTimeoutRelease($queueSpec) {
151 $this->queue
= $this->queueService
->create($queueSpec);
152 $this->assertTrue($this->queue
instanceof CRM_Queue_Queue
);
154 CRM_Utils_Time
::setTime('2012-04-01 1:00:00');
155 $this->queue
->createItem([
159 $item = $this->queue
->claimItem();
160 $this->assertEquals('a', $item->data
['test-key']);
161 $this->assertEquals(1, $this->queue
->numberOfItems());
164 // haven't reach expiration yet
165 CRM_Utils_Time
::setTime('2012-04-01 1:59:00');
166 $item2 = $this->queue
->claimItem();
167 $this->assertEquals(FALSE, $item2);
169 // pass expiration mark
170 CRM_Utils_Time
::setTime('2012-04-01 2:00:03');
171 $item3 = $this->queue
->claimItem();
172 $this->assertEquals('a', $item3->data
['test-key']);
173 $this->assertEquals(1, $this->queue
->numberOfItems());
174 $this->queue
->deleteItem($item3);
176 $this->assertEquals(0, $this->queue
->numberOfItems());
180 * Test that item leases can be ignored.
182 * @dataProvider getQueueSpecs
185 public function testStealItem($queueSpec) {
186 $this->queue
= $this->queueService
->create($queueSpec);
187 $this->assertTrue($this->queue
instanceof CRM_Queue_Queue
);
189 CRM_Utils_Time
::setTime('2012-04-01 1:00:00');
190 $this->queue
->createItem([
194 $item = $this->queue
->claimItem();
195 $this->assertEquals('a', $item->data
['test-key']);
196 $this->assertEquals(1, $this->queue
->numberOfItems());
199 // haven't reached expiration yet, so claimItem fails
200 CRM_Utils_Time
::setTime('2012-04-01 1:59:00');
201 $item2 = $this->queue
->claimItem();
202 $this->assertEquals(FALSE, $item2);
204 // but stealItem works
205 $item3 = $this->queue
->stealItem();
206 $this->assertEquals('a', $item3->data
['test-key']);
207 $this->assertEquals(1, $this->queue
->numberOfItems());
208 $this->queue
->deleteItem($item3);
210 $this->assertEquals(0, $this->queue
->numberOfItems());
214 * Create a persistent queue via CRM_Queue_Service. Get a queue object with Civi::queue().
216 * @dataProvider getQueueSpecs
219 public function testPersistentUsage_service($queueSpec) {
220 $this->assertTrue(!empty($queueSpec['name']));
221 $this->assertTrue(!empty($queueSpec['type']));
223 $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_queue');
224 $q1 = CRM_Queue_Service
::singleton()->create($queueSpec +
[
225 'is_persistent' => TRUE,
227 $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_queue');
229 $q2 = Civi
::queue($queueSpec['name']);
230 $this->assertInstanceOf('CRM_Queue_Queue_' . $queueSpec['type'], $q2);
231 $this->assertTrue($q1 === $q2);
235 * Create a persistent queue via APIv4. Get a queue object with Civi::queue().
237 * @dataProvider getQueueSpecs
240 public function testPersistentUsage_api4($queueSpec) {
241 $this->assertTrue(!empty($queueSpec['name']));
242 $this->assertTrue(!empty($queueSpec['type']));
244 \Civi\Api4\Queue
::create(0)
245 ->setValues($queueSpec)
248 $q1 = Civi
::queue($queueSpec['name']);
249 $this->assertInstanceOf('CRM_Queue_Queue_' . $queueSpec['type'], $q1);
251 if ($queueSpec['type'] !== 'Memory') {
252 CRM_Queue_Service
::singleton(TRUE);
253 $q2 = CRM_Queue_Service
::singleton()->load([
254 'name' => $queueSpec['name'],
255 'is_persistent' => TRUE,
257 $this->assertInstanceOf('CRM_Queue_Queue_' . $queueSpec['type'], $q1);
261 public function testFacadeAutoCreate() {
262 $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_queue');
263 $q1 = Civi
::queue('testFacadeAutoCreate_q1', [
266 $q2 = Civi
::queue('testFacadeAutoCreate_q2', [
267 'type' => 'SqlParallel',
269 $q1Reload = Civi
::queue('testFacadeAutoCreate_q1', [
270 /* q1 already exists, so it doesn't matter what type you give. */
271 'type' => 'ZoombaroombaFaketypeGoombapoompa',
273 $this->assertDBQuery(2, 'SELECT count(*) FROM civicrm_queue');
274 $this->assertInstanceOf('CRM_Queue_Queue_Sql', $q1);
275 $this->assertInstanceOf('CRM_Queue_Queue_SqlParallel', $q2);
276 $this->assertInstanceOf('CRM_Queue_Queue_Sql', $q1Reload);
279 Civi
::queue('testFacadeAutoCreate_q3' /* missing type */);
280 $this->fail('Queue lookup should fail. There is neither pre-existing registration nor new details.');
282 catch (CRM_Core_Exception
$e) {
283 $this->assertRegExp(';Missing field "type";', $e->getMessage());
288 * Test that queue content is reset when reset=>TRUE
290 * @dataProvider getQueueSpecs
293 public function testCreateResetTrue($queueSpec) {
294 $this->queue
= $this->queueService
->create($queueSpec);
295 $this->queue
->createItem([
298 $this->queue
->createItem([
301 $this->assertEquals(2, $this->queue
->numberOfItems());
304 $queue2 = $this->queueService
->create(
305 $queueSpec +
['reset' => TRUE]
307 $this->assertEquals(0, $queue2->numberOfItems());
311 * Test that queue content is not reset when reset is omitted.
313 * @dataProvider getQueueSpecs
316 public function testCreateResetFalse($queueSpec) {
317 $this->queue
= $this->queueService
->create($queueSpec);
318 $this->queue
->createItem([
321 $this->queue
->createItem([
324 $this->assertEquals(2, $this->queue
->numberOfItems());
327 $queue2 = $this->queueService
->create($queueSpec);
328 $this->assertEquals(2, $queue2->numberOfItems());
330 $item = $queue2->claimItem();
331 $this->assertEquals('a', $item->data
['test-key']);
332 $queue2->releaseItem($item);
336 * Test that queue content is not reset when using load()
338 * @dataProvider getQueueSpecs
341 public function testLoad($queueSpec) {
342 $this->queue
= $this->queueService
->create($queueSpec);
343 $this->queue
->createItem([
346 $this->queue
->createItem([
349 $this->assertEquals(2, $this->queue
->numberOfItems());
352 $queue2 = $this->queueService
->create($queueSpec);
353 $this->assertEquals(2, $queue2->numberOfItems());
355 $item = $queue2->claimItem();
356 $this->assertEquals('a', $item->data
['test-key']);
357 $queue2->releaseItem($item);