MDL-79843 core: add plugin_manager tests for plugintype deprecation
This change also includes a small extension to testable_plugin_manager, allowing it to load a fixture plugininfo class for mock plugintypes from the respective mock type directory root instead of requiring the plugininfo be located in lib/classes/plugininfo. This prevents debugging calls during mock use in tests.
This commit is contained in:
+33
@@ -121,4 +121,37 @@ class testable_core_plugin_manager extends core_plugin_manager {
|
||||
|
||||
$this->presentplugins[$record->type][$record->name] = $record;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test-specific override allowing mock plugin types to provide their plugininfo at PATH/TYPE_plugininfo.php instead of the
|
||||
* usual core location lib/classes/plugininfo.
|
||||
*
|
||||
* This is required to:
|
||||
* a) prevent debugging calls during tests using deep mocked plugintypes, as their plugininfo can't be located without this
|
||||
* override.
|
||||
* b) ensure plugin_manager returns an instance of the fixture plugininfo class, during tests using deep mocked plugintypes.
|
||||
* If no fixture plugininfo is found, plugin_manager will default to \core\pluginfo\general.
|
||||
*
|
||||
* @param string $type the plugintype.
|
||||
* @return string the name of the plugininfo class.
|
||||
*/
|
||||
public static function resolve_plugininfo_class($type): string {
|
||||
$allplugintypes = array_merge(
|
||||
\core_component::get_plugin_types(),
|
||||
\core_component::get_deprecated_plugin_types(),
|
||||
\core_component::get_deleted_plugin_types()
|
||||
);
|
||||
|
||||
// This is not a problem for mock plugins supporting subtypes, since subtype plugininfo class can be loaded, as expected,
|
||||
// from the subtype root directory.
|
||||
$issubtype = !is_null(\core_component::get_subtype_parent($type));
|
||||
|
||||
$path = $allplugintypes[$type];
|
||||
if (!$issubtype && preg_match('/lib\/tests\/fixtures/', $path)) {
|
||||
require_once("$path/{$type}_plugininfo.php");
|
||||
return "{$type}_plugininfo";
|
||||
}
|
||||
|
||||
return parent::resolve_plugininfo_class($type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
namespace core;
|
||||
|
||||
use core\plugininfo\base;
|
||||
use core\tests\fake_plugins_test_trait;
|
||||
use core_plugin_manager;
|
||||
use testable_core_plugin_manager;
|
||||
use testable_plugininfo_base;
|
||||
@@ -30,6 +32,9 @@ use testable_plugininfo_base;
|
||||
* @covers \core_plugin_manager
|
||||
*/
|
||||
final class plugin_manager_test extends \advanced_testcase {
|
||||
|
||||
use fake_plugins_test_trait;
|
||||
|
||||
public static function setUpBeforeClass(): void {
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/lib/tests/fixtures/testable_plugin_manager.php');
|
||||
@@ -786,4 +791,272 @@ final class plugin_manager_test extends \advanced_testcase {
|
||||
$this->assertContains('block_badges', $plugins);
|
||||
$this->assertNotContains('marmelade_paddington', $plugins);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test core_plugin_manager when dealing with deprecated plugin (not subplugin) types.
|
||||
*
|
||||
* @runInSeparateProcess
|
||||
* @return void
|
||||
*/
|
||||
public function test_plugin_manager_deprecated_plugintype(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Inject the mock plugin 'fake_fullfeatured' and deprecate it.
|
||||
$this->add_full_mocked_plugintype(
|
||||
plugintype: 'fake',
|
||||
path: 'lib/tests/fixtures/fakeplugins/fake',
|
||||
);
|
||||
$this->deprecate_full_mocked_plugintype('fake');
|
||||
|
||||
// Use testable_plugin_manager, as this properly loads the mocked fake_plugininfo class, meaning the fake plugins are
|
||||
// recognised by the plugin manager. See testable_plugin_manager::resolve_plugininfo_class().
|
||||
$pluginman = testable_core_plugin_manager::instance();
|
||||
|
||||
// Deprecated plugin type are excluded from the following for B/C.
|
||||
$this->assertArrayNotHasKey('fake', $pluginman->get_plugin_types());
|
||||
$this->assertNull($pluginman->get_enabled_plugins('fake'));
|
||||
|
||||
// Deprecated plugins excluded by default for B/C, but can be included by request.
|
||||
$this->assertArrayNotHasKey('fake', $pluginman->get_plugins());
|
||||
$plugins = $pluginman->get_plugins(true);
|
||||
$this->assertArrayHasKey('fake', $plugins);
|
||||
|
||||
/** @var base $plugininfo */
|
||||
$plugininfo = $plugins['fake']['fullfeatured'];
|
||||
$this->assertNull($plugininfo->is_enabled());
|
||||
$this->assertTrue($plugininfo->is_deprecated());
|
||||
$this->assertFalse($plugininfo->is_deleted());
|
||||
$this->assertTrue($plugininfo->is_uninstall_allowed());
|
||||
$this->assertIsString($plugininfo->full_path('version.php'));
|
||||
$this->assertEquals(\core_plugin_manager::PLUGIN_STATUS_UPTODATE, $plugininfo->get_status());
|
||||
$this->assertFalse($plugininfo->get_parent_plugin());
|
||||
$this->assertNotEmpty($plugininfo->versiondisk);
|
||||
$this->assertStringContainsString('/fake/', $plugininfo->get_dir());
|
||||
|
||||
$this->assertArrayNotHasKey('fullfeatured', $pluginman->get_plugins_of_type('fake'));
|
||||
$this->assertArrayHasKey('fullfeatured', $pluginman->get_plugins_of_type('fake', true));
|
||||
|
||||
// Deprecated plugins included in the following.
|
||||
$this->assertArrayHasKey('fullfeatured', $pluginman->get_present_plugins('fake')); // Plugins on disk.
|
||||
$this->assertArrayHasKey('fullfeatured', $pluginman->get_installed_plugins('fake')); // Plugins with DB config.
|
||||
$this->assertInstanceOf(\fake_plugininfo::class, $pluginman->get_plugin_info('fake_fullfeatured'));
|
||||
$this->assertIsString($pluginman->get_plugintype_root('fake'));
|
||||
$this->assertTrue($pluginman->can_uninstall_plugin('fake_fullfeatured'));
|
||||
$uninstallurl = $pluginman->get_uninstall_url('fake_fullfeatured');
|
||||
$this->assertInstanceOf(\moodle_url::class, $uninstallurl);
|
||||
$this->assertEquals('fake_fullfeatured', $uninstallurl->param('uninstall'));
|
||||
|
||||
// Strings are supported for deprecated plugins.
|
||||
$this->assertEquals('Fake full featured plugin', $pluginman->plugin_name('fake_fullfeatured'));
|
||||
$this->assertEquals('fake', $pluginman->plugintype_name('fake'));
|
||||
$this->assertEquals('fake', $pluginman->plugintype_name_plural('fake'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test core_plugin_manager when dealing with deprecated subplugin types.
|
||||
*
|
||||
* @runInSeparateProcess
|
||||
* @return void
|
||||
*/
|
||||
public function test_plugin_manager_deprecated_subplugintype(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Inject the 'fake' plugin type. This includes three mock subplugins:
|
||||
// 1. fullsubtype_example: a regular plugin type, not deprecated, nor deleted.
|
||||
// 2. fulldeprecatedsubtype_test: a deprecated subplugin type.
|
||||
// 3. fulldeletedsubtype_demo: a deleted subplugin type.
|
||||
$this->add_full_mocked_plugintype(
|
||||
plugintype: 'fake',
|
||||
path: 'lib/tests/fixtures/fakeplugins/fake',
|
||||
subpluginsupport: true
|
||||
);
|
||||
|
||||
// Use testable_plugin_manager, as this properly loads the mocked fake_plugininfo class, meaning the fake plugins are
|
||||
// recognised by the plugin manager. See testable_plugin_manager::resolve_plugininfo_class().
|
||||
$pluginman = testable_core_plugin_manager::instance();
|
||||
|
||||
// Deprecated plugin type are excluded from the following for B/C.
|
||||
$this->assertArrayNotHasKey('fulldeprecatedsubtype', $pluginman->get_plugin_types());
|
||||
$this->assertNull($pluginman->get_enabled_plugins('fulldeprecatedsubtype'));
|
||||
$subplugins = $pluginman->get_subplugins();
|
||||
$this->assertArrayHasKey('fake_fullfeatured', $subplugins);
|
||||
$fullfeaturedplug = $subplugins['fake_fullfeatured'];
|
||||
$this->assertArrayHasKey('fullsubtype', $fullfeaturedplug);
|
||||
$this->assertArrayNotHasKey('fulldeprecatedsubtype', $fullfeaturedplug);
|
||||
$this->assertArrayHasKey('fullsubtype_example', $pluginman->get_subplugins_of_plugin('fake_fullfeatured'));
|
||||
$this->assertArrayNotHasKey('fulldeprecatedsubtype_test', $pluginman->get_subplugins_of_plugin('fake_fullfeatured'));
|
||||
|
||||
// Deprecated plugins excluded by default for B/C, but can be included by request.
|
||||
$this->assertArrayNotHasKey('fulldeprecatedsubtype', $pluginman->get_plugins());
|
||||
$plugins = $pluginman->get_plugins(true);
|
||||
$this->assertArrayHasKey('fulldeprecatedsubtype', $plugins);
|
||||
|
||||
/** @var base $plugininfo */
|
||||
$plugininfo = $plugins['fulldeprecatedsubtype']['test'];
|
||||
$this->assertNull($plugininfo->is_enabled());
|
||||
$this->assertTrue($plugininfo->is_deprecated());
|
||||
$this->assertFalse($plugininfo->is_deleted());
|
||||
$this->assertTrue($plugininfo->is_uninstall_allowed());
|
||||
$this->assertIsString($plugininfo->full_path('version.php'));
|
||||
$this->assertEquals(\core_plugin_manager::PLUGIN_STATUS_UPTODATE, $plugininfo->get_status());
|
||||
$this->assertEquals('fake_fullfeatured', $plugininfo->get_parent_plugin());
|
||||
$this->assertNotEmpty($plugininfo->versiondisk);
|
||||
$this->assertStringContainsString('/fulldeprecatedsubtype/', $plugininfo->get_dir());
|
||||
|
||||
$this->assertArrayNotHasKey('test', $pluginman->get_plugins_of_type('fulldeprecatedsubtype'));
|
||||
$this->assertArrayHasKey('test', $pluginman->get_plugins_of_type('fulldeprecatedsubtype', true));
|
||||
|
||||
$this->assertFalse($pluginman->get_parent_of_subplugin('fulldeprecatedsubtype'));
|
||||
$this->assertEquals('fake_fullfeatured', $pluginman->get_parent_of_subplugin('fulldeprecatedsubtype', true));
|
||||
|
||||
// Deprecated plugins included in the following.
|
||||
$this->assertArrayHasKey('test', $pluginman->get_present_plugins('fulldeprecatedsubtype')); // Plugins on disk.
|
||||
$this->assertArrayHasKey('test', $pluginman->get_installed_plugins('fulldeprecatedsubtype')); // Plugins with DB config.
|
||||
$this->assertInstanceOf(\fake_fullfeatured\plugininfo\fulldeprecatedsubtype::class,
|
||||
$pluginman->get_plugin_info('fulldeprecatedsubtype_test'));
|
||||
$this->assertEquals('Full deprecated subtype test', $pluginman->plugin_name('fulldeprecatedsubtype_test'));
|
||||
$this->assertIsString($pluginman->get_plugintype_root('fulldeprecatedsubtype'));
|
||||
$this->assertTrue($pluginman->can_uninstall_plugin('fulldeprecatedsubtype_test'));
|
||||
$uninstallurl = $pluginman->get_uninstall_url('fulldeprecatedsubtype_test');
|
||||
$this->assertInstanceOf(\moodle_url::class, $uninstallurl);
|
||||
$this->assertEquals('fulldeprecatedsubtype_test', $uninstallurl->param('uninstall'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test core_plugin_manager when dealing with deleted plugin (not subplugin) types.
|
||||
*
|
||||
* @runInSeparateProcess
|
||||
* @return void
|
||||
*/
|
||||
public function test_plugin_manager_deleted_plugintype(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Inject the mock plugin 'fake_fullfeatured', and deprecate it.
|
||||
$this->add_full_mocked_plugintype(
|
||||
plugintype: 'fake',
|
||||
path: 'lib/tests/fixtures/fakeplugins/fake',
|
||||
);
|
||||
$this->delete_full_mocked_plugintype('fake');
|
||||
|
||||
// Use testable_plugin_manager, as this properly loads the mocked fake_plugininfo class, meaning the fake plugins are
|
||||
// recognised by the plugin manager. See testable_plugin_manager::resolve_plugininfo_class().
|
||||
$pluginman = testable_core_plugin_manager::instance();
|
||||
|
||||
// Deleted plugins are excluded from the following for B/C.
|
||||
$this->assertArrayNotHasKey('fake', $pluginman->get_plugin_types());
|
||||
$this->assertNull($pluginman->get_enabled_plugins('fake'));
|
||||
|
||||
// Deleted plugins excluded by default for B/C, but can be included by request.
|
||||
$this->assertArrayNotHasKey('fake', $pluginman->get_plugins());
|
||||
$plugins = $pluginman->get_plugins(true);
|
||||
$this->assertArrayHasKey('fake', $plugins);
|
||||
|
||||
/** @var base $plugininfo */
|
||||
$plugininfo = $plugins['fake']['fullfeatured'];
|
||||
$this->assertNull($plugininfo->is_enabled());
|
||||
$this->assertFalse($plugininfo->is_deprecated());
|
||||
$this->assertTrue($plugininfo->is_deleted());
|
||||
$this->assertTrue($plugininfo->is_uninstall_allowed());
|
||||
$this->assertIsString($plugininfo->full_path('version.php'));
|
||||
$this->assertEquals(\core_plugin_manager::PLUGIN_STATUS_UPTODATE, $plugininfo->get_status());
|
||||
$this->assertFalse($plugininfo->get_parent_plugin());
|
||||
$this->assertNotEmpty($plugininfo->versiondisk);
|
||||
$this->assertStringContainsString('/fake/', $plugininfo->get_dir());
|
||||
|
||||
$this->assertArrayNotHasKey('fullfeatured', $pluginman->get_plugins_of_type('fake'));
|
||||
$this->assertArrayHasKey('fullfeatured', $pluginman->get_plugins_of_type('fake', true));
|
||||
|
||||
// Deleted plugins included in the following.
|
||||
$this->assertArrayHasKey('fullfeatured', $pluginman->get_present_plugins('fake')); // Plugins on disk.
|
||||
$this->assertArrayHasKey('fullfeatured', $pluginman->get_installed_plugins('fake')); // Plugins with DB config.
|
||||
$this->assertInstanceOf(\fake_plugininfo::class, $pluginman->get_plugin_info('fake_fullfeatured'));
|
||||
$this->assertIsString($pluginman->get_plugintype_root('fake'));
|
||||
$this->assertTrue($pluginman->can_uninstall_plugin('fake_fullfeatured'));
|
||||
$uninstallurl = $pluginman->get_uninstall_url('fake_fullfeatured');
|
||||
$this->assertInstanceOf(\moodle_url::class, $uninstallurl);
|
||||
$this->assertEquals('fake_fullfeatured', $uninstallurl->param('uninstall'));
|
||||
|
||||
// Included, but there is no string support for deleted plugin types.
|
||||
// Without string support, the type name defaults to the plugin type,
|
||||
// while plugin name is set in \core\plugininfo\base::init_is_deprecated().
|
||||
$this->assertEquals('fullfeatured', $pluginman->plugin_name('fake_fullfeatured'));
|
||||
$this->assertEquals('fake', $pluginman->plugintype_name('fake'));
|
||||
$this->assertEquals('fake', $pluginman->plugintype_name_plural('fake'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test core_plugin_manager when dealing with deleted subplugin types.
|
||||
*
|
||||
* @runInSeparateProcess
|
||||
* @return void
|
||||
*/
|
||||
public function test_plugin_manager_deleted_subplugintype(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Inject the 'fake' plugin type. This includes three mock subplugins:
|
||||
// 1. fullsubtype_example: a regular plugin type, not deprecated, nor deleted.
|
||||
// 2. fulldeprecatedsubtype_test: a deprecated subplugin type.
|
||||
// 3. fulldeletedsubtype_demo: a deleted subplugin type.
|
||||
$this->add_full_mocked_plugintype(
|
||||
plugintype: 'fake',
|
||||
path: 'lib/tests/fixtures/fakeplugins/fake',
|
||||
subpluginsupport: true
|
||||
);
|
||||
|
||||
// Use testable_plugin_manager, as this properly loads the mocked fake_plugininfo class, meaning the fake plugins are
|
||||
// recognised by the plugin manager. See testable_plugin_manager::resolve_plugininfo_class().
|
||||
$pluginman = testable_core_plugin_manager::instance();
|
||||
|
||||
// Deleted plugin type are excluded from the following for B/C.
|
||||
$this->assertArrayNotHasKey('fulldeletedsubtype', $pluginman->get_plugin_types());
|
||||
$this->assertNull($pluginman->get_enabled_plugins('fulldeletedsubtype'));
|
||||
$subplugins = $pluginman->get_subplugins();
|
||||
$this->assertArrayHasKey('fake_fullfeatured', $subplugins);
|
||||
$fullfeaturedplug = $subplugins['fake_fullfeatured'];
|
||||
$this->assertArrayHasKey('fullsubtype', $fullfeaturedplug);
|
||||
$this->assertArrayNotHasKey('fulldeletedsubtype', $fullfeaturedplug);
|
||||
$this->assertArrayHasKey('fullsubtype_example', $pluginman->get_subplugins_of_plugin('fake_fullfeatured'));
|
||||
$this->assertArrayNotHasKey('fulldeletedsubtype_demo', $pluginman->get_subplugins_of_plugin('fake_fullfeatured'));
|
||||
|
||||
// Deleted plugins excluded by default for B/C, but can be included by request.
|
||||
$this->assertArrayNotHasKey('fulldeletedsubtype', $pluginman->get_plugins());
|
||||
$plugins = $pluginman->get_plugins(true);
|
||||
$this->assertArrayHasKey('fulldeletedsubtype', $plugins);
|
||||
|
||||
/** @var base $plugininfo */
|
||||
$plugininfo = $plugins['fulldeletedsubtype']['demo'];
|
||||
$this->assertNull($plugininfo->is_enabled());
|
||||
$this->assertFalse($plugininfo->is_deprecated());
|
||||
$this->assertTrue($plugininfo->is_deleted());
|
||||
$this->assertTrue($plugininfo->is_uninstall_allowed());
|
||||
$this->assertIsString($plugininfo->full_path('version.php'));
|
||||
$this->assertEquals(\core_plugin_manager::PLUGIN_STATUS_UPTODATE, $plugininfo->get_status());
|
||||
$this->assertEquals('fake_fullfeatured', $plugininfo->get_parent_plugin());
|
||||
$this->assertNotEmpty($plugininfo->versiondisk);
|
||||
$this->assertStringContainsString('/fulldeletedsubtype/', $plugininfo->get_dir());
|
||||
|
||||
$this->assertArrayNotHasKey('demo', $pluginman->get_plugins_of_type('fulldeletedsubtype'));
|
||||
$this->assertArrayHasKey('demo', $pluginman->get_plugins_of_type('fulldeletedsubtype', true));
|
||||
|
||||
$this->assertFalse($pluginman->get_parent_of_subplugin('fulldeletedsubtype'));
|
||||
$this->assertEquals('fake_fullfeatured', $pluginman->get_parent_of_subplugin('fulldeletedsubtype', true));
|
||||
|
||||
// Deprecated plugins included in the following.
|
||||
$this->assertArrayHasKey('demo', $pluginman->get_present_plugins('fulldeletedsubtype')); // Plugins on disk.
|
||||
$this->assertArrayHasKey('demo', $pluginman->get_installed_plugins('fulldeletedsubtype')); // Plugins with DB config.
|
||||
$this->assertInstanceOf(\fake_fullfeatured\plugininfo\fulldeletedsubtype::class,
|
||||
$pluginman->get_plugin_info('fulldeletedsubtype_demo'));
|
||||
$this->assertIsString($pluginman->get_plugintype_root('fulldeletedsubtype'));
|
||||
$this->assertTrue($pluginman->can_uninstall_plugin('fulldeletedsubtype_demo'));
|
||||
$uninstallurl = $pluginman->get_uninstall_url('fulldeletedsubtype_demo');
|
||||
$this->assertInstanceOf(\moodle_url::class, $uninstallurl);
|
||||
$this->assertEquals('fulldeletedsubtype_demo', $uninstallurl->param('uninstall'));
|
||||
|
||||
// Included, but there is no string support for deleted plugin types.
|
||||
// Without string support, the type name defaults to the plugin type,
|
||||
// while plugin name is set in \core\plugininfo\base::init_is_deprecated().
|
||||
$this->assertEquals('demo', $pluginman->plugin_name('fulldeletedsubtype_demo'));
|
||||
$this->assertEquals('fulldeletedsubtype', $pluginman->plugintype_name('fulldeletedsubtype'));
|
||||
$this->assertEquals('fulldeletedsubtype', $pluginman->plugintype_name_plural('fulldeletedsubtype'));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user