Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | ||
aba1cd8b EM |
3 | /** |
4 | * Class CRM_Core_ManagedEntitiesTest | |
acb109b7 | 5 | * @group headless |
aba1cd8b | 6 | */ |
6a488035 | 7 | class CRM_Core_ManagedEntitiesTest extends CiviUnitTestCase { |
378e2654 TO |
8 | /** |
9 | * @var \Civi\API\Kernel | |
10 | */ | |
11 | protected $apiKernel; | |
12 | ||
13 | /** | |
14 | * @var \Civi\API\Provider\AdhocProvider | |
15 | */ | |
16 | protected $adhocProvider; | |
17 | ||
aba1cd8b | 18 | /** |
bbf66e9c | 19 | * @var array(string $shortName => CRM_Core_Module $module) |
aba1cd8b | 20 | */ |
bbf66e9c TO |
21 | protected $modules; |
22 | ||
6ea13979 TO |
23 | protected $fixtures; |
24 | ||
00be9182 | 25 | public function setUp() { |
e4ccda28 | 26 | $this->useTransaction(TRUE); |
6a488035 TO |
27 | parent::setUp(); |
28 | $this->modules = array( | |
29 | 'one' => new CRM_Core_Module('com.example.one', TRUE), | |
30 | 'two' => new CRM_Core_Module('com.example.two', TRUE), | |
31 | ); | |
e4ccda28 TO |
32 | |
33 | // Testing on drupal-demo fails because some extensions have mgd ents. | |
34 | CRM_Core_DAO::singleValueQuery('DELETE FROM civicrm_managed'); | |
6ea13979 TO |
35 | |
36 | $this->fixtures['com.example.one-foo'] = array( | |
37 | 'module' => 'com.example.one', | |
38 | 'name' => 'foo', | |
39 | 'entity' => 'CustomSearch', | |
40 | 'params' => array( | |
41 | 'version' => 3, | |
42 | 'class_name' => 'CRM_Example_One_Foo', | |
43 | 'is_reserved' => 1, | |
44 | ), | |
45 | ); | |
46 | $this->fixtures['com.example.one-bar'] = array( | |
47 | 'module' => 'com.example.one', | |
48 | 'name' => 'bar', | |
49 | 'entity' => 'CustomSearch', | |
50 | 'params' => array( | |
51 | 'version' => 3, | |
52 | 'class_name' => 'CRM_Example_One_Bar', | |
53 | 'is_reserved' => 1, | |
54 | ), | |
55 | ); | |
ee8b9cee MM |
56 | $this->fixtures['com.example.one-CustomGroup'] = array( |
57 | 'module' => 'com.example.one', | |
58 | 'name' => 'CustomGroup', | |
59 | 'entity' => 'CustomGroup', | |
60 | 'params' => array( | |
61 | 'version' => 3, | |
62 | 'name' => 'test_custom_group', | |
63 | 'title' => 'Test custom group', | |
64 | 'extends' => 'Individual', | |
65 | ), | |
66 | ); | |
67 | $this->fixtures['com.example.one-CustomField'] = array( | |
68 | 'module' => 'com.example.one', | |
69 | 'name' => 'CustomField', | |
70 | 'entity' => 'CustomField', | |
71 | 'params' => array( | |
72 | 'version' => 3, | |
73 | 'name' => 'test_custom_field', | |
74 | 'label' => 'Test custom field', | |
75 | 'custom_group_id' => 'test_custom_group', | |
76 | 'data_type' => 'String', | |
77 | 'html_type' => 'Text', | |
78 | ), | |
79 | ); | |
378e2654 | 80 | |
048222df | 81 | $this->apiKernel = \Civi::service('civi_api_kernel'); |
378e2654 TO |
82 | $this->adhocProvider = new \Civi\API\Provider\AdhocProvider(3, 'CustomSearch'); |
83 | $this->apiKernel->registerApiProvider($this->adhocProvider); | |
6a488035 TO |
84 | } |
85 | ||
00be9182 | 86 | public function tearDown() { |
6a488035 | 87 | parent::tearDown(); |
048222df | 88 | \Civi::reset(); |
6a488035 TO |
89 | } |
90 | ||
91 | /** | |
92 | * Set up an active module and, over time, the hook implementation changes | |
93 | * to (1) create 'foo' entity, (2) create 'bar' entity', (3) remove 'foo' | |
94 | * entity | |
95 | */ | |
00be9182 | 96 | public function testAddRemoveEntitiesModule_UpdateAlways_DeleteAlways() { |
6a488035 TO |
97 | $decls = array(); |
98 | ||
99 | // create first managed entity ('foo') | |
6ea13979 | 100 | $decls[] = $this->fixtures['com.example.one-foo']; |
6a488035 TO |
101 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); |
102 | $me->reconcile(); | |
103 | $foo = $me->get('com.example.one', 'foo'); | |
104 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
105 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
106 | ||
107 | // later on, hook returns an extra managed entity ('bar') | |
6ea13979 | 108 | $decls[] = $this->fixtures['com.example.one-bar']; |
6a488035 TO |
109 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); |
110 | $me->reconcile(); | |
111 | $foo = $me->get('com.example.one', 'foo'); | |
112 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
113 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
114 | $bar = $me->get('com.example.one', 'bar'); | |
115 | $this->assertEquals('CRM_Example_One_Bar', $bar['name']); | |
116 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Bar"'); | |
117 | ||
118 | // and then hook changes its mind, removing 'foo' (first of two entities) | |
119 | unset($decls[0]); | |
120 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); | |
121 | $me->reconcile(); | |
122 | $foo = $me->get('com.example.one', 'foo'); | |
123 | $this->assertTrue($foo === NULL); | |
124 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
125 | $bar = $me->get('com.example.one', 'bar'); | |
126 | $this->assertEquals('CRM_Example_One_Bar', $bar['name']); | |
127 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Bar"'); | |
128 | ||
129 | // and then hook changes its mind, removing 'bar' (the last remaining entity) | |
130 | unset($decls[1]); | |
131 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); | |
132 | $me->reconcile(); | |
133 | $foo = $me->get('com.example.one', 'foo'); | |
134 | $this->assertTrue($foo === NULL); | |
135 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
136 | $bar = $me->get('com.example.one', 'bar'); | |
137 | $this->assertTrue($bar === NULL); | |
138 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Bar"'); | |
139 | } | |
140 | ||
141 | /** | |
142 | * Set up an active module with one managed-entity and, over | |
143 | * time, the content of the entity changes | |
144 | */ | |
00be9182 | 145 | public function testModifyDeclaration_UpdateAlways() { |
6a488035 TO |
146 | $decls = array(); |
147 | ||
148 | // create first managed entity ('foo') | |
6ea13979 | 149 | $decls[] = $this->fixtures['com.example.one-foo']; |
6a488035 TO |
150 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); |
151 | $me->reconcile(); | |
152 | $foo = $me->get('com.example.one', 'foo'); | |
153 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
154 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
155 | ||
156 | // later on, hook specification changes | |
157 | $decls[0]['params']['class_name'] = 'CRM_Example_One_Foobar'; | |
158 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); | |
159 | $me->reconcile(); | |
160 | $foo2 = $me->get('com.example.one', 'foo'); | |
161 | $this->assertEquals('CRM_Example_One_Foobar', $foo2['name']); | |
162 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
163 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_FooBar"'); | |
164 | $this->assertEquals($foo['id'], $foo2['id']); | |
165 | } | |
166 | ||
0dd54586 TO |
167 | /** |
168 | * Set up an active module with one managed-entity and, over | |
169 | * time, the content of the entity changes | |
170 | */ | |
00be9182 | 171 | public function testModifyDeclaration_UpdateNever() { |
0dd54586 TO |
172 | $decls = array(); |
173 | ||
174 | // create first managed entity ('foo') | |
175 | $decls[] = array_merge($this->fixtures['com.example.one-foo'], array( | |
176 | 'update' => 'never', // Policy is to never update after initial creation | |
177 | )); | |
178 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); | |
179 | $me->reconcile(); | |
180 | $foo = $me->get('com.example.one', 'foo'); | |
181 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
182 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
183 | ||
184 | // later on, hook specification changes | |
185 | $decls[0]['params']['class_name'] = 'CRM_Example_One_Foobar'; | |
186 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); | |
187 | $me->reconcile(); | |
188 | $foo2 = $me->get('com.example.one', 'foo'); | |
189 | $this->assertEquals('CRM_Example_One_Foo', $foo2['name']); | |
190 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
191 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_FooBar"'); | |
192 | $this->assertEquals($foo['id'], $foo2['id']); | |
193 | } | |
194 | ||
1f103dc4 TO |
195 | /** |
196 | * Set up an active module with one managed-entity using the | |
197 | * policy "cleanup=>never". When the managed-entity goes away, | |
198 | * ensure that the policy is followed (ie the entity is not | |
199 | * deleted). | |
200 | */ | |
00be9182 | 201 | public function testRemoveDeclaration_CleanupNever() { |
1f103dc4 TO |
202 | $decls = array(); |
203 | ||
204 | // create first managed entity ('foo') | |
205 | $decls[] = array_merge($this->fixtures['com.example.one-foo'], array( | |
21dfd5f5 | 206 | 'cleanup' => 'never', |
1f103dc4 TO |
207 | )); |
208 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); | |
209 | $me->reconcile(); | |
210 | $foo = $me->get('com.example.one', 'foo'); | |
211 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
212 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
213 | ||
214 | // later on, entity definition disappears; but we decide not to do any cleanup (per policy) | |
215 | $decls = array(); | |
216 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); | |
217 | $me->reconcile(); | |
218 | $foo2 = $me->get('com.example.one', 'foo'); | |
219 | $this->assertEquals('CRM_Example_One_Foo', $foo2['name']); | |
220 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
221 | $this->assertEquals($foo['id'], $foo2['id']); | |
222 | } | |
223 | ||
378e2654 TO |
224 | /** |
225 | * Set up an active module with one managed-entity using the | |
226 | * policy "cleanup=>never". When the managed-entity goes away, | |
227 | * ensure that the policy is followed (ie the entity is not | |
228 | * deleted). | |
229 | */ | |
00be9182 | 230 | public function testRemoveDeclaration_CleanupUnused() { |
378e2654 TO |
231 | $decls = array(); |
232 | ||
233 | // create first managed entity ('foo') | |
234 | $decls[] = array_merge($this->fixtures['com.example.one-foo'], array( | |
21dfd5f5 | 235 | 'cleanup' => 'unused', |
378e2654 TO |
236 | )); |
237 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); | |
238 | $me->reconcile(); | |
239 | $foo = $me->get('com.example.one', 'foo'); | |
240 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
241 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
242 | ||
243 | // Override 'getrefcount' ==> The refcount is 1 | |
92915c55 | 244 | $this->adhocProvider->addAction('getrefcount', 'access CiviCRM', function ($apiRequest) { |
378e2654 TO |
245 | return civicrm_api3_create_success(array( |
246 | array( | |
247 | 'name' => 'mock', | |
248 | 'type' => 'mock', | |
249 | 'count' => 1, | |
21dfd5f5 | 250 | ), |
378e2654 TO |
251 | )); |
252 | }); | |
253 | ||
254 | // Later on, entity definition disappears; but we decide not to do any cleanup (per policy) | |
255 | $decls = array(); | |
256 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); | |
257 | $me->reconcile(); | |
258 | $foo2 = $me->get('com.example.one', 'foo'); | |
259 | $this->assertEquals('CRM_Example_One_Foo', $foo2['name']); | |
260 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
261 | $this->assertEquals($foo['id'], $foo2['id']); | |
262 | ||
378e2654 | 263 | // Override 'getrefcount' ==> The refcount is 0 |
92915c55 | 264 | $this->adhocProvider->addAction('getrefcount', 'access CiviCRM', function ($apiRequest) { |
378e2654 TO |
265 | return civicrm_api3_create_success(array()); |
266 | }); | |
267 | ||
268 | // The entity definition disappeared and there's no reference; we decide to cleanup (per policy) | |
269 | $decls = array(); | |
270 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); | |
271 | $me->reconcile(); | |
272 | $foo3 = $me->get('com.example.one', 'foo'); | |
273 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
274 | $this->assertTrue($foo3 === NULL); | |
275 | } | |
276 | ||
6a488035 | 277 | /** |
eceb18cc | 278 | * Setup an active module with a malformed entity declaration. |
6a488035 | 279 | */ |
00be9182 | 280 | public function testInvalidDeclarationModule() { |
6a488035 TO |
281 | // create first managed entity ('foo') |
282 | $decls = array(); | |
283 | $decls[] = array( | |
284 | 'module' => 'com.example.unknown', // erroneous | |
285 | 'name' => 'foo', | |
286 | 'entity' => 'CustomSearch', | |
287 | 'params' => array( | |
288 | 'version' => 3, | |
289 | 'class_name' => 'CRM_Example_One_Foo', | |
290 | 'is_reserved' => 1, | |
291 | ), | |
292 | ); | |
293 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); | |
294 | try { | |
295 | $me->reconcile(); | |
296 | $this->fail('Expected exception when using invalid declaration'); | |
0db6c3e1 TO |
297 | } |
298 | catch (Exception $e) { | |
6c6e6187 | 299 | // good |
6a488035 TO |
300 | } |
301 | } | |
302 | ||
303 | /** | |
eceb18cc | 304 | * Setup an active module with a malformed entity declaration. |
6a488035 | 305 | */ |
00be9182 | 306 | public function testMissingName() { |
6a488035 TO |
307 | // create first managed entity ('foo') |
308 | $decls = array(); | |
309 | $decls[] = array( | |
310 | 'module' => 'com.example.unknown', | |
311 | 'name' => NULL, // erroneous | |
312 | 'entity' => 'CustomSearch', | |
313 | 'params' => array( | |
314 | 'version' => 3, | |
315 | 'class_name' => 'CRM_Example_One_Foo', | |
316 | 'is_reserved' => 1, | |
317 | ), | |
318 | ); | |
319 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); | |
320 | try { | |
321 | $me->reconcile(); | |
322 | $this->fail('Expected exception when using invalid declaration'); | |
0db6c3e1 TO |
323 | } |
324 | catch (Exception $e) { | |
6c6e6187 | 325 | // good |
6a488035 TO |
326 | } |
327 | } | |
328 | ||
329 | /** | |
eceb18cc | 330 | * Setup an active module with a malformed entity declaration. |
6a488035 | 331 | */ |
00be9182 | 332 | public function testMissingEntity() { |
6a488035 TO |
333 | // create first managed entity ('foo') |
334 | $decls = array(); | |
335 | $decls[] = array( | |
336 | 'module' => 'com.example.unknown', | |
337 | 'name' => 'foo', | |
338 | 'entity' => NULL, // erroneous | |
339 | 'params' => array( | |
340 | 'version' => 3, | |
341 | 'class_name' => 'CRM_Example_One_Foo', | |
342 | 'is_reserved' => 1, | |
343 | ), | |
344 | ); | |
345 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); | |
346 | try { | |
347 | $me->reconcile(); | |
348 | $this->fail('Expected exception when using invalid declaration'); | |
0db6c3e1 TO |
349 | } |
350 | catch (Exception $e) { | |
6c6e6187 | 351 | // good |
6a488035 TO |
352 | } |
353 | } | |
354 | ||
355 | /** | |
356 | * Setup an active module with an entity -- then disable and re-enable the | |
357 | * module | |
358 | */ | |
00be9182 | 359 | public function testDeactivateReactivateModule() { |
6a488035 TO |
360 | // create first managed entity ('foo') |
361 | $decls = array(); | |
6ea13979 | 362 | $decls[] = $this->fixtures['com.example.one-foo']; |
6a488035 TO |
363 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); |
364 | $me->reconcile(); | |
365 | $foo = $me->get('com.example.one', 'foo'); | |
366 | $this->assertEquals(1, $foo['is_active']); | |
367 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
368 | $this->assertDBQuery(1, 'SELECT is_active FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
369 | ||
370 | // now deactivate module, which has empty decls and which cascades to managed object | |
371 | $this->modules['one']->is_active = FALSE; | |
372 | $me = new CRM_Core_ManagedEntities($this->modules, array()); | |
373 | $me->reconcile(); | |
374 | $foo = $me->get('com.example.one', 'foo'); | |
375 | $this->assertEquals(0, $foo['is_active']); | |
376 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
377 | $this->assertDBQuery(0, 'SELECT is_active FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
378 | ||
379 | // and reactivate module, which again provides decls and which cascades to managed object | |
380 | $this->modules['one']->is_active = TRUE; | |
381 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); | |
382 | $me->reconcile(); | |
383 | $foo = $me->get('com.example.one', 'foo'); | |
384 | $this->assertEquals(1, $foo['is_active']); | |
385 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
386 | $this->assertDBQuery(1, 'SELECT is_active FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
387 | } | |
388 | ||
389 | /** | |
390 | * Setup an active module with an entity -- then entirely uninstall the | |
391 | * module | |
392 | */ | |
00be9182 | 393 | public function testUninstallModule() { |
6a488035 TO |
394 | // create first managed entity ('foo') |
395 | $decls = array(); | |
6ea13979 | 396 | $decls[] = $this->fixtures['com.example.one-foo']; |
6a488035 TO |
397 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); |
398 | $me->reconcile(); | |
399 | $foo = $me->get('com.example.one', 'foo'); | |
400 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
401 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
402 | ||
e4f46be0 | 403 | // then destroy module; note that decls go away |
6a488035 TO |
404 | unset($this->modules['one']); |
405 | $me = new CRM_Core_ManagedEntities($this->modules, array()); | |
406 | $me->reconcile(); | |
407 | $fooNew = $me->get('com.example.one', 'foo'); | |
408 | $this->assertTrue(NULL === $fooNew); | |
409 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
410 | } | |
96025800 | 411 | |
ee8b9cee MM |
412 | public function testDependentEntitiesUninstallCleanly() { |
413 | ||
414 | // Install a module with two dependent managed entities | |
415 | $decls = array(); | |
416 | $decls[] = $this->fixtures['com.example.one-CustomGroup']; | |
417 | $decls[] = $this->fixtures['com.example.one-CustomField']; | |
418 | $me = new CRM_Core_ManagedEntities($this->modules, $decls); | |
419 | $me->reconcile(); | |
420 | ||
421 | // Uninstall the module | |
422 | unset($this->modules['one']); | |
423 | $me = new CRM_Core_ManagedEntities($this->modules, []); | |
424 | $me->reconcile(); | |
425 | ||
426 | // Ensure that no managed entities remain in the civicrm_managed | |
427 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_managed'); | |
428 | ||
429 | // Ensure that com.example.one-CustomGroup is deleted | |
430 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_custom_group WHERE name = "test_custom_group"'); | |
431 | ||
432 | // Ensure that com.example.one-CustomField is deleted | |
433 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_custom_field WHERE name = "test_custom_field"'); | |
434 | ||
435 | } | |
436 | ||
6a488035 | 437 | } |