Merge pull request #18400 from aydun/class_api_tweak_2
[civicrm-core.git] / tests / phpunit / E2E / Core / PrevNextTest.php
1 <?php
2
3 namespace E2E\Core;
4
5 /**
6 * Class PrevNextTest
7 *
8 * Check that the active prev-next service behaves as expected.
9 *
10 * @package E2E\Core
11 * @group e2e
12 */
13 class PrevNextTest extends \CiviEndToEndTestCase {
14
15 /**
16 * @var string
17 */
18 protected $cacheKey;
19
20 /**
21 * @var string
22 */
23 protected $cacheKeyB;
24
25 /**
26 * @var \CRM_Core_PrevNextCache_Interface
27 */
28 protected $prevNext;
29
30 protected function setUp() {
31 parent::setUp();
32 $this->prevNext = \Civi::service('prevnext');
33 $this->cacheKey = 'PrevNextTest_' . \CRM_Utils_String::createRandom(16, \CRM_Utils_String::ALPHANUMERIC);
34 $this->cacheKeyB = 'PrevNextTestb_' . \CRM_Utils_String::createRandom(16, \CRM_Utils_String::ALPHANUMERIC);
35 $this->assertTrue(
36 \CRM_Core_DAO::singleValueQuery('SELECT count(*) FROM civicrm_contact') > 25,
37 'The contact table must have at least 25 records.'
38 );
39 }
40
41 protected function tearDown() {
42 \Civi::service('prevnext')->deleteItem(NULL, $this->cacheKey);
43 \Civi::service('prevnext')->deleteItem(NULL, $this->cacheKeyB);
44 }
45
46 public function testFillSql() {
47 $start = 0;
48 $prefillLimit = 25;
49 $sort = NULL;
50
51 $query = new \CRM_Contact_BAO_Query([['sort_name', 'IS NOT NULL', 1, 0, 0]], NULL, NULL, FALSE, FALSE, 1, FALSE, TRUE, FALSE, NULL, 'AND');
52 $sql = $query->searchQuery($start, $prefillLimit, $sort, FALSE, $query->_includeContactIds,
53 FALSE, TRUE, TRUE);
54 $selectSQL = "SELECT DISTINCT %1, contact_a.id, contact_a.sort_name";
55 $sql = str_replace(array("SELECT contact_a.id as contact_id", "SELECT contact_a.id as id"), $selectSQL, $sql);
56
57 $this->assertTrue(
58 $this->prevNext->fillWithSql($this->cacheKey, $sql, [1 => [$this->cacheKey, 'String']]),
59 "fillWithSql should return TRUE on success"
60 );
61
62 $this->assertEquals(25, $this->prevNext->getCount($this->cacheKey));
63 $this->assertEquals(0, $this->prevNext->getCount('not-a-key-' . $this->cacheKey));
64
65 $all = $this->prevNext->getSelection($this->cacheKey, 'getall')[$this->cacheKey];
66 $this->assertCount($prefillLimit, $all);
67 $this->assertCount($prefillLimit, array_unique(array_keys($all)));
68 $this->assertEquals([1], array_unique(array_values($all)));
69
70 $this->assertSelections([]);
71 }
72
73 public function testFillArray() {
74 $rowSetA = [
75 ['entity_id1' => 100, 'data' => 'Alice'],
76 ['entity_id1' => 400, 'data' => 'Bob'],
77 ['entity_id1' => 200, 'data' => 'Carol'],
78 ];
79 $rowSetB = [
80 ['entity_id1' => 300, 'data' => 'Dave'],
81 ];
82
83 $this->assertTrue(
84 $this->prevNext->fillWithArray($this->cacheKey, $rowSetA),
85 "fillWithArray should return TRUE on success"
86 );
87 $this->assertTrue(
88 $this->prevNext->fillWithArray($this->cacheKey, $rowSetB),
89 "fillWithArray should return TRUE on success"
90 );
91
92 $this->assertEquals(4, $this->prevNext->getCount($this->cacheKey));
93 $this->assertEquals(0, $this->prevNext->getCount('not-a-key-' . $this->cacheKey));
94
95 $all = $this->prevNext->getSelection($this->cacheKey, 'getall')[$this->cacheKey];
96 $this->assertEquals([100, 400, 200, 300], array_keys($all));
97 $this->assertEquals([1], array_unique(array_values($all)));
98
99 $this->assertSelections([]);
100 }
101
102 public function testFetch() {
103 $this->testFillArray();
104
105 $cids = $this->prevNext->fetch($this->cacheKey, 0, 2);
106 $this->assertEquals([100, 400], $cids);
107
108 $cids = $this->prevNext->fetch($this->cacheKey, 0, 4);
109 $this->assertEquals([100, 400, 200, 300], $cids);
110
111 $cids = $this->prevNext->fetch($this->cacheKey, 2, 2);
112 $this->assertEquals([200, 300], $cids);
113 }
114
115 public function getFillFunctions() {
116 return [
117 ['testFillSql'],
118 ['testFillArray'],
119 ];
120 }
121
122 /**
123 * Select and unselect one item.
124 *
125 * @dataProvider getFillFunctions
126 */
127 public function testMarkSelection_1($fillFunction) {
128 call_user_func([$this, $fillFunction]);
129
130 $all = $this->prevNext->getSelection($this->cacheKey, 'getall')[$this->cacheKey];
131 list ($id1, $id2) = array_keys($all);
132 $this->prevNext->markSelection($this->cacheKey, 'select', $id1);
133
134 $this->assertSelections([$id1]);
135
136 $this->prevNext->markSelection($this->cacheKey, 'unselect', $id1);
137 $this->assertSelections([]);
138 }
139
140 /**
141 * Select and unselect two items.
142 *
143 * @dataProvider getFillFunctions
144 */
145 public function testMarkSelection_2($fillFunction) {
146 call_user_func([$this, $fillFunction]);
147
148 $all = $this->prevNext->getSelection($this->cacheKey, 'getall')[$this->cacheKey];
149 list ($id1, $id2, $id3) = array_keys($all);
150
151 $this->prevNext->markSelection($this->cacheKey, 'select', [$id1, $id3]);
152 $this->assertSelections([$id1, $id3]);
153
154 $this->prevNext->markSelection($this->cacheKey, 'unselect', $id1);
155 $this->assertSelections([$id3]);
156
157 $this->prevNext->markSelection($this->cacheKey, 'select', $id2);
158 $this->assertSelections([$id2, $id3]);
159
160 $this->prevNext->markSelection($this->cacheKey, 'unselect');
161 $this->assertSelections([]);
162 }
163
164 /**
165 * Check the neighbors of the first item.
166 *
167 * @dataProvider getFillFunctions
168 */
169 public function testGetPosition_first($fillFunction) {
170 call_user_func([$this, $fillFunction]);
171
172 $all = $this->prevNext->getSelection($this->cacheKey, 'getall')[$this->cacheKey];
173 list ($id1, $id2, $id3) = array_keys($all);
174
175 $pos = $this->prevNext->getPositions($this->cacheKey, $id1);
176
177 $this->assertTrue((bool) $pos['foundEntry']);
178
179 $this->assertEquals($id2, $pos['next']['id1']);
180 $this->assertTrue(!empty($pos['next']['data']));
181
182 $this->assertTrue(!isset($pos['prev']));
183 }
184
185 /**
186 * Check the neighbors of a middle item.
187 *
188 * @dataProvider getFillFunctions
189 */
190 public function testGetPosition_middle($fillFunction) {
191 call_user_func([$this, $fillFunction]);
192
193 $all = $this->prevNext->getSelection($this->cacheKey, 'getall')[$this->cacheKey];
194 list ($id1, $id2, $id3) = array_keys($all);
195
196 $pos = $this->prevNext->getPositions($this->cacheKey, $id2);
197 $this->assertTrue((bool) $pos['foundEntry']);
198
199 $this->assertEquals($id3, $pos['next']['id1']);
200 $this->assertTrue(!empty($pos['next']['data']));
201
202 $this->assertEquals($id1, $pos['prev']['id1']);
203 $this->assertTrue(!empty($pos['prev']['data']));
204 }
205
206 /**
207 * Check the neighbors of the last item.
208 *
209 * @dataProvider getFillFunctions
210 */
211 public function testGetPosition_last($fillFunction) {
212 call_user_func([$this, $fillFunction]);
213
214 $all = $this->prevNext->getSelection($this->cacheKey, 'getall')[$this->cacheKey];
215 list ($idLast, $idPrev) = array_reverse(array_keys($all));
216
217 $pos = $this->prevNext->getPositions($this->cacheKey, $idLast);
218 $this->assertTrue((bool) $pos['foundEntry']);
219
220 $this->assertTrue(!isset($pos['next']));
221
222 $this->assertEquals($idPrev, $pos['prev']['id1']);
223 $this->assertTrue(!empty($pos['prev']['data']));
224 }
225
226 /**
227 * Check the neighbors of the last item.
228 *
229 * @dataProvider getFillFunctions
230 */
231 public function testGetPosition_invalid($fillFunction) {
232 call_user_func([$this, $fillFunction]);
233
234 $pos = $this->prevNext->getPositions($this->cacheKey, 99999999);
235 $this->assertFalse((bool) $pos['foundEntry']);
236 $this->assertTrue(!isset($pos['next']));
237 $this->assertTrue(!isset($pos['prev']));
238 }
239
240 public function testDeleteByCacheKey() {
241 // Add background data
242 $this->prevNext->fillWithArray($this->cacheKeyB, [
243 ['entity_id1' => 100, 'data' => 'Alice'],
244 ['entity_id1' => 150, 'data' => 'Dave'],
245 ]);
246 $this->prevNext->markSelection($this->cacheKeyB, 'select', 100);
247 $this->assertSelections([100], 'get', $this->cacheKeyB);
248 $this->assertSelections([100, 150], 'getall', $this->cacheKeyB);
249
250 // Add some data that we're actually working with.
251 $this->testFillArray();
252
253 $all = $this->prevNext->getSelection($this->cacheKey, 'getall')[$this->cacheKey];
254 $this->assertEquals([100, 400, 200, 300], array_keys($all), 'selected cache not correct for ' . $this->cacheKey
255 . ' defined keys are ' . $this->cacheKey . 'and ' . $this->cacheKeyB
256 . ' the prevNext cache is ' . print_r($this->prevNext, TRUE)
257 );
258
259 list ($id1, $id2, $id3) = array_keys($all);
260 $this->prevNext->markSelection($this->cacheKey, 'select', [$id1, $id3]);
261 $this->assertSelections([$id1, $id3]);
262
263 $this->prevNext->deleteItem(NULL, $this->cacheKey);
264 $all = $this->prevNext->getSelection($this->cacheKey, 'getall')[$this->cacheKey];
265 $this->assertEquals([], array_keys($all));
266 $this->assertSelections([]);
267
268 // Ensure background data was untouched.
269 $this->assertSelections([100], 'get', $this->cacheKeyB);
270 $this->assertSelections([100, 150], 'getall', $this->cacheKeyB);
271 }
272
273 public function testDeleteByEntityId() {
274 // Fill two caches
275 $this->prevNext->fillWithArray($this->cacheKey, [
276 ['entity_id1' => 100, 'data' => 'Alice'],
277 ['entity_id1' => 150, 'data' => 'Dave'],
278 ]);
279 $this->prevNext->markSelection($this->cacheKey, 'select', 100);
280 $this->assertSelections([100], 'get', $this->cacheKey);
281 $this->assertSelections([100, 150], 'getall', $this->cacheKey);
282
283 $this->prevNext->fillWithArray($this->cacheKeyB, [
284 ['entity_id1' => 100, 'data' => 'Alice'],
285 ['entity_id1' => 400, 'data' => 'Bob'],
286 ]);
287 $this->prevNext->markSelection($this->cacheKeyB, 'select', [100, 400]);
288 $this->assertSelections([100, 400], 'get', $this->cacheKeyB);
289 $this->assertSelections([100, 400], 'getall', $this->cacheKeyB);
290
291 // Delete
292 $this->prevNext->deleteItem(100);
293 $this->assertSelections([], 'get', $this->cacheKey);
294 $this->assertSelections([150], 'getall', $this->cacheKey);
295 $this->assertSelections([400], 'get', $this->cacheKeyB);
296 $this->assertSelections([400], 'getall', $this->cacheKeyB);
297 }
298
299 public function testDeleteAll() {
300 // Fill two caches
301 $this->prevNext->fillWithArray($this->cacheKey, [
302 ['entity_id1' => 100, 'data' => 'Alice'],
303 ['entity_id1' => 150, 'data' => 'Dave'],
304 ]);
305 $this->prevNext->markSelection($this->cacheKey, 'select', 100);
306 $this->assertSelections([100], 'get', $this->cacheKey);
307 $this->assertSelections([100, 150], 'getall', $this->cacheKey);
308
309 $this->prevNext->fillWithArray($this->cacheKeyB, [
310 ['entity_id1' => 100, 'data' => 'Alice'],
311 ['entity_id1' => 400, 'data' => 'Bob'],
312 ]);
313 $this->prevNext->markSelection($this->cacheKeyB, 'select', [100, 400]);
314 $this->assertSelections([100, 400], 'get', $this->cacheKeyB);
315 $this->assertSelections([100, 400], 'getall', $this->cacheKeyB);
316
317 // Delete
318 $this->prevNext->deleteItem(NULL, NULL);
319 $this->assertSelections([], 'get', $this->cacheKey);
320 $this->assertSelections([], 'getall', $this->cacheKey);
321 $this->assertSelections([], 'get', $this->cacheKeyB);
322 $this->assertSelections([], 'getall', $this->cacheKeyB);
323 }
324
325 /**
326 * Assert that the current cacheKey has a list of selected contact IDs.
327 *
328 * @param array $ids
329 * Contact IDs that should be selected.
330 * @param string $action
331 * @param string|NULL $cacheKey
332 */
333 protected function assertSelections($ids, $action = 'get', $cacheKey = NULL) {
334 if ($cacheKey === NULL) {
335 $cacheKey = $this->cacheKey;
336 }
337 $selected = $this->prevNext->getSelection($cacheKey, $action)[$cacheKey];
338 $this->assertEquals($ids, array_keys($selected), 'selected cache not correct for ' . $cacheKey
339 . ' defined keys are ' . $this->cacheKey . 'and ' . $this->cacheKeyB
340 . ' result from getall is ' . print_r($this->prevNext->getSelection($cacheKey, 'getall'), 1)
341 . ' and the prevNext cache is ' . print_r($this->prevNext, TRUE)
342 );
343
344 $this->assertCount(count($ids), $selected);
345 }
346
347 }