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