| 1 | <?php |
| 2 | |
| 3 | /** |
| 4 | * Class CRM_Extension_Manager_ModuleTest |
| 5 | * @group headless |
| 6 | */ |
| 7 | class CRM_Extension_Manager_ModuleTest extends CiviUnitTestCase { |
| 8 | |
| 9 | public function setUp() { |
| 10 | parent::setUp(); |
| 11 | // $query = "INSERT INTO civicrm_domain ( name, version ) VALUES ( 'domain', 3 )"; |
| 12 | // $result = CRM_Core_DAO::executeQuery($query); |
| 13 | global $_test_extension_manager_moduletest_counts; |
| 14 | $_test_extension_manager_moduletest_counts = array(); |
| 15 | $this->basedir = $this->createTempDir('ext-'); |
| 16 | $this->system = new CRM_Extension_System(array( |
| 17 | 'extensionsDir' => $this->basedir, |
| 18 | 'extensionsURL' => 'http://testbase/', |
| 19 | )); |
| 20 | $this->setExtensionSystem($this->system); |
| 21 | } |
| 22 | |
| 23 | public function tearDown() { |
| 24 | parent::tearDown(); |
| 25 | $this->system = NULL; |
| 26 | } |
| 27 | |
| 28 | /** |
| 29 | * Install an extension with a valid type name. |
| 30 | */ |
| 31 | public function testInstallDisableUninstall() { |
| 32 | $manager = $this->system->getManager(); |
| 33 | $this->assertModuleActiveByName(FALSE, 'moduletest'); |
| 34 | |
| 35 | $manager->install(array('test.extension.manager.moduletest')); |
| 36 | $this->assertHookCounts('moduletest', array( |
| 37 | 'install' => 1, |
| 38 | 'postInstall' => 1, |
| 39 | 'enable' => 1, |
| 40 | 'disable' => 0, |
| 41 | 'uninstall' => 0, |
| 42 | )); |
| 43 | $this->assertModuleActiveByName(TRUE, 'moduletest'); |
| 44 | $this->assertModuleActiveByKey(TRUE, 'test.extension.manager.moduletest'); |
| 45 | |
| 46 | $manager->disable(array('test.extension.manager.moduletest')); |
| 47 | $this->assertHookCounts('moduletest', array( |
| 48 | 'install' => 1, |
| 49 | 'postInstall' => 1, |
| 50 | 'enable' => 1, |
| 51 | 'disable' => 1, |
| 52 | 'uninstall' => 0, |
| 53 | )); |
| 54 | $this->assertModuleActiveByName(FALSE, 'moduletest'); |
| 55 | $this->assertModuleActiveByKey(FALSE, 'test.extension.manager.moduletest'); |
| 56 | |
| 57 | $manager->uninstall(array('test.extension.manager.moduletest')); |
| 58 | $this->assertHookCounts('moduletest', array( |
| 59 | 'install' => 1, |
| 60 | 'postInstall' => 1, |
| 61 | 'enable' => 1, |
| 62 | 'disable' => 1, |
| 63 | 'uninstall' => 1, |
| 64 | )); |
| 65 | $this->assertModuleActiveByName(FALSE, 'moduletest'); |
| 66 | $this->assertModuleActiveByKey(FALSE, 'test.extension.manager.moduletest'); |
| 67 | } |
| 68 | |
| 69 | /** |
| 70 | * Install an extension with a valid type name. |
| 71 | */ |
| 72 | public function testInstallDisableEnable() { |
| 73 | $manager = $this->system->getManager(); |
| 74 | $this->assertModuleActiveByName(FALSE, 'moduletest'); |
| 75 | $this->assertModuleActiveByKey(FALSE, 'test.extension.manager.moduletest'); |
| 76 | |
| 77 | $manager->install(array('test.extension.manager.moduletest')); |
| 78 | $this->assertHookCounts('moduletest', array( |
| 79 | 'install' => 1, |
| 80 | 'enable' => 1, |
| 81 | 'disable' => 0, |
| 82 | 'uninstall' => 0, |
| 83 | )); |
| 84 | $this->assertModuleActiveByName(TRUE, 'moduletest'); |
| 85 | $this->assertModuleActiveByKey(TRUE, 'test.extension.manager.moduletest'); |
| 86 | |
| 87 | $manager->disable(array('test.extension.manager.moduletest')); |
| 88 | $this->assertHookCounts('moduletest', array( |
| 89 | 'install' => 1, |
| 90 | 'enable' => 1, |
| 91 | 'disable' => 1, |
| 92 | 'uninstall' => 0, |
| 93 | )); |
| 94 | $this->assertModuleActiveByName(FALSE, 'moduletest'); |
| 95 | $this->assertModuleActiveByKey(FALSE, 'test.extension.manager.moduletest'); |
| 96 | |
| 97 | $manager->enable(array('test.extension.manager.moduletest')); |
| 98 | $this->assertHookCounts('moduletest', array( |
| 99 | 'install' => 1, |
| 100 | 'enable' => 2, |
| 101 | 'disable' => 1, |
| 102 | 'uninstall' => 0, |
| 103 | )); |
| 104 | $this->assertModuleActiveByName(TRUE, 'moduletest'); |
| 105 | $this->assertModuleActiveByKey(TRUE, 'test.extension.manager.moduletest'); |
| 106 | } |
| 107 | |
| 108 | /** |
| 109 | * Install an extension then forcibly remove the code and cleanup DB afterwards. |
| 110 | */ |
| 111 | public function testInstall_DirtyRemove_Disable_Uninstall() { |
| 112 | // create temporary extension (which can dirtily remove later) |
| 113 | $this->_createExtension('test.extension.manager.module.auto1', 'module', 'test_extension_manager_module_auto1'); |
| 114 | $mainfile = $this->basedir . '/test.extension.manager.module.auto1/test_extension_manager_module_auto1.php'; |
| 115 | $this->assertTrue(file_exists($mainfile)); |
| 116 | $manager = $this->system->getManager(); |
| 117 | $this->assertModuleActiveByName(FALSE, 'test_extension_manager_module_auto1'); |
| 118 | $this->assertModuleActiveByKey(FALSE, 'test.extension.manager.module.auto1'); |
| 119 | |
| 120 | // install it |
| 121 | $manager->install(array('test.extension.manager.module.auto1')); |
| 122 | $this->assertEquals('installed', $manager->getStatus('test.extension.manager.module.auto1')); |
| 123 | $this->assertHookCounts('test_extension_manager_module_auto1', array( |
| 124 | 'install' => 1, |
| 125 | 'enable' => 1, |
| 126 | 'disable' => 0, |
| 127 | 'uninstall' => 0, |
| 128 | )); |
| 129 | $this->assertModuleActiveByName(TRUE, 'test_extension_manager_module_auto1'); |
| 130 | $this->assertModuleActiveByKey(TRUE, 'test.extension.manager.module.auto1'); |
| 131 | |
| 132 | // dirty removal |
| 133 | CRM_Utils_File::cleanDir($this->basedir . '/test.extension.manager.module.auto1', TRUE, FALSE); |
| 134 | $manager->refresh(); |
| 135 | $this->assertEquals('installed-missing', $manager->getStatus('test.extension.manager.module.auto1')); |
| 136 | |
| 137 | // disable while missing |
| 138 | $manager->disable(array('test.extension.manager.module.auto1')); |
| 139 | $this->assertEquals('disabled-missing', $manager->getStatus('test.extension.manager.module.auto1')); |
| 140 | $this->assertHookCounts('test_extension_manager_module_auto1', array( |
| 141 | 'install' => 1, |
| 142 | 'enable' => 1, |
| 143 | 'disable' => 0, // normally called -- but not for missing modules! |
| 144 | 'uninstall' => 0, |
| 145 | )); |
| 146 | $this->assertModuleActiveByName(FALSE, 'test_extension_manager_module_auto1'); |
| 147 | $this->assertModuleActiveByKey(FALSE, 'test.extension.manager.moduletest'); |
| 148 | |
| 149 | $manager->uninstall(array('test.extension.manager.module.auto1')); |
| 150 | $this->assertHookCounts('test_extension_manager_module_auto1', array( |
| 151 | 'install' => 1, |
| 152 | 'enable' => 1, |
| 153 | 'disable' => 0, // normally called -- but not for missing modules! |
| 154 | 'uninstall' => 0, // normally called -- but not for missing modules! |
| 155 | )); |
| 156 | $this->assertEquals('unknown', $manager->getStatus('test.extension.manager.module.auto1')); |
| 157 | $this->assertModuleActiveByName(FALSE, 'test_extension_manager_module_auto1'); |
| 158 | $this->assertModuleActiveByKey(FALSE, 'test.extension.manager.module.auto1'); |
| 159 | } |
| 160 | |
| 161 | /** |
| 162 | * Install an extension then forcibly remove the code and cleanup DB afterwards. |
| 163 | */ |
| 164 | public function testInstall_DirtyRemove_Disable_Restore() { |
| 165 | // create temporary extension (which can dirtily remove later) |
| 166 | $this->_createExtension('test.extension.manager.module.auto2', 'module', 'test_extension_manager_module_auto2'); |
| 167 | $mainfile = $this->basedir . '/test.extension.manager.module.auto2/test_extension_manager_module_auto2.php'; |
| 168 | $this->assertTrue(file_exists($mainfile)); |
| 169 | $manager = $this->system->getManager(); |
| 170 | $this->assertModuleActiveByName(FALSE, 'test_extension_manager_module_auto2'); |
| 171 | $this->assertModuleActiveByKey(FALSE, 'test.extension.manager.module.auto2'); |
| 172 | |
| 173 | // install it |
| 174 | $manager->install(array('test.extension.manager.module.auto2')); |
| 175 | $this->assertEquals('installed', $manager->getStatus('test.extension.manager.module.auto2')); |
| 176 | $this->assertHookCounts('test_extension_manager_module_auto2', array( |
| 177 | 'install' => 1, |
| 178 | 'enable' => 1, |
| 179 | 'disable' => 0, |
| 180 | 'uninstall' => 0, |
| 181 | )); |
| 182 | $this->assertModuleActiveByName(TRUE, 'test_extension_manager_module_auto2'); |
| 183 | $this->assertModuleActiveByKey(TRUE, 'test.extension.manager.module.auto2'); |
| 184 | |
| 185 | // dirty removal |
| 186 | CRM_Utils_File::cleanDir($this->basedir . '/test.extension.manager.module.auto2', TRUE, FALSE); |
| 187 | $manager->refresh(); |
| 188 | $this->assertEquals('installed-missing', $manager->getStatus('test.extension.manager.module.auto2')); |
| 189 | |
| 190 | // disable while missing |
| 191 | $manager->disable(array('test.extension.manager.module.auto2')); |
| 192 | $this->assertEquals('disabled-missing', $manager->getStatus('test.extension.manager.module.auto2')); |
| 193 | $this->assertHookCounts('test_extension_manager_module_auto2', array( |
| 194 | 'install' => 1, |
| 195 | 'enable' => 1, |
| 196 | 'disable' => 0, // normally called -- but not for missing modules! |
| 197 | 'uninstall' => 0, |
| 198 | )); |
| 199 | $this->assertModuleActiveByName(FALSE, 'test_extension_manager_module_auto2'); |
| 200 | $this->assertModuleActiveByKey(FALSE, 'test.extension.manager.moduletest'); |
| 201 | |
| 202 | // restore the code |
| 203 | $this->_createExtension('test.extension.manager.module.auto2', 'module', 'test_extension_manager_module_auto2'); |
| 204 | $manager->refresh(); |
| 205 | $this->assertHookCounts('test_extension_manager_module_auto2', array( |
| 206 | 'install' => 1, |
| 207 | 'enable' => 1, |
| 208 | 'disable' => 0, |
| 209 | 'uninstall' => 0, |
| 210 | )); |
| 211 | $this->assertEquals('disabled', $manager->getStatus('test.extension.manager.module.auto2')); |
| 212 | $this->assertModuleActiveByName(FALSE, 'test_extension_manager_module_auto2'); |
| 213 | $this->assertModuleActiveByKey(FALSE, 'test.extension.manager.module.auto2'); |
| 214 | } |
| 215 | |
| 216 | /** |
| 217 | * @param $module |
| 218 | * @param array $counts |
| 219 | * Expected hook invocation counts ($hookName => $count). |
| 220 | */ |
| 221 | public function assertHookCounts($module, $counts) { |
| 222 | global $_test_extension_manager_moduletest_counts; |
| 223 | foreach ($counts as $key => $expected) { |
| 224 | $actual = @$_test_extension_manager_moduletest_counts[$module][$key]; |
| 225 | $this->assertEquals($expected, $actual, |
| 226 | sprintf('Expected %d call(s) to hook_civicrm_%s -- found %d', $expected, $key, $actual) |
| 227 | ); |
| 228 | } |
| 229 | } |
| 230 | |
| 231 | /** |
| 232 | * @param $expectedIsActive |
| 233 | * @param $prefix |
| 234 | */ |
| 235 | public function assertModuleActiveByName($expectedIsActive, $prefix) { |
| 236 | $activeModules = CRM_Core_PseudoConstant::getModuleExtensions(TRUE); // FIXME |
| 237 | foreach ($activeModules as $activeModule) { |
| 238 | if ($activeModule['prefix'] == $prefix) { |
| 239 | $this->assertEquals($expectedIsActive, TRUE); |
| 240 | return; |
| 241 | } |
| 242 | } |
| 243 | $this->assertEquals($expectedIsActive, FALSE); |
| 244 | } |
| 245 | |
| 246 | /** |
| 247 | * @param $expectedIsActive |
| 248 | * @param $key |
| 249 | */ |
| 250 | public function assertModuleActiveByKey($expectedIsActive, $key) { |
| 251 | foreach (CRM_Core_Module::getAll() as $module) { |
| 252 | if ($module->name == $key) { |
| 253 | $this->assertEquals((bool) $expectedIsActive, (bool) $module->is_active); |
| 254 | return; |
| 255 | } |
| 256 | } |
| 257 | $this->assertEquals($expectedIsActive, FALSE); |
| 258 | } |
| 259 | |
| 260 | /** |
| 261 | * @param $key |
| 262 | * @param $type |
| 263 | * @param $file |
| 264 | * @param string $template |
| 265 | */ |
| 266 | public function _createExtension($key, $type, $file, $template = self::MODULE_TEMPLATE) { |
| 267 | $basedir = $this->basedir; |
| 268 | mkdir("$basedir/$key"); |
| 269 | file_put_contents("$basedir/$key/info.xml", "<extension key='$key' type='$type'><file>$file</file></extension>"); |
| 270 | file_put_contents("$basedir/$key/$file.php", strtr($template, array('_FILE_' => $file))); |
| 271 | $this->system->getCache()->flush(); |
| 272 | $this->system->getManager()->refresh(); |
| 273 | } |
| 274 | |
| 275 | /** |
| 276 | * @param $module |
| 277 | * @param string $name |
| 278 | */ |
| 279 | public static function incHookCount($module, $name) { |
| 280 | global $_test_extension_manager_moduletest_counts; |
| 281 | if (!isset($_test_extension_manager_moduletest_counts[$module][$name])) { |
| 282 | $_test_extension_manager_moduletest_counts[$module][$name] = 0; |
| 283 | } |
| 284 | $_test_extension_manager_moduletest_counts[$module][$name] = 1 + (int) $_test_extension_manager_moduletest_counts[$module][$name]; |
| 285 | } |
| 286 | |
| 287 | const MODULE_TEMPLATE = " |
| 288 | <?php |
| 289 | function _FILE__civicrm_install() { |
| 290 | CRM_Extension_Manager_ModuleTest::incHookCount('_FILE_', 'install'); |
| 291 | } |
| 292 | |
| 293 | function _FILE__civicrm_postInstall() { |
| 294 | CRM_Extension_Manager_ModuleTest::incHookCount('_FILE_', 'postInstall'); |
| 295 | } |
| 296 | |
| 297 | function _FILE__civicrm_uninstall() { |
| 298 | CRM_Extension_Manager_ModuleTest::incHookCount('_FILE_', 'uninstall'); |
| 299 | } |
| 300 | |
| 301 | function _FILE__civicrm_enable() { |
| 302 | CRM_Extension_Manager_ModuleTest::incHookCount('_FILE_', 'enable'); |
| 303 | } |
| 304 | |
| 305 | function _FILE__civicrm_disable() { |
| 306 | CRM_Extension_Manager_ModuleTest::incHookCount('_FILE_', 'disable'); |
| 307 | } |
| 308 | "; |
| 309 | |
| 310 | } |