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