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 | /** |
1d3260ea | 19 | * @var String[] |
aba1cd8b | 20 | */ |
bbf66e9c TO |
21 | protected $modules; |
22 | ||
6ea13979 TO |
23 | protected $fixtures; |
24 | ||
faba1457 | 25 | public function setUp(): void { |
e4ccda28 | 26 | $this->useTransaction(TRUE); |
6a488035 | 27 | parent::setUp(); |
9099cab3 | 28 | $this->modules = [ |
6a488035 TO |
29 | 'one' => new CRM_Core_Module('com.example.one', TRUE), |
30 | 'two' => new CRM_Core_Module('com.example.two', TRUE), | |
9099cab3 | 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 | 35 | |
9099cab3 | 36 | $this->fixtures['com.example.one-foo'] = [ |
6ea13979 TO |
37 | 'module' => 'com.example.one', |
38 | 'name' => 'foo', | |
39 | 'entity' => 'CustomSearch', | |
9099cab3 | 40 | 'params' => [ |
6ea13979 TO |
41 | 'version' => 3, |
42 | 'class_name' => 'CRM_Example_One_Foo', | |
43 | 'is_reserved' => 1, | |
9099cab3 CW |
44 | ], |
45 | ]; | |
46 | $this->fixtures['com.example.one-bar'] = [ | |
6ea13979 TO |
47 | 'module' => 'com.example.one', |
48 | 'name' => 'bar', | |
49 | 'entity' => 'CustomSearch', | |
9099cab3 | 50 | 'params' => [ |
6ea13979 TO |
51 | 'version' => 3, |
52 | 'class_name' => 'CRM_Example_One_Bar', | |
53 | 'is_reserved' => 1, | |
9099cab3 CW |
54 | ], |
55 | ]; | |
56 | $this->fixtures['com.example.one-CustomGroup'] = [ | |
ee8b9cee MM |
57 | 'module' => 'com.example.one', |
58 | 'name' => 'CustomGroup', | |
59 | 'entity' => 'CustomGroup', | |
9099cab3 | 60 | 'params' => [ |
ee8b9cee MM |
61 | 'version' => 3, |
62 | 'name' => 'test_custom_group', | |
63 | 'title' => 'Test custom group', | |
64 | 'extends' => 'Individual', | |
9099cab3 CW |
65 | ], |
66 | ]; | |
67 | $this->fixtures['com.example.one-CustomField'] = [ | |
ee8b9cee MM |
68 | 'module' => 'com.example.one', |
69 | 'name' => 'CustomField', | |
70 | 'entity' => 'CustomField', | |
9099cab3 | 71 | 'params' => [ |
ee8b9cee MM |
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', | |
9099cab3 CW |
78 | ], |
79 | ]; | |
378e2654 | 80 | |
20429eb9 RL |
81 | $this->fixtures['com.example.one-Job'] = [ |
82 | 'module' => 'com.example.one', | |
83 | 'name' => 'Job', | |
84 | 'entity' => 'Job', | |
85 | 'params' => [ | |
86 | 'version' => 3, | |
87 | 'name' => 'test_job', | |
88 | 'run_frequency' => 'Daily', | |
89 | 'api_entity' => 'Job', | |
90 | 'api_action' => 'Get', | |
91 | 'parameters' => '', | |
92 | ], | |
93 | ]; | |
d4cf4164 EM |
94 | $this->fixtures['com.example.one-Contact'] = [ |
95 | 'module' => 'com.example.one', | |
96 | 'name' => 'Contact', | |
97 | 'entity' => 'Contact', | |
98 | 'params' => [ | |
99 | 'version' => 3, | |
100 | 'first_name' => 'Daffy', | |
101 | 'last_name' => 'Duck', | |
102 | 'contact_type' => 'Individual', | |
103 | 'update' => 'never', | |
104 | ], | |
105 | ]; | |
15fbb541 TO |
106 | $this->fixtures['com.example.two-CustomGroup'] = [ |
107 | 'module' => 'com.example.two', | |
108 | 'name' => 'CustomGroup', | |
109 | 'entity' => 'CustomGroup', | |
110 | 'params' => [ | |
111 | 'version' => 3, | |
112 | 'name' => 'test_custom_group_two', | |
113 | 'title' => 'Test custom group two', | |
114 | 'extends' => 'Individual', | |
115 | ], | |
116 | ]; | |
117 | $this->fixtures['com.example.three-CustomGroup'] = [ | |
118 | 'module' => 'com.example.three', | |
119 | 'name' => 'CustomGroup', | |
120 | 'entity' => 'CustomGroup', | |
121 | 'params' => [ | |
122 | 'version' => 3, | |
123 | 'name' => 'test_custom_group_three', | |
124 | 'title' => 'Test custom group three', | |
125 | 'extends' => 'Individual', | |
126 | ], | |
127 | ]; | |
20429eb9 | 128 | |
048222df | 129 | $this->apiKernel = \Civi::service('civi_api_kernel'); |
378e2654 TO |
130 | $this->adhocProvider = new \Civi\API\Provider\AdhocProvider(3, 'CustomSearch'); |
131 | $this->apiKernel->registerApiProvider($this->adhocProvider); | |
8cb5ca10 | 132 | $this->hookClass->setHook('civicrm_managed', [$this, 'hookManaged']); |
6a488035 TO |
133 | } |
134 | ||
594a9328 | 135 | public function tearDown(): void { |
6a488035 | 136 | parent::tearDown(); |
048222df | 137 | \Civi::reset(); |
6a488035 TO |
138 | } |
139 | ||
8cb5ca10 EM |
140 | /** |
141 | * @var array | |
142 | */ | |
143 | protected $managedEntities = []; | |
144 | ||
145 | /** | |
146 | * Implements hook managed. | |
147 | * | |
148 | * @param array $entities | |
149 | */ | |
150 | public function hookManaged(array &$entities): void { | |
151 | $entities = $this->managedEntities; | |
152 | } | |
153 | ||
6a488035 TO |
154 | /** |
155 | * Set up an active module and, over time, the hook implementation changes | |
156 | * to (1) create 'foo' entity, (2) create 'bar' entity', (3) remove 'foo' | |
157 | * entity | |
158 | */ | |
00be9182 | 159 | public function testAddRemoveEntitiesModule_UpdateAlways_DeleteAlways() { |
6a488035 | 160 | // create first managed entity ('foo') |
8cb5ca10 EM |
161 | $this->managedEntities = [$this->fixtures['com.example.one-foo']]; |
162 | $me = new CRM_Core_ManagedEntities($this->modules); | |
6a488035 TO |
163 | $me->reconcile(); |
164 | $foo = $me->get('com.example.one', 'foo'); | |
165 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
166 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
167 | ||
168 | // later on, hook returns an extra managed entity ('bar') | |
8cb5ca10 EM |
169 | $this->managedEntities[] = $this->fixtures['com.example.one-bar']; |
170 | $me = new CRM_Core_ManagedEntities($this->modules); | |
6a488035 TO |
171 | $me->reconcile(); |
172 | $foo = $me->get('com.example.one', 'foo'); | |
173 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
174 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
175 | $bar = $me->get('com.example.one', 'bar'); | |
176 | $this->assertEquals('CRM_Example_One_Bar', $bar['name']); | |
177 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Bar"'); | |
178 | ||
179 | // and then hook changes its mind, removing 'foo' (first of two entities) | |
8cb5ca10 EM |
180 | unset($this->managedEntities[0]); |
181 | $me = new CRM_Core_ManagedEntities($this->modules); | |
6a488035 TO |
182 | $me->reconcile(); |
183 | $foo = $me->get('com.example.one', 'foo'); | |
184 | $this->assertTrue($foo === NULL); | |
185 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
186 | $bar = $me->get('com.example.one', 'bar'); | |
187 | $this->assertEquals('CRM_Example_One_Bar', $bar['name']); | |
188 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Bar"'); | |
189 | ||
190 | // and then hook changes its mind, removing 'bar' (the last remaining entity) | |
8cb5ca10 EM |
191 | unset($this->managedEntities[1]); |
192 | $me = new CRM_Core_ManagedEntities($this->modules); | |
6a488035 TO |
193 | $me->reconcile(); |
194 | $foo = $me->get('com.example.one', 'foo'); | |
195 | $this->assertTrue($foo === NULL); | |
196 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
197 | $bar = $me->get('com.example.one', 'bar'); | |
8cb5ca10 | 198 | $this->assertNull($bar); |
6a488035 TO |
199 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Bar"'); |
200 | } | |
201 | ||
202 | /** | |
203 | * Set up an active module with one managed-entity and, over | |
204 | * time, the content of the entity changes | |
8cb5ca10 EM |
205 | * |
206 | * @throws \CRM_Core_Exception | |
6a488035 | 207 | */ |
8cb5ca10 | 208 | public function testModifyDeclaration_UpdateAlways(): void { |
6a488035 | 209 | // create first managed entity ('foo') |
8cb5ca10 EM |
210 | $this->managedEntities = [$this->fixtures['com.example.one-foo']]; |
211 | $me = new CRM_Core_ManagedEntities($this->modules); | |
6a488035 TO |
212 | $me->reconcile(); |
213 | $foo = $me->get('com.example.one', 'foo'); | |
214 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
215 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
216 | ||
217 | // later on, hook specification changes | |
8cb5ca10 EM |
218 | $this->managedEntities[0]['params']['class_name'] = 'CRM_Example_One_Foobar'; |
219 | $me = new CRM_Core_ManagedEntities($this->modules); | |
6a488035 TO |
220 | $me->reconcile(); |
221 | $foo2 = $me->get('com.example.one', 'foo'); | |
222 | $this->assertEquals('CRM_Example_One_Foobar', $foo2['name']); | |
223 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
224 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_FooBar"'); | |
225 | $this->assertEquals($foo['id'], $foo2['id']); | |
226 | } | |
227 | ||
0dd54586 TO |
228 | /** |
229 | * Set up an active module with one managed-entity and, over | |
230 | * time, the content of the entity changes | |
8cb5ca10 EM |
231 | * |
232 | * @throws \CRM_Core_Exception | |
0dd54586 | 233 | */ |
8cb5ca10 | 234 | public function testModifyDeclaration_UpdateNever(): void { |
0dd54586 | 235 | // create first managed entity ('foo') |
8cb5ca10 | 236 | $this->managedEntities[] = array_merge($this->fixtures['com.example.one-foo'], [ |
39b959db SL |
237 | // Policy is to never update after initial creation |
238 | 'update' => 'never', | |
9099cab3 | 239 | ]); |
8cb5ca10 | 240 | $me = new CRM_Core_ManagedEntities($this->modules); |
0dd54586 TO |
241 | $me->reconcile(); |
242 | $foo = $me->get('com.example.one', 'foo'); | |
243 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
244 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
245 | ||
246 | // later on, hook specification changes | |
8cb5ca10 EM |
247 | $this->managedEntities[0]['params']['class_name'] = 'CRM_Example_One_Foobar'; |
248 | $me = new CRM_Core_ManagedEntities($this->modules); | |
0dd54586 TO |
249 | $me->reconcile(); |
250 | $foo2 = $me->get('com.example.one', 'foo'); | |
251 | $this->assertEquals('CRM_Example_One_Foo', $foo2['name']); | |
252 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
253 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_FooBar"'); | |
254 | $this->assertEquals($foo['id'], $foo2['id']); | |
255 | } | |
256 | ||
1f103dc4 TO |
257 | /** |
258 | * Set up an active module with one managed-entity using the | |
259 | * policy "cleanup=>never". When the managed-entity goes away, | |
260 | * ensure that the policy is followed (ie the entity is not | |
261 | * deleted). | |
8cb5ca10 EM |
262 | * |
263 | * @throws \CRM_Core_Exception | |
1f103dc4 | 264 | */ |
8cb5ca10 | 265 | public function testRemoveDeclaration_CleanupNever(): void { |
1f103dc4 | 266 | // create first managed entity ('foo') |
8cb5ca10 EM |
267 | $this->managedEntities = [ |
268 | array_merge($this->fixtures['com.example.one-foo'], ['cleanup' => 'never']), | |
269 | ]; | |
270 | $me = new CRM_Core_ManagedEntities($this->modules); | |
1f103dc4 TO |
271 | $me->reconcile(); |
272 | $foo = $me->get('com.example.one', 'foo'); | |
273 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
274 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
275 | ||
276 | // later on, entity definition disappears; but we decide not to do any cleanup (per policy) | |
8cb5ca10 EM |
277 | $this->managedEntities = []; |
278 | $me = new CRM_Core_ManagedEntities($this->modules); | |
1f103dc4 TO |
279 | $me->reconcile(); |
280 | $foo2 = $me->get('com.example.one', 'foo'); | |
281 | $this->assertEquals('CRM_Example_One_Foo', $foo2['name']); | |
282 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
283 | $this->assertEquals($foo['id'], $foo2['id']); | |
284 | } | |
285 | ||
378e2654 TO |
286 | /** |
287 | * Set up an active module with one managed-entity using the | |
a2bf5923 CW |
288 | * policy "cleanup=>unused". When the managed-entity goes away, |
289 | * ensure that the policy is followed (ie the entity is conditionally | |
378e2654 | 290 | * deleted). |
8cb5ca10 EM |
291 | * |
292 | * @throws \CRM_Core_Exception | |
378e2654 | 293 | */ |
8cb5ca10 | 294 | public function testRemoveDeclaration_CleanupUnused(): void { |
378e2654 | 295 | // create first managed entity ('foo') |
8cb5ca10 EM |
296 | $this->managedEntities = [array_merge($this->fixtures['com.example.one-foo'], ['cleanup' => 'unused'])]; |
297 | $me = new CRM_Core_ManagedEntities($this->modules); | |
378e2654 TO |
298 | $me->reconcile(); |
299 | $foo = $me->get('com.example.one', 'foo'); | |
300 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
301 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
302 | ||
303 | // Override 'getrefcount' ==> The refcount is 1 | |
92915c55 | 304 | $this->adhocProvider->addAction('getrefcount', 'access CiviCRM', function ($apiRequest) { |
9099cab3 CW |
305 | return civicrm_api3_create_success([ |
306 | [ | |
378e2654 TO |
307 | 'name' => 'mock', |
308 | 'type' => 'mock', | |
309 | 'count' => 1, | |
9099cab3 CW |
310 | ], |
311 | ]); | |
378e2654 TO |
312 | }); |
313 | ||
314 | // Later on, entity definition disappears; but we decide not to do any cleanup (per policy) | |
8cb5ca10 EM |
315 | $this->managedEntities = []; |
316 | $me = new CRM_Core_ManagedEntities($this->modules); | |
378e2654 TO |
317 | $me->reconcile(); |
318 | $foo2 = $me->get('com.example.one', 'foo'); | |
319 | $this->assertEquals('CRM_Example_One_Foo', $foo2['name']); | |
320 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
321 | $this->assertEquals($foo['id'], $foo2['id']); | |
322 | ||
378e2654 | 323 | // Override 'getrefcount' ==> The refcount is 0 |
92915c55 | 324 | $this->adhocProvider->addAction('getrefcount', 'access CiviCRM', function ($apiRequest) { |
9099cab3 | 325 | return civicrm_api3_create_success([]); |
378e2654 TO |
326 | }); |
327 | ||
328 | // The entity definition disappeared and there's no reference; we decide to cleanup (per policy) | |
8cb5ca10 EM |
329 | $this->managedEntities = []; |
330 | $me = new CRM_Core_ManagedEntities($this->modules); | |
378e2654 TO |
331 | $me->reconcile(); |
332 | $foo3 = $me->get('com.example.one', 'foo'); | |
333 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
8cb5ca10 | 334 | $this->assertNull($foo3); |
378e2654 TO |
335 | } |
336 | ||
6a488035 | 337 | /** |
eceb18cc | 338 | * Setup an active module with a malformed entity declaration. |
6a488035 | 339 | */ |
8cb5ca10 | 340 | public function testInvalidDeclarationModule(): void { |
6a488035 | 341 | // create first managed entity ('foo') |
8cb5ca10 EM |
342 | $this->managedEntities = [ |
343 | [ | |
344 | // erroneous | |
345 | 'module' => 'com.example.unknown', | |
346 | 'name' => 'foo', | |
347 | 'entity' => 'CustomSearch', | |
348 | 'params' => [ | |
349 | 'version' => 3, | |
350 | 'class_name' => 'CRM_Example_One_Foo', | |
351 | 'is_reserved' => 1, | |
352 | ], | |
9099cab3 CW |
353 | ], |
354 | ]; | |
8cb5ca10 | 355 | $me = new CRM_Core_ManagedEntities($this->modules); |
6a488035 TO |
356 | try { |
357 | $me->reconcile(); | |
358 | $this->fail('Expected exception when using invalid declaration'); | |
0db6c3e1 TO |
359 | } |
360 | catch (Exception $e) { | |
6c6e6187 | 361 | // good |
6a488035 TO |
362 | } |
363 | } | |
364 | ||
365 | /** | |
eceb18cc | 366 | * Setup an active module with a malformed entity declaration. |
6a488035 | 367 | */ |
8cb5ca10 EM |
368 | public function testMissingName(): void { |
369 | $this->managedEntities = [ | |
370 | [ | |
371 | 'module' => 'com.example.unknown', | |
372 | // erroneous | |
373 | 'name' => NULL, | |
374 | 'entity' => 'CustomSearch', | |
375 | 'params' => [ | |
376 | 'version' => 3, | |
377 | 'class_name' => 'CRM_Example_One_Foo', | |
378 | 'is_reserved' => 1, | |
379 | ], | |
9099cab3 CW |
380 | ], |
381 | ]; | |
8cb5ca10 | 382 | $me = new CRM_Core_ManagedEntities($this->modules); |
6a488035 TO |
383 | try { |
384 | $me->reconcile(); | |
385 | $this->fail('Expected exception when using invalid declaration'); | |
0db6c3e1 TO |
386 | } |
387 | catch (Exception $e) { | |
6c6e6187 | 388 | // good |
6a488035 TO |
389 | } |
390 | } | |
391 | ||
392 | /** | |
eceb18cc | 393 | * Setup an active module with a malformed entity declaration. |
6a488035 | 394 | */ |
8cb5ca10 EM |
395 | public function testMissingEntity(): void { |
396 | $this->managedEntities = [ | |
397 | [ | |
398 | 'module' => 'com.example.unknown', | |
399 | 'name' => 'foo', | |
400 | // erroneous | |
401 | 'entity' => NULL, | |
402 | 'params' => [ | |
403 | 'version' => 3, | |
404 | 'class_name' => 'CRM_Example_One_Foo', | |
405 | 'is_reserved' => 1, | |
406 | ], | |
9099cab3 CW |
407 | ], |
408 | ]; | |
8cb5ca10 | 409 | $me = new CRM_Core_ManagedEntities($this->modules); |
6a488035 TO |
410 | try { |
411 | $me->reconcile(); | |
412 | $this->fail('Expected exception when using invalid declaration'); | |
0db6c3e1 TO |
413 | } |
414 | catch (Exception $e) { | |
6c6e6187 | 415 | // good |
6a488035 TO |
416 | } |
417 | } | |
418 | ||
419 | /** | |
420 | * Setup an active module with an entity -- then disable and re-enable the | |
421 | * module | |
d4cf4164 EM |
422 | * |
423 | * @throws \CRM_Core_Exception | |
6a488035 | 424 | */ |
d4cf4164 | 425 | public function testDeactivateReactivateModule(): void { |
20429eb9 | 426 | $manager = CRM_Extension_System::singleton()->getManager(); |
d4cf4164 EM |
427 | // Register the hook so we can check there is no effort to de-activate contact. |
428 | $this->hookClass->setHook('civicrm_pre', [$this, 'preHook']); | |
429 | // create first managed entities ('foo' & Contact) | |
8cb5ca10 | 430 | $this->managedEntities = [$this->fixtures['com.example.one-foo'], $this->fixtures['com.example.one-Contact']]; |
20429eb9 RL |
431 | // Mock the contextual process info that would be added by CRM_Extension_Manager::install |
432 | $manager->setProcessesForTesting(['com.example.one' => ['install']]); | |
8cb5ca10 | 433 | $me = new CRM_Core_ManagedEntities($this->modules); |
6a488035 TO |
434 | $me->reconcile(); |
435 | $foo = $me->get('com.example.one', 'foo'); | |
436 | $this->assertEquals(1, $foo['is_active']); | |
437 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
438 | $this->assertDBQuery(1, 'SELECT is_active FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
439 | ||
8cb5ca10 | 440 | // now deactivate module, which has no declarations and which cascades to managed object |
6a488035 | 441 | $this->modules['one']->is_active = FALSE; |
20429eb9 RL |
442 | // Mock the contextual process info that would be added by CRM_Extension_Manager::disable |
443 | $manager->setProcessesForTesting(['com.example.one' => ['disable']]); | |
8cb5ca10 EM |
444 | $this->managedEntities = []; |
445 | $me = new CRM_Core_ManagedEntities($this->modules); | |
6a488035 TO |
446 | $me->reconcile(); |
447 | $foo = $me->get('com.example.one', 'foo'); | |
448 | $this->assertEquals(0, $foo['is_active']); | |
449 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
450 | $this->assertDBQuery(0, 'SELECT is_active FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
451 | ||
452 | // and reactivate module, which again provides decls and which cascades to managed object | |
453 | $this->modules['one']->is_active = TRUE; | |
20429eb9 RL |
454 | // Mock the contextual process info that would be added by CRM_Extension_Manager::enable |
455 | $manager->setProcessesForTesting(['com.example.one' => ['enable']]); | |
8cb5ca10 EM |
456 | $this->managedEntities = [$this->fixtures['com.example.one-foo'], $this->fixtures['com.example.one-Contact']]; |
457 | ||
458 | $me = new CRM_Core_ManagedEntities($this->modules); | |
6a488035 TO |
459 | $me->reconcile(); |
460 | $foo = $me->get('com.example.one', 'foo'); | |
461 | $this->assertEquals(1, $foo['is_active']); | |
462 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
463 | $this->assertDBQuery(1, 'SELECT is_active FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
20429eb9 RL |
464 | |
465 | // Special case: Job entities. | |
466 | // | |
467 | // First we repeat the above steps, but adding the context that | |
468 | // CRM_Extension_Manager adds when installing/enabling extensions. | |
469 | // | |
470 | // The behaviour should be as above. | |
8cb5ca10 | 471 | $this->managedEntities = [$this->fixtures['com.example.one-Job']]; |
20429eb9 RL |
472 | // Mock the contextual process info that would be added by CRM_Extension_Manager::install |
473 | $manager->setProcessesForTesting(['com.example.one' => ['install']]); | |
8cb5ca10 | 474 | $me = new CRM_Core_ManagedEntities($this->modules); |
20429eb9 RL |
475 | $me->reconcile(); |
476 | $job = $me->get('com.example.one', 'Job'); | |
477 | $this->assertEquals(1, $job['is_active']); | |
478 | $this->assertEquals('test_job', $job['name']); | |
479 | $this->assertDBQuery(1, 'SELECT is_active FROM civicrm_job WHERE name = "test_job"'); | |
480 | // Reset context. | |
481 | $manager->setProcessesForTesting([]); | |
482 | ||
8cb5ca10 | 483 | // now deactivate module |
20429eb9 RL |
484 | $this->modules['one']->is_active = FALSE; |
485 | // Mock the contextual process info that would be added by CRM_Extension_Manager::disable | |
486 | $manager->setProcessesForTesting(['com.example.one' => ['disable']]); | |
8cb5ca10 EM |
487 | $this->managedEntities = []; |
488 | $me = new CRM_Core_ManagedEntities($this->modules); | |
20429eb9 RL |
489 | $me->reconcile(); |
490 | $job = $me->get('com.example.one', 'Job'); | |
491 | $this->assertEquals(0, $job['is_active']); | |
492 | $this->assertEquals('test_job', $job['name']); | |
493 | $this->assertDBQuery(0, 'SELECT is_active FROM civicrm_job WHERE name = "test_job"'); | |
494 | ||
8cb5ca10 | 495 | // and reactivate module |
20429eb9 | 496 | $this->modules['one']->is_active = TRUE; |
8cb5ca10 EM |
497 | $this->managedEntities = [$this->fixtures['com.example.one-Job']]; |
498 | $me = new CRM_Core_ManagedEntities($this->modules); | |
20429eb9 RL |
499 | // Mock the contextual process info that would be added by CRM_Extension_Manager::enable |
500 | $manager->setProcessesForTesting(['com.example.one' => ['enable']]); | |
501 | $me->reconcile(); | |
502 | $job = $me->get('com.example.one', 'Job'); | |
503 | $this->assertEquals(1, $job['is_active']); | |
504 | $this->assertEquals('test_job', $job['name']); | |
505 | $this->assertDBQuery(1, 'SELECT is_active FROM civicrm_job WHERE name = "test_job"'); | |
506 | ||
507 | // Currently: module enabled, job enabled. | |
508 | // Test that if we now manually disable the job, calling reconcile in a | |
509 | // normal flush situation does NOT re-enable it. | |
510 | // ... manually disable job. | |
511 | $this->callAPISuccess('Job', 'create', ['id' => $job['id'], 'is_active' => 0]); | |
512 | ||
513 | // ... now call reconcile in the context of a normal flush operation. | |
514 | // Mock the contextual process info - there would not be any | |
515 | $manager->setProcessesForTesting([]); | |
8cb5ca10 | 516 | $me = new CRM_Core_ManagedEntities($this->modules); |
20429eb9 RL |
517 | $me->reconcile(); |
518 | $job = $me->get('com.example.one', 'Job'); | |
519 | $this->assertEquals(0, $job['is_active'], "Job that was manually set inactive should not have been set active again, but it was."); | |
520 | $this->assertDBQuery(0, 'SELECT is_active FROM civicrm_job WHERE name = "test_job"'); | |
521 | ||
522 | // Now call reconcile again, but in the context of the job's extension being installed/enabled. This should re-enable the job. | |
523 | foreach (['enable', 'install'] as $process) { | |
524 | // Manually disable the job | |
525 | $this->callAPISuccess('Job', 'create', ['id' => $job['id'], 'is_active' => 0]); | |
526 | // Mock the contextual process info that would be added by CRM_Extension_Manager::enable | |
527 | $manager->setProcessesForTesting(['com.example.one' => [$process]]); | |
8cb5ca10 | 528 | $me = new CRM_Core_ManagedEntities($this->modules); |
20429eb9 RL |
529 | $me->reconcile(); |
530 | $job = $me->get('com.example.one', 'Job'); | |
531 | $this->assertEquals(1, $job['is_active']); | |
532 | $this->assertEquals('test_job', $job['name']); | |
533 | $this->assertDBQuery(1, 'SELECT is_active FROM civicrm_job WHERE name = "test_job"'); | |
534 | } | |
535 | ||
536 | // Reset context. | |
537 | $manager->setProcessesForTesting([]); | |
6a488035 TO |
538 | } |
539 | ||
d4cf4164 EM |
540 | /** |
541 | * Pre hook to test contact is not called on disable. | |
542 | * | |
543 | * @param string $op | |
544 | * @param string $objectName | |
545 | * @param int|null $id | |
546 | * @param array $params | |
547 | */ | |
548 | public function preHook($op, $objectName, $id, $params): void { | |
549 | if ($op === 'edit' && $objectName === 'Individual') { | |
550 | $this->assertArrayNotHasKey('is_active', $params); | |
551 | } | |
552 | } | |
553 | ||
6a488035 TO |
554 | /** |
555 | * Setup an active module with an entity -- then entirely uninstall the | |
556 | * module | |
8cb5ca10 EM |
557 | * |
558 | * @throws \CRM_Core_Exception | |
6a488035 | 559 | */ |
8cb5ca10 EM |
560 | public function testUninstallModule(): void { |
561 | $this->managedEntities = [$this->fixtures['com.example.one-foo']]; | |
562 | $me = new CRM_Core_ManagedEntities($this->modules); | |
6a488035 TO |
563 | $me->reconcile(); |
564 | $foo = $me->get('com.example.one', 'foo'); | |
565 | $this->assertEquals('CRM_Example_One_Foo', $foo['name']); | |
566 | $this->assertDBQuery(1, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); | |
567 | ||
8cb5ca10 | 568 | // then destroy module |
6a488035 | 569 | unset($this->modules['one']); |
8cb5ca10 EM |
570 | $this->managedEntities = []; |
571 | $me = new CRM_Core_ManagedEntities($this->modules); | |
6a488035 TO |
572 | $me->reconcile(); |
573 | $fooNew = $me->get('com.example.one', 'foo'); | |
8cb5ca10 | 574 | $this->assertNull($fooNew); |
6a488035 TO |
575 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_option_value WHERE name = "CRM_Example_One_Foo"'); |
576 | } | |
96025800 | 577 | |
8cb5ca10 EM |
578 | /** |
579 | * @throws \CRM_Core_Exception | |
580 | */ | |
581 | public function testDependentEntitiesUninstallCleanly(): void { | |
ee8b9cee MM |
582 | |
583 | // Install a module with two dependent managed entities | |
8cb5ca10 EM |
584 | $this->managedEntities = [$this->fixtures['com.example.one-CustomGroup']]; |
585 | $this->managedEntities[] = $this->fixtures['com.example.one-CustomField']; | |
586 | $me = new CRM_Core_ManagedEntities($this->modules); | |
ee8b9cee MM |
587 | $me->reconcile(); |
588 | ||
589 | // Uninstall the module | |
590 | unset($this->modules['one']); | |
8cb5ca10 EM |
591 | $this->managedEntities = []; |
592 | $me = new CRM_Core_ManagedEntities($this->modules); | |
ee8b9cee MM |
593 | $me->reconcile(); |
594 | ||
595 | // Ensure that no managed entities remain in the civicrm_managed | |
596 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_managed'); | |
597 | ||
598 | // Ensure that com.example.one-CustomGroup is deleted | |
599 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_custom_group WHERE name = "test_custom_group"'); | |
600 | ||
601 | // Ensure that com.example.one-CustomField is deleted | |
602 | $this->assertDBQuery(0, 'SELECT count(*) FROM civicrm_custom_field WHERE name = "test_custom_field"'); | |
603 | ||
604 | } | |
605 | ||
15fbb541 TO |
606 | /** |
607 | * The hook_managed signature expanded slightly (adding the `$modules` filter). | |
608 | * Pre-existing implementations may over-report (ie return entities despite the `$modules` filter). | |
609 | * This test ensures that the framework respects the `$modules` filter (even if specific implementations don't). | |
610 | */ | |
611 | public function testHookManaged_FilterModule() { | |
612 | $this->managedEntities = [ | |
613 | $this->fixtures['com.example.one-bar'], | |
614 | $this->fixtures['com.example.two-CustomGroup'], | |
615 | $this->fixtures['com.example.three-CustomGroup'], | |
616 | ]; | |
617 | ||
618 | $entitiesAll = []; | |
619 | CRM_Utils_Hook::managed($entitiesAll); | |
620 | $this->assertEquals($this->managedEntities, $entitiesAll); | |
621 | $this->assertEquals(3, count($entitiesAll)); | |
622 | ||
623 | $entitiesTwoOnly = []; | |
624 | CRM_Utils_Hook::managed($entitiesTwoOnly, ['com.example.two']); | |
625 | $this->assertEquals([$this->fixtures['com.example.two-CustomGroup']], array_values($entitiesTwoOnly)); | |
626 | $this->assertEquals(1, count($entitiesTwoOnly)); | |
627 | ||
628 | $entitiesTwoExtra = []; | |
629 | CRM_Utils_Hook::managed($entitiesTwoExtra, ['com.example.two', 'com.example.extra']); | |
630 | $this->assertEquals([$this->fixtures['com.example.two-CustomGroup']], array_values($entitiesTwoExtra)); | |
631 | $this->assertEquals(1, count($entitiesTwoExtra)); | |
632 | ||
633 | $entitiesTwoThree = []; | |
634 | CRM_Utils_Hook::managed($entitiesTwoThree, ['com.example.two', 'com.example.three']); | |
635 | $this->assertEquals([$this->fixtures['com.example.two-CustomGroup'], $this->fixtures['com.example.three-CustomGroup']], array_values($entitiesTwoThree)); | |
636 | $this->assertEquals(2, count($entitiesTwoThree)); | |
637 | } | |
638 | ||
6a488035 | 639 | } |