From 04dd610c6f34f081e2caa512b33c2119380e4076 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Tue, 17 Sep 2024 09:49:01 +0200 Subject: [PATCH] Add process and environment capacities --- .../Capacity/HasEnvironmentsCapacity.php | 86 ++++++++ .../Asset/Capacity/HasProcessCapacity.php | 88 ++++++++ .../Capacity/HasEnvironmentsCapacity.php | 200 ++++++++++++++++++ .../Asset/Capacity/HasProcessCapacity.php | 200 ++++++++++++++++++ 4 files changed, 574 insertions(+) create mode 100644 src/Glpi/Asset/Capacity/HasEnvironmentsCapacity.php create mode 100644 src/Glpi/Asset/Capacity/HasProcessCapacity.php create mode 100644 tests/functional/Glpi/Asset/Capacity/HasEnvironmentsCapacity.php create mode 100644 tests/functional/Glpi/Asset/Capacity/HasProcessCapacity.php diff --git a/src/Glpi/Asset/Capacity/HasEnvironmentsCapacity.php b/src/Glpi/Asset/Capacity/HasEnvironmentsCapacity.php new file mode 100644 index 000000000000..382d8221c7ca --- /dev/null +++ b/src/Glpi/Asset/Capacity/HasEnvironmentsCapacity.php @@ -0,0 +1,86 @@ +. + * + * --------------------------------------------------------------------- + */ + +namespace Glpi\Asset\Capacity; + +use CommonGLPI; +use Item_Environment; +use Session; + +class HasEnvironmentsCapacity extends AbstractCapacity +{ + public function getLabel(): string + { + return Item_Environment::getTypeName(Session::getPluralNumber()); + } + + public function getIcon(): string + { + return Item_Environment::getIcon(); + } + + public function isUsed(string $classname): bool + { + return parent::isUsed($classname) + && $this->countAssetsLinkedToPeerItem($classname, Item_Environment::class) > 0; + } + + public function getCapacityUsageDescription(string $classname): string + { + return sprintf( + __('%1$s environments attached to %2$s assets'), + $this->countPeerItemsUsage($classname, Item_Environment::class), + $this->countAssetsLinkedToPeerItem($classname, Item_Environment::class) + ); + } + + public function onClassBootstrap(string $classname): void + { + $this->registerToTypeConfig('environment_types', $classname); + CommonGLPI::registerStandardTab($classname, Item_Environment::class, 85); + } + + public function onCapacityDisabled(string $classname): void + { + $this->unregisterFromTypeConfig('environment_types', $classname); + + $appliance_item = new Item_Environment(); + $appliance_item->deleteByCriteria([ + 'itemtype' => $classname, + ], true, false); + + $this->deleteRelationLogs($classname, Item_Environment::class); + } +} diff --git a/src/Glpi/Asset/Capacity/HasProcessCapacity.php b/src/Glpi/Asset/Capacity/HasProcessCapacity.php new file mode 100644 index 000000000000..605edb216d20 --- /dev/null +++ b/src/Glpi/Asset/Capacity/HasProcessCapacity.php @@ -0,0 +1,88 @@ +. + * + * --------------------------------------------------------------------- + */ + +namespace Glpi\Asset\Capacity; + +use Appliance; +use Appliance_Item; +use CommonGLPI; +use Item_Process; +use Session; + +class HasProcessCapacity extends AbstractCapacity +{ + public function getLabel(): string + { + return Item_Process::getTypeName(Session::getPluralNumber()); + } + + public function getIcon(): string + { + return Item_Process::getIcon(); + } + + public function isUsed(string $classname): bool + { + return parent::isUsed($classname) + && $this->countAssetsLinkedToPeerItem($classname, Item_Process::class) > 0; + } + + public function getCapacityUsageDescription(string $classname): string + { + return sprintf( + __('%1$s process attached to %2$s assets'), + $this->countPeerItemsUsage($classname, Item_Process::class), + $this->countAssetsLinkedToPeerItem($classname, Item_Process::class) + ); + } + + public function onClassBootstrap(string $classname): void + { + $this->registerToTypeConfig('process_types', $classname); + CommonGLPI::registerStandardTab($classname, Item_Process::class, 85); + } + + public function onCapacityDisabled(string $classname): void + { + $this->unregisterFromTypeConfig('process_types', $classname); + + $appliance_item = new Item_Process(); + $appliance_item->deleteByCriteria([ + 'itemtype' => $classname, + ], true, false); + + $this->deleteRelationLogs($classname, Item_Process::class); + } +} diff --git a/tests/functional/Glpi/Asset/Capacity/HasEnvironmentsCapacity.php b/tests/functional/Glpi/Asset/Capacity/HasEnvironmentsCapacity.php new file mode 100644 index 000000000000..2c914e4dbca5 --- /dev/null +++ b/tests/functional/Glpi/Asset/Capacity/HasEnvironmentsCapacity.php @@ -0,0 +1,200 @@ +. + * + * --------------------------------------------------------------------- + */ + +namespace tests\units\Glpi\Asset\Capacity; + +use DbTestCase; +use Entity; +use Glpi\Tests\Asset\CapacityUsageTestTrait; +use Log; + +class HasEnvironmentsCapacity extends DbTestCase +{ + use CapacityUsageTestTrait; + + protected function getTargetCapacity(): string + { + return \Glpi\Asset\Capacity\HasEnvironmentsCapacity::class; + } + + public function testCapacityActivation(): void + { + global $CFG_GLPI; + + $root_entity_id = getItemByTypeName(Entity::class, '_test_root_entity', true); + + $definition_1 = $this->initAssetDefinition( + capacities: [ + \Glpi\Asset\Capacity\HasEnvironmentsCapacity::class, + \Glpi\Asset\Capacity\HasNotepadCapacity::class, + ] + ); + $classname_1 = $definition_1->getAssetClassName(); + $definition_2 = $this->initAssetDefinition( + capacities: [ + \Glpi\Asset\Capacity\HasHistoryCapacity::class, + ] + ); + $classname_2 = $definition_2->getAssetClassName(); + $definition_3 = $this->initAssetDefinition( + capacities: [ + \Glpi\Asset\Capacity\HasEnvironmentsCapacity::class, + \Glpi\Asset\Capacity\HasHistoryCapacity::class, + ] + ); + $classname_3 = $definition_3->getAssetClassName(); + + $has_capacity_mapping = [ + $classname_1 => true, + $classname_2 => false, + $classname_3 => true, + ]; + + foreach ($has_capacity_mapping as $classname => $has_capacity) { + // Check that the class is globally registered + $this->login(); + if ($has_capacity) { + $this->array($CFG_GLPI['environment_types'])->contains($classname); + } else { + $this->array($CFG_GLPI['environment_types'])->notContains($classname); + } + + // Check that the corresponding tab is present on items + $item = $this->createItem($classname, ['name' => __FUNCTION__, 'entities_id' => $root_entity_id]); + $this->login(); + //no item in db, no tab for Item_Environment + $this->array($item->defineAllTabs())->notHasKey('Item_Environment$1'); + + //no search options + } + } + + public function testCapacityDeactivation(): void + { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + + $root_entity_id = getItemByTypeName(Entity::class, '_test_root_entity', true); + + $definition_1 = $this->initAssetDefinition( + capacities: [ + \Glpi\Asset\Capacity\HasEnvironmentsCapacity::class, + \Glpi\Asset\Capacity\HasHistoryCapacity::class, + ] + ); + $classname_1 = $definition_1->getAssetClassName(); + $definition_2 = $this->initAssetDefinition( + capacities: [ + \Glpi\Asset\Capacity\HasEnvironmentsCapacity::class, + \Glpi\Asset\Capacity\HasHistoryCapacity::class, + ] + ); + $classname_2 = $definition_2->getAssetClassName(); + + $item_1 = $this->createItem( + $classname_1, + [ + 'name' => __FUNCTION__, + 'entities_id' => $root_entity_id, + ] + ); + + $item_2 = $this->createItem( + $classname_2, + [ + 'name' => __FUNCTION__, + 'entities_id' => $root_entity_id, + ] + ); + + $environment_item_1 = $this->createItem( + \Item_Environment::class, + [ + 'itemtype' => $item_1::class, + 'items_id' => $item_1->getID() + ] + ); + + $environment_item_2 = $this->createItem( + \Item_Environment::class, + [ + 'itemtype' => $item_2::class, + 'items_id' => $item_2->getID() + ] + ); + + + $item_1_logs_criteria = [ + 'itemtype' => $classname_1, + ]; + $item_2_logs_criteria = [ + 'itemtype' => $classname_2, + ]; + + // Ensure relation, display preferences and logs exists, and class is registered to global config + $this->object(\Item_Environment::getById($environment_item_1->getID()))->isInstanceOf(\Item_Environment::class); + $this->integer(countElementsInTable(Log::getTable(), $item_1_logs_criteria))->isEqualTo(2); //create + add environment + $this->object(\Item_Environment::getById($environment_item_2->getID()))->isInstanceOf(\Item_Environment::class); + $this->integer(countElementsInTable(Log::getTable(), $item_2_logs_criteria))->isEqualTo(2); //create + add environment + $this->array($CFG_GLPI['environment_types'])->contains($classname_1); + $this->array($CFG_GLPI['environment_types'])->contains($classname_2); + + // Disable capacity and check that relations have been cleaned, and class is unregistered from global config + $this->boolean($definition_1->update(['id' => $definition_1->getID(), 'capacities' => []]))->isTrue(); + $this->boolean(\Item_Environment::getById($environment_item_1->getID()))->isFalse(); + $this->integer(countElementsInTable(Log::getTable(), $item_1_logs_criteria))->isEqualTo(0); + $this->array($CFG_GLPI['environment_types'])->notContains($classname_1); + + // Ensure relations, logs and global registration are preserved for other definition + $this->object(\Item_Environment::getById($environment_item_2->getID()))->isInstanceOf(\Item_Environment::class); + $this->integer(countElementsInTable(Log::getTable(), $item_2_logs_criteria))->isEqualTo(2); + $this->array($CFG_GLPI['environment_types'])->contains($classname_2); + } + + public function provideIsUsed(): iterable + { + yield [ + 'target_classname' => \Item_Environment::class + ]; + } + + public function provideGetCapacityUsageDescription(): iterable + { + yield [ + 'target_classname' => \Item_Environment::class, + 'expected' => '%d environments attached to %d assets' + ]; + } +} diff --git a/tests/functional/Glpi/Asset/Capacity/HasProcessCapacity.php b/tests/functional/Glpi/Asset/Capacity/HasProcessCapacity.php new file mode 100644 index 000000000000..9bc4d979e5c9 --- /dev/null +++ b/tests/functional/Glpi/Asset/Capacity/HasProcessCapacity.php @@ -0,0 +1,200 @@ +. + * + * --------------------------------------------------------------------- + */ + +namespace tests\units\Glpi\Asset\Capacity; + +use DbTestCase; +use Entity; +use Glpi\Tests\Asset\CapacityUsageTestTrait; +use Log; + +class HasProcessCapacity extends DbTestCase +{ + use CapacityUsageTestTrait; + + protected function getTargetCapacity(): string + { + return \Glpi\Asset\Capacity\HasProcessCapacity::class; + } + + public function testCapacityActivation(): void + { + global $CFG_GLPI; + + $root_entity_id = getItemByTypeName(Entity::class, '_test_root_entity', true); + + $definition_1 = $this->initAssetDefinition( + capacities: [ + \Glpi\Asset\Capacity\HasProcessCapacity::class, + \Glpi\Asset\Capacity\HasNotepadCapacity::class, + ] + ); + $classname_1 = $definition_1->getAssetClassName(); + $definition_2 = $this->initAssetDefinition( + capacities: [ + \Glpi\Asset\Capacity\HasHistoryCapacity::class, + ] + ); + $classname_2 = $definition_2->getAssetClassName(); + $definition_3 = $this->initAssetDefinition( + capacities: [ + \Glpi\Asset\Capacity\HasProcessCapacity::class, + \Glpi\Asset\Capacity\HasHistoryCapacity::class, + ] + ); + $classname_3 = $definition_3->getAssetClassName(); + + $has_capacity_mapping = [ + $classname_1 => true, + $classname_2 => false, + $classname_3 => true, + ]; + + foreach ($has_capacity_mapping as $classname => $has_capacity) { + // Check that the class is globally registered + $this->login(); + if ($has_capacity) { + $this->array($CFG_GLPI['process_types'])->contains($classname); + } else { + $this->array($CFG_GLPI['process_types'])->notContains($classname); + } + + // Check that the corresponding tab is present on items + $item = $this->createItem($classname, ['name' => __FUNCTION__, 'entities_id' => $root_entity_id]); + $this->login(); + //no item in db, no tab for Item_Process + $this->array($item->defineAllTabs())->notHasKey('Item_Process$1'); + + //no search options + } + } + + public function testCapacityDeactivation(): void + { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + + $root_entity_id = getItemByTypeName(Entity::class, '_test_root_entity', true); + + $definition_1 = $this->initAssetDefinition( + capacities: [ + \Glpi\Asset\Capacity\HasProcessCapacity::class, + \Glpi\Asset\Capacity\HasHistoryCapacity::class, + ] + ); + $classname_1 = $definition_1->getAssetClassName(); + $definition_2 = $this->initAssetDefinition( + capacities: [ + \Glpi\Asset\Capacity\HasProcessCapacity::class, + \Glpi\Asset\Capacity\HasHistoryCapacity::class, + ] + ); + $classname_2 = $definition_2->getAssetClassName(); + + $item_1 = $this->createItem( + $classname_1, + [ + 'name' => __FUNCTION__, + 'entities_id' => $root_entity_id, + ] + ); + + $item_2 = $this->createItem( + $classname_2, + [ + 'name' => __FUNCTION__, + 'entities_id' => $root_entity_id, + ] + ); + + $process_item_1 = $this->createItem( + \Item_Process::class, + [ + 'itemtype' => $item_1::class, + 'items_id' => $item_1->getID() + ] + ); + + $process_item_2 = $this->createItem( + \Item_Process::class, + [ + 'itemtype' => $item_2::class, + 'items_id' => $item_2->getID() + ] + ); + + + $item_1_logs_criteria = [ + 'itemtype' => $classname_1, + ]; + $item_2_logs_criteria = [ + 'itemtype' => $classname_2, + ]; + + // Ensure relation, display preferences and logs exists, and class is registered to global config + $this->object(\Item_Process::getById($process_item_1->getID()))->isInstanceOf(\Item_Process::class); + $this->integer(countElementsInTable(Log::getTable(), $item_1_logs_criteria))->isEqualTo(2); //create + add process + $this->object(\Item_Process::getById($process_item_2->getID()))->isInstanceOf(\Item_Process::class); + $this->integer(countElementsInTable(Log::getTable(), $item_2_logs_criteria))->isEqualTo(2); //create + add process + $this->array($CFG_GLPI['process_types'])->contains($classname_1); + $this->array($CFG_GLPI['process_types'])->contains($classname_2); + + // Disable capacity and check that relations have been cleaned, and class is unregistered from global config + $this->boolean($definition_1->update(['id' => $definition_1->getID(), 'capacities' => []]))->isTrue(); + $this->boolean(\Item_Process::getById($process_item_1->getID()))->isFalse(); + $this->integer(countElementsInTable(Log::getTable(), $item_1_logs_criteria))->isEqualTo(0); + $this->array($CFG_GLPI['process_types'])->notContains($classname_1); + + // Ensure relations, logs and global registration are preserved for other definition + $this->object(\Item_Process::getById($process_item_2->getID()))->isInstanceOf(\Item_Process::class); + $this->integer(countElementsInTable(Log::getTable(), $item_2_logs_criteria))->isEqualTo(2); + $this->array($CFG_GLPI['process_types'])->contains($classname_2); + } + + public function provideIsUsed(): iterable + { + yield [ + 'target_classname' => \Item_Process::class + ]; + } + + public function provideGetCapacityUsageDescription(): iterable + { + yield [ + 'target_classname' => \Item_Process::class, + 'expected' => '%d process attached to %d assets' + ]; + } +}