From 50a87ef47b26febc1941d241ac3d7d572d34a4e5 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Tue, 17 Sep 2024 10:29:48 +0200 Subject: [PATCH] Add inventoriable capacity (#17807) * Add inventoriable capacity Update DB schema with missing fields Add configuration types for environment and process, use them in inventory Add checks for Monitor and Peripherals Add missing devices types in configuration Add new tests Fix Monitor and Printer inventory Prevent numerous Undefined array key "glpi_currenttime" loading bootstrap data * Fix CS --- .phpstan-baseline.php | 60 - composer.lock | 62 +- inc/relation.constant.php | 1 + .../update_10.0.x_to_11.0.0/assets.php | 14 + install/mysql/glpi-empty.sql | 7 + .../Glpi/Inventory/Assets/ComputerTest.php | 3 +- .../Glpi/Inventory/Assets/ControllerTest.php | 14 +- .../Inventory/GenericAssetInventoryTest.php | 1980 +++++++++++++++++ .../Glpi/Inventory/InventoryTest.php | 2 +- src/Glpi/Asset/Asset.php | 1 + src/Glpi/Asset/Asset_PeripheralAsset.php | 3 +- src/Glpi/Asset/Capacity/AbstractCapacity.php | 10 +- .../Capacity/IsInventoriableCapacity.php | 104 + src/Glpi/Features/Inventoriable.php | 1 + src/Glpi/Inventory/Asset/Antivirus.php | 4 +- src/Glpi/Inventory/Asset/Battery.php | 2 +- src/Glpi/Inventory/Asset/Bios.php | 5 - src/Glpi/Inventory/Asset/Camera.php | 5 - src/Glpi/Inventory/Asset/Computer.php | 5 - src/Glpi/Inventory/Asset/Controller.php | 3 +- src/Glpi/Inventory/Asset/DatabaseInstance.php | 4 +- src/Glpi/Inventory/Asset/Device.php | 11 + src/Glpi/Inventory/Asset/Drive.php | 2 +- src/Glpi/Inventory/Asset/Environment.php | 4 +- src/Glpi/Inventory/Asset/Firmware.php | 5 - src/Glpi/Inventory/Asset/GenericAsset.php | 60 + src/Glpi/Inventory/Asset/GraphicCard.php | 2 +- src/Glpi/Inventory/Asset/HardDrive.php | 2 +- src/Glpi/Inventory/Asset/InventoryAsset.php | 5 +- .../Inventory/Asset/InventoryNetworkPort.php | 10 +- src/Glpi/Inventory/Asset/MainAsset.php | 4 +- src/Glpi/Inventory/Asset/Memory.php | 2 +- src/Glpi/Inventory/Asset/Monitor.php | 9 +- src/Glpi/Inventory/Asset/NetworkCard.php | 2 +- src/Glpi/Inventory/Asset/NetworkEquipment.php | 5 - src/Glpi/Inventory/Asset/NetworkPort.php | 6 +- src/Glpi/Inventory/Asset/OperatingSystem.php | 4 +- src/Glpi/Inventory/Asset/Peripheral.php | 5 +- src/Glpi/Inventory/Asset/Phone.php | 5 - src/Glpi/Inventory/Asset/PowerSupply.php | 2 +- src/Glpi/Inventory/Asset/Printer.php | 20 +- src/Glpi/Inventory/Asset/Process.php | 4 +- src/Glpi/Inventory/Asset/Processor.php | 2 +- src/Glpi/Inventory/Asset/RemoteManagement.php | 4 +- src/Glpi/Inventory/Asset/Sensor.php | 5 - src/Glpi/Inventory/Asset/Simcard.php | 2 +- src/Glpi/Inventory/Asset/Software.php | 4 +- src/Glpi/Inventory/Asset/SoundCard.php | 2 +- src/Glpi/Inventory/Asset/Unmanaged.php | 5 - src/Glpi/Inventory/Asset/VirtualMachine.php | 4 +- src/Glpi/Inventory/Asset/Volume.php | 4 +- src/Glpi/Inventory/Inventory.php | 28 +- src/autoload/CFG_GLPI.php | 9 +- .../Capacity/IsInventoriableCapacity.php | 228 ++ tests/src/autoload/functions.php | 1 + 55 files changed, 2575 insertions(+), 182 deletions(-) create mode 100644 phpunit/functional/Glpi/Inventory/GenericAssetInventoryTest.php create mode 100644 src/Glpi/Asset/Capacity/IsInventoriableCapacity.php create mode 100644 src/Glpi/Inventory/Asset/GenericAsset.php create mode 100644 tests/functional/Glpi/Asset/Capacity/IsInventoriableCapacity.php diff --git a/.phpstan-baseline.php b/.phpstan-baseline.php index c38b7f0182b..9dbf7a507bd 100644 --- a/.phpstan-baseline.php +++ b/.phpstan-baseline.php @@ -907,12 +907,6 @@ 'count' => 1, 'path' => __DIR__ . '/src/CommonItilObject_Item.php', ]; -$ignoreErrors[] = [ - // identifier: greater.alwaysTrue - 'message' => '#^Comparison operation "\\>" between int\\<1, max\\> and 0 is always true\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/src/Computer.php', -]; $ignoreErrors[] = [ // identifier: instanceof.alwaysFalse 'message' => '#^Instanceof between static\\(Computer\\) and PDU will always evaluate to false\\.$#', @@ -1231,12 +1225,6 @@ 'count' => 1, 'path' => __DIR__ . '/src/DCRoom.php', ]; -$ignoreErrors[] = [ - // identifier: greater.alwaysTrue - 'message' => '#^Comparison operation "\\>" between int\\<1, max\\> and 0 is always true\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/src/DatabaseInstance.php', -]; $ignoreErrors[] = [ // identifier: identical.alwaysFalse 'message' => '#^Strict comparison using \\=\\=\\= between array and false will always evaluate to false\\.$#', @@ -1963,12 +1951,6 @@ 'count' => 1, 'path' => __DIR__ . '/src/Glpi/Asset/AssetType.php', ]; -$ignoreErrors[] = [ - // identifier: classConstant.nonObject - 'message' => '#^Cannot access constant class on CommonDBTM\\|false\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/src/Glpi/Asset/Asset_PeripheralAsset.php', -]; $ignoreErrors[] = [ // identifier: parameter.notFound 'message' => '#^PHPDoc tag @param references unknown parameter\\: \\$source_itemtype$#', @@ -3649,12 +3631,6 @@ 'count' => 8, 'path' => __DIR__ . '/src/Migration.php', ]; -$ignoreErrors[] = [ - // identifier: greater.alwaysTrue - 'message' => '#^Comparison operation "\\>" between int\\<1, max\\> and 0 is always true\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/src/Monitor.php', -]; $ignoreErrors[] = [ // identifier: instanceof.alwaysFalse 'message' => '#^Instanceof between static\\(Monitor\\) and PDU will always evaluate to false\\.$#', @@ -3685,12 +3661,6 @@ 'count' => 1, 'path' => __DIR__ . '/src/Monitor.php', ]; -$ignoreErrors[] = [ - // identifier: greater.alwaysTrue - 'message' => '#^Comparison operation "\\>" between int\\<1, max\\> and 0 is always true\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/src/NetworkEquipment.php', -]; $ignoreErrors[] = [ // identifier: if.alwaysTrue 'message' => '#^If condition is always true\\.$#', @@ -3919,12 +3889,6 @@ 'count' => 1, 'path' => __DIR__ . '/src/PendingReason_Item.php', ]; -$ignoreErrors[] = [ - // identifier: greater.alwaysTrue - 'message' => '#^Comparison operation "\\>" between int\\<1, max\\> and 0 is always true\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/src/Peripheral.php', -]; $ignoreErrors[] = [ // identifier: instanceof.alwaysFalse 'message' => '#^Instanceof between static\\(Peripheral\\) and PDU will always evaluate to false\\.$#', @@ -3955,12 +3919,6 @@ 'count' => 1, 'path' => __DIR__ . '/src/Peripheral.php', ]; -$ignoreErrors[] = [ - // identifier: greater.alwaysTrue - 'message' => '#^Comparison operation "\\>" between int\\<1, max\\> and 0 is always true\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/src/Phone.php', -]; $ignoreErrors[] = [ // identifier: identical.alwaysFalse 'message' => '#^Strict comparison using \\=\\=\\= between array and false will always evaluate to false\\.$#', @@ -4069,12 +4027,6 @@ 'count' => 2, 'path' => __DIR__ . '/src/Plugin.php', ]; -$ignoreErrors[] = [ - // identifier: greater.alwaysTrue - 'message' => '#^Comparison operation "\\>" between int\\<1, max\\> and 0 is always true\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/src/Printer.php', -]; $ignoreErrors[] = [ // identifier: parameter.notFound 'message' => '#^PHPDoc tag @param references unknown parameter\\: \\$printer$#', @@ -4225,12 +4177,6 @@ 'count' => 1, 'path' => __DIR__ . '/src/Rack.php', ]; -$ignoreErrors[] = [ - // identifier: greater.alwaysTrue - 'message' => '#^Comparison operation "\\>" between int\\<1, max\\> and 0 is always true\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/src/RefusedEquipment.php', -]; $ignoreErrors[] = [ // identifier: method.notFound 'message' => '#^Call to an undefined method Sabre\\\\VObject\\\\Document\\:\\:getBaseComponent\\(\\)\\.$#', @@ -4783,12 +4729,6 @@ 'count' => 1, 'path' => __DIR__ . '/src/Toolbox.php', ]; -$ignoreErrors[] = [ - // identifier: greater.alwaysTrue - 'message' => '#^Comparison operation "\\>" between int\\<1, max\\> and 0 is always true\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/src/Unmanaged.php', -]; $ignoreErrors[] = [ // identifier: identical.alwaysFalse 'message' => '#^Strict comparison using \\=\\=\\= between array and false will always evaluate to false\\.$#', diff --git a/composer.lock b/composer.lock index b8dad9b3bd2..09a46c0e2f2 100644 --- a/composer.lock +++ b/composer.lock @@ -830,16 +830,16 @@ }, { "name": "glpi-project/inventory_format", - "version": "1.1.34", + "version": "1.1.35", "source": { "type": "git", "url": "https://github.com/glpi-project/inventory_format.git", - "reference": "3241f9ea5182183af369993fce3e1e34b3916771" + "reference": "0a58e67640cc396aed64924a533c08ee2da30924" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/glpi-project/inventory_format/zipball/3241f9ea5182183af369993fce3e1e34b3916771", - "reference": "3241f9ea5182183af369993fce3e1e34b3916771", + "url": "https://api.github.com/repos/glpi-project/inventory_format/zipball/0a58e67640cc396aed64924a533c08ee2da30924", + "reference": "0a58e67640cc396aed64924a533c08ee2da30924", "shasum": "" }, "require": { @@ -849,16 +849,16 @@ "ext-libxml": "*", "ext-simplexml": "*", "php": ">=7.4", - "seld/jsonlint": "^1.10", + "seld/jsonlint": "^1.11", "swaggest/json-schema": "^0.12.42", - "symfony/polyfill-php81": "^1.28" + "symfony/polyfill-php81": "^1.30" }, "require-dev": { - "phpstan/extension-installer": "^1.3", - "phpstan/phpstan": "^1.10", - "phpstan/phpstan-deprecation-rules": "^1.1", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^1.12", + "phpstan/phpstan-deprecation-rules": "^1.2", "phpunit/phpunit": "^9.6", - "squizlabs/php_codesniffer": "^3.8" + "squizlabs/php_codesniffer": "^3.10" }, "bin": [ "bin/convert", @@ -898,7 +898,7 @@ "issues": "https://github.com/glpi-project/inventory_format/issues", "source": "https://github.com/glpi-project/inventory_format" }, - "time": "2024-02-08T13:22:54+00:00" + "time": "2024-09-11T10:16:40+00:00" }, { "name": "guzzlehttp/guzzle", @@ -5379,23 +5379,23 @@ }, { "name": "seld/jsonlint", - "version": "1.10.2", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "9bb7db07b5d66d90f6ebf542f09fc67d800e5259" + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/9bb7db07b5d66d90f6ebf542f09fc67d800e5259", - "reference": "9bb7db07b5d66d90f6ebf542f09fc67d800e5259", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/1748aaf847fc731cfad7725aec413ee46f0cc3a2", + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2", "shasum": "" }, "require": { "php": "^5.3 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^1.5", + "phpstan/phpstan": "^1.11", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^8.5.13" }, "bin": [ @@ -5427,7 +5427,7 @@ ], "support": { "issues": "https://github.com/Seldaek/jsonlint/issues", - "source": "https://github.com/Seldaek/jsonlint/tree/1.10.2" + "source": "https://github.com/Seldaek/jsonlint/tree/1.11.0" }, "funding": [ { @@ -5439,7 +5439,7 @@ "type": "tidelift" } ], - "time": "2024-02-07T12:57:50+00:00" + "time": "2024-07-11T14:55:45+00:00" }, { "name": "simplepie/simplepie", @@ -5519,16 +5519,16 @@ }, { "name": "swaggest/json-diff", - "version": "v3.10.5", + "version": "v3.11.0", "source": { "type": "git", "url": "https://github.com/swaggest/json-diff.git", - "reference": "17bfc66b330f46e12a7e574133497a290cd79ba5" + "reference": "c55d38a3cb372753b5d5ee4c9b7d8470e486e6a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swaggest/json-diff/zipball/17bfc66b330f46e12a7e574133497a290cd79ba5", - "reference": "17bfc66b330f46e12a7e574133497a290cd79ba5", + "url": "https://api.github.com/repos/swaggest/json-diff/zipball/c55d38a3cb372753b5d5ee4c9b7d8470e486e6a5", + "reference": "c55d38a3cb372753b5d5ee4c9b7d8470e486e6a5", "shasum": "" }, "require": { @@ -5556,9 +5556,9 @@ "description": "JSON diff/rearrange/patch/pointer library for PHP", "support": { "issues": "https://github.com/swaggest/json-diff/issues", - "source": "https://github.com/swaggest/json-diff/tree/v3.10.5" + "source": "https://github.com/swaggest/json-diff/tree/v3.11.0" }, - "time": "2023-11-17T11:12:46+00:00" + "time": "2024-07-02T11:32:10+00:00" }, { "name": "swaggest/json-schema", @@ -7327,20 +7327,20 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.30.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c" + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c", - "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -7387,7 +7387,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" }, "funding": [ { @@ -7403,7 +7403,7 @@ "type": "tidelift" } ], - "time": "2024-06-19T12:30:46+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php83", diff --git a/inc/relation.constant.php b/inc/relation.constant.php index 50dae772e85..ab5d86c1be7 100644 --- a/inc/relation.constant.php +++ b/inc/relation.constant.php @@ -137,6 +137,7 @@ 'glpi_printers' => 'autoupdatesystems_id', 'glpi_refusedequipments' => 'autoupdatesystems_id', 'glpi_unmanageds' => 'autoupdatesystems_id', + 'glpi_assets_assets' => 'autoupdatesystems_id', ], 'glpi_budgets' => [ diff --git a/install/migrations/update_10.0.x_to_11.0.0/assets.php b/install/migrations/update_10.0.x_to_11.0.0/assets.php index 7028fa55bdd..d82f3c9015c 100644 --- a/install/migrations/update_10.0.x_to_11.0.0/assets.php +++ b/install/migrations/update_10.0.x_to_11.0.0/assets.php @@ -80,6 +80,7 @@ `assets_assetmodels_id` int {$default_key_sign} NOT NULL DEFAULT '0', `assets_assettypes_id` int {$default_key_sign} NOT NULL DEFAULT '0', `name` varchar(255) DEFAULT NULL, + `uuid` varchar(255) DEFAULT NULL, `comment` text, `serial` varchar(255) DEFAULT NULL, `otherserial` varchar(255) DEFAULT NULL, @@ -94,14 +95,18 @@ `is_recursive` tinyint NOT NULL DEFAULT '0', `is_deleted` tinyint NOT NULL DEFAULT '0', `is_template` tinyint NOT NULL DEFAULT '0', + `is_dynamic` tinyint NOT NULL DEFAULT '0', `template_name` varchar(255) DEFAULT NULL, + `autoupdatesystems_id` int unsigned NOT NULL DEFAULT '0', `date_creation` timestamp NULL DEFAULT NULL, `date_mod` timestamp NULL DEFAULT NULL, + `last_inventory_update` timestamp NULL DEFAULT NULL, PRIMARY KEY (`id`), KEY `assets_assetdefinitions_id` (`assets_assetdefinitions_id`), KEY `assets_assetmodels_id` (`assets_assetmodels_id`), KEY `assets_assettypes_id` (`assets_assettypes_id`), KEY `name` (`name`), + KEY `uuid` (`uuid`), KEY `users_id` (`users_id`), KEY `users_id_tech` (`users_id_tech`), KEY `locations_id` (`locations_id`), @@ -111,6 +116,8 @@ KEY `is_recursive` (`is_recursive`), KEY `is_deleted` (`is_deleted`), KEY `is_template` (`is_template`), + KEY `is_dynamic` (`is_dynamic`), + KEY `autoupdatesystems_id` (`autoupdatesystems_id`), KEY `date_creation` (`date_creation`), KEY `date_mod` (`date_mod`) ) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC; @@ -123,11 +130,18 @@ $migration->addKey('glpi_assets_assets', 'assets_assettypes_id'); $migration->addField('glpi_assets_assets', 'is_template', 'bool'); $migration->addKey('glpi_assets_assets', 'is_template'); + $migration->addField('glpi_assets_assets', 'is_dynamic', 'bool'); + $migration->addKey('glpi_assets_assets', 'is_dynamic'); $migration->addField('glpi_assets_assets', 'template_name', 'string'); $migration->dropKey('glpi_assets_assets', 'groups_id'); $migration->dropField('glpi_assets_assets', 'groups_id'); $migration->dropKey('glpi_assets_assets', 'groups_id_tech'); $migration->dropField('glpi_assets_assets', 'groups_id_tech'); + $migration->addField('glpi_assets_assets', 'uuid', 'string'); + $migration->addKey('glpi_assets_assets', 'uuid'); + $migration->addField('glpi_assets_assets', 'autoupdatesystems_id', 'fkey'); + $migration->addKey('glpi_assets_assets', 'autoupdatesystems_id'); + $migration->addField('glpi_assets_assets', 'last_inventory_update', 'timestamp'); } if (!$DB->tableExists('glpi_assets_assetmodels')) { diff --git a/install/mysql/glpi-empty.sql b/install/mysql/glpi-empty.sql index 09fc9ae0816..34cd492c399 100644 --- a/install/mysql/glpi-empty.sql +++ b/install/mysql/glpi-empty.sql @@ -9848,6 +9848,7 @@ CREATE TABLE `glpi_assets_assets` ( `assets_assetmodels_id` int unsigned NOT NULL DEFAULT '0', `assets_assettypes_id` int unsigned NOT NULL DEFAULT '0', `name` varchar(255) DEFAULT NULL, + `uuid` varchar(255) DEFAULT NULL, `comment` text, `serial` varchar(255) DEFAULT NULL, `otherserial` varchar(255) DEFAULT NULL, @@ -9862,14 +9863,18 @@ CREATE TABLE `glpi_assets_assets` ( `is_recursive` tinyint NOT NULL DEFAULT '0', `is_deleted` tinyint NOT NULL DEFAULT '0', `is_template` tinyint NOT NULL DEFAULT '0', + `is_dynamic` tinyint NOT NULL DEFAULT '0', `template_name` varchar(255) DEFAULT NULL, + `autoupdatesystems_id` int unsigned NOT NULL DEFAULT '0', `date_creation` timestamp NULL DEFAULT NULL, `date_mod` timestamp NULL DEFAULT NULL, + `last_inventory_update` timestamp NULL DEFAULT NULL, PRIMARY KEY (`id`), KEY `assets_assetdefinitions_id` (`assets_assetdefinitions_id`), KEY `assets_assetmodels_id` (`assets_assetmodels_id`), KEY `assets_assettypes_id` (`assets_assettypes_id`), KEY `name` (`name`), + KEY `uuid` (`uuid`), KEY `users_id` (`users_id`), KEY `users_id_tech` (`users_id_tech`), KEY `locations_id` (`locations_id`), @@ -9879,6 +9884,8 @@ CREATE TABLE `glpi_assets_assets` ( KEY `is_recursive` (`is_recursive`), KEY `is_deleted` (`is_deleted`), KEY `is_template` (`is_template`), + KEY `is_dynamic` (`is_dynamic`), + KEY `autoupdatesystems_id` (`autoupdatesystems_id`), KEY `date_creation` (`date_creation`), KEY `date_mod` (`date_mod`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC; diff --git a/phpunit/functional/Glpi/Inventory/Assets/ComputerTest.php b/phpunit/functional/Glpi/Inventory/Assets/ComputerTest.php index 76b47f8fad7..4fece379855 100644 --- a/phpunit/functional/Glpi/Inventory/Assets/ComputerTest.php +++ b/phpunit/functional/Glpi/Inventory/Assets/ComputerTest.php @@ -581,6 +581,7 @@ public function testHandle() $json = json_decode($json_str); $computer = new \Computer(); + $conf = new \Glpi\Inventory\Conf(); $data = (array)$json->content; $inventory = new \Glpi\Inventory\Inventory(); @@ -590,7 +591,7 @@ public function testHandle() $this->assertGreaterThan(0, $agent->handleAgent($inventory->extractMetadata())); $main = new \Glpi\Inventory\Asset\Computer($computer, $json); - $main->setAgent($agent)->setExtraData($data); + $main->setAgent($agent)->setExtraData($data)->checkConf($conf); $result = $main->prepare(); $this->assertCount(1, $result); diff --git a/phpunit/functional/Glpi/Inventory/Assets/ControllerTest.php b/phpunit/functional/Glpi/Inventory/Assets/ControllerTest.php index ab30863338d..4c3038848ff 100644 --- a/phpunit/functional/Glpi/Inventory/Assets/ControllerTest.php +++ b/phpunit/functional/Glpi/Inventory/Assets/ControllerTest.php @@ -212,11 +212,13 @@ public function testInventoryUpdate() 'itemtype' => 'Computer', 'devicecontrols_id' => $controller_1_id ]); + $this->assertGreaterThan(0, $item_controller_1_id); $manufacturer = new \Manufacturer(); $manufacturers_id = $manufacturer->add([ 'name' => 'Samsung Electronics Co Ltd' ]); + $this->assertGreaterThan(0, $manufacturers_id); $controller_2_id = $device_control->add([ 'designation' => 'NVMe SSD Controller SM951/PM951', @@ -252,26 +254,26 @@ public function testInventoryUpdate() $this->assertEquals(0, $controller['is_dynamic']); } - //computer inventory knows only "Xeon" and "NVMe SSD" controllers + //computer inventory knows only "Xeon" and "NVMe SSD" controllers $this->doInventory($xml_source, true); - //we still have 3 controllers + //we still have 3 controllers $controllers = $device_control->find(); $this->assertCount(3, $controllers); - //we still have 3 controllers items linked to the computer + //we still have 3 controllers items linked to the computer $controllers = $item_control->find(['itemtype' => 'Computer', 'items_id' => $computers_id]); $this->assertCount(3, $controllers); - //controllers present in the inventory source are now dynamic + //controllers present in the inventory source are now dynamic $controllers = $item_control->find(['itemtype' => 'Computer', 'items_id' => $computers_id, 'is_dynamic' => 1]); $this->assertCount(2, $controllers); - //controller not present in the inventory is still not dynamic + //controller not present in the inventory is still not dynamic $controllers = $item_control->find(['itemtype' => 'Computer', 'items_id' => $computers_id, 'is_dynamic' => 0]); $this->assertCount(1, $controllers); - //Redo inventory, but with removed "NVMe SSD" controller + //Redo inventory, but with removed "NVMe SSD" controller $xml_source = " diff --git a/phpunit/functional/Glpi/Inventory/GenericAssetInventoryTest.php b/phpunit/functional/Glpi/Inventory/GenericAssetInventoryTest.php new file mode 100644 index 00000000000..3e134e1ffd8 --- /dev/null +++ b/phpunit/functional/Glpi/Inventory/GenericAssetInventoryTest.php @@ -0,0 +1,1980 @@ +. + * + * --------------------------------------------------------------------- + */ + +namespace tests\units\Glpi\Inventory; + +use InventoryTestCase; + +class GenericAssetInventoryTest extends InventoryTestCase +{ + /** + * Inventory a generic smartphone asset + * + * @param array $capacities Capacities to activate + * + * @return \Glpi\Asset\Asset + */ + private function inventorySmartphone(array $capacities = []): \Glpi\Asset\Asset + { + /** @var \DBmysql $DB */ + global $DB; + + //create Smartphone generic asset + $definition = $this->initAssetDefinition( + system_name: 'Smartphone' . $this->getUniqueString(), + capacities: array_merge( + $capacities, + [ + \Glpi\Asset\Capacity\IsInventoriableCapacity::class + ] + ) + ); + $classname = $definition->getAssetClassName(); + + //we take a standard phone inventory and just change itemtype to Smartphone + $json = json_decode(file_get_contents(self::INV_FIXTURES . 'phone_1.json')); + $json->itemtype = $classname; + $inventory = $this->doInventory($json); + + //check inventory metadata + $metadata = $inventory->getMetadata(); + $this->assertCount(5, $metadata); + $this->assertSame('Mi9TPro-TéléphoneM-2019-12-18-14-30-16', $metadata['deviceid']); + $this->assertSame('example-app-java', $metadata['version']); + $this->assertSame($classname, $metadata['itemtype']); + $this->assertNull($metadata['port']); + $this->assertSame('inventory', $metadata['action']); + + //check created agent + $agenttype = $DB->request(['FROM' => \AgentType::getTable(), 'WHERE' => ['name' => 'Core']])->current(); + $agents = $DB->request(['FROM' => \Agent::getTable()]); + $this->assertCount(1, $agents); + $agent = $agents->current(); + $this->assertIsArray($agent); + $this->assertSame('Mi9TPro-TéléphoneM-2019-12-18-14-30-16', $agent['deviceid']); + $this->assertSame('Mi9TPro-TéléphoneM-2019-12-18-14-30-16', $agent['name']); + $this->assertSame($classname, $agent['itemtype']); + $this->assertSame($agenttype['id'], $agent['agenttypes_id']); + $this->assertGreaterThan(0, $agent['items_id']); + + //check matchedlogs + $mlogs = new \RuleMatchedLog(); + $found = $mlogs->find(); + $this->assertCount(1, $found); + + $criteria = [ + 'FROM' => \RuleMatchedLog::getTable(), + 'LEFT JOIN' => [ + \Rule::getTable() => [ + 'ON' => [ + \RuleMatchedLog::getTable() => 'rules_id', + \Rule::getTable() => 'id' + ] + ] + ], + 'WHERE' => ['itemtype' => $classname] + ]; + + $iterator = $DB->request($criteria); + $this->assertCount(1, $iterator); + //$this->assertSame('Assert import (by serial + uuid)', $iterator->current()['name']); + $this->assertSame('Global import (by serial)', $iterator->current()['name']); + $this->assertSame(\Glpi\Inventory\Request::INVENT_QUERY, $iterator->current()['method']); + + //get models, manufacturer, ... + $autoupdatesystems = $DB->request(['FROM' => \AutoupdateSystem::getTable(), 'WHERE' => ['name' => 'GLPI Native Inventory']])->current(); + $this->assertIsArray($autoupdatesystems); + $autoupdatesystems_id = $autoupdatesystems['id']; + + $cmodels = $DB->request(['FROM' => $definition->getAssetModelClassName()::getTable(), 'WHERE' => ['name' => 'Mi 9T Pro']])->current(); + $this->assertIsArray($cmodels); + $models_id = $cmodels['id']; + + $ctypes = $DB->request(['FROM' => $definition->getAssetTypeClassName()::getTable(), 'WHERE' => ['name' => 'Mi 9T Pro']])->current(); + $this->assertIsArray($ctypes); + $types_id = $ctypes['id']; + + $cmanuf = $DB->request(['FROM' => \Manufacturer::getTable(), 'WHERE' => ['name' => 'Xiaomi']])->current(); + $this->assertIsArray($cmanuf); + $manufacturers_id = $cmanuf['id']; + + //check created asset + $assets_id = $inventory->getAgent()->fields['items_id']; + $this->assertGreaterThan(0, $assets_id); + $asset = new $classname(); + $this->assertTrue($asset->getFromDB($assets_id)); + + $expected = [ + 'id' => $assets_id, + 'entities_id' => 0, + 'name' => 'Mi9TPro-TéléphoneM', + 'date_mod' => $asset->fields['date_mod'], + 'contact' => 'builder', + 'contact_num' => null, + 'users_id_tech' => 0, + 'comment' => null, + 'serial' => 'af8d8fcfa6fa4794', + 'otherserial' => 'release-keys', + 'locations_id' => 0, + 'assets_assetdefinitions_id' => $definition->getID(), + 'assets_assettypes_id' => $types_id, + 'assets_assetmodels_id' => $models_id, + 'manufacturers_id' => $manufacturers_id, + 'is_deleted' => 0, + 'is_template' => 0, + 'template_name' => null, + 'users_id' => 0, + 'states_id' => 0, + 'is_dynamic' => 1, + 'autoupdatesystems_id' => $autoupdatesystems_id, + 'uuid' => 'af8d3fcfa6fe4784', + 'date_creation' => $asset->fields['date_creation'], + 'is_recursive' => 0, + 'last_inventory_update' => $asset->fields['last_inventory_update'], + 'groups_id' => [], + 'groups_id_tech' => [], + ]; + $this->assertIsArray($asset->fields); + ksort($expected); + ksort($asset->fields); + $this->assertSame($expected, $asset->fields); + + return $asset; + } + + /** + * Test basic Generic Asset inventory + * + * @return void + */ + public function testImportSmartphone(): void + { + global $DB; + + //create Smartphone generic asset + $asset = $this->inventorySmartphone(); + $classname = $asset::class; + $assets_id = $asset->getID(); + + //operating system + $ios = new \Item_OperatingSystem(); + $iterator = $ios->getFromItem($asset); + //No OS capacity, no OS :) + $this->assertCount(0, $iterator); + + //remote management + $mgmt = new \Item_RemoteManagement(); + $iterator = $mgmt->getFromItem($asset); + $this->assertCount(0, $iterator); + + //volumes + $idisks = new \Item_Disk(); + $iterator = $idisks->getFromItem($asset); + //No disk capacity, no disk :) + $this->assertCount(0, $iterator); + + //check network ports + $iterator = $DB->request([ + 'FROM' => \NetworkPort::getTable(), + 'WHERE' => [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + ], + ]); + $this->assertCount(0, $iterator); + + //check for components + $components = []; + $this->assertCount(0, \Item_Devices::getItemAffinities($classname)); + + //software + $isoft = new \Item_SoftwareVersion(); + $iterator = $isoft->getFromItem($asset); + //No software capacity, no software :) + $this->assertCount(0, $iterator); + } + + /** + * Test Generic Asset inventory with OS + * + * @return void + */ + public function testImportSmartphoneWOS() + { + //create Smartphone generic asset + $asset = $this->inventorySmartphone([\Glpi\Asset\Capacity\HasOperatingSystemCapacity::class]); + + //operating system + $ios = new \Item_OperatingSystem(); + $iterator = $ios->getFromItem($asset); + //OS capacity enabled + $this->assertCount(1, $iterator); + $record = $iterator->current(); + + $expected = [ + 'assocID' => $record['assocID'], + 'name' => 'Q Android 10.0 api 29', + 'version' => '29', + 'architecture' => 'arm64-v8a,armeabi-v7a,armeabi', + 'servicepack' => null, + ]; + $this->assertSame($expected, $record); + } + + /** + * Test Generic Asset inventory with Volumes + * + * @return void + */ + public function testImportSmartphoneWVolumes() + { + //create Smartphone generic asset + $asset = $this->inventorySmartphone([\Glpi\Asset\Capacity\HasVolumesCapacity::class]); + $classname = $asset::class; + $assets_id = $asset->getID(); + + //volumes + $idisks = new \Item_Disk(); + $iterator = $idisks->getFromItem($asset); + //Disk capacity activated + $this->assertCount(4, $iterator); + + $expecteds = [ + [ + 'totalsize' => 3471, + 'freesize' => 23, + ], [ + 'totalsize' => 51913, + 'freesize' => 33722, + ], [ + 'totalsize' => 51913, + 'freesize' => 33722, + ], [ + 'totalsize' => 51913, + 'freesize' => 33722, + ] + ]; + + $i = 0; + foreach ($iterator as $volume) { + unset($volume['id']); + unset($volume['date_mod']); + unset($volume['date_creation']); + $expected = $expecteds[$i]; + $expected = $expected + [ + 'fsname' => null, + 'name' => null, + 'device' => null, + 'mountpoint' => null, + 'filesystems_id' => 0, + 'encryption_status' => 0, + 'encryption_tool' => null, + 'encryption_algorithm' => null, + 'encryption_type' => null, + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'entities_id' => 0, + 'is_deleted' => 0, + 'is_dynamic' => 1 + ]; + ksort($volume); + ksort($expected); + $this->assertIsArray($volume); + $this->assertEquals($expected, $volume); + ++$i; + } + } + + /** + * Test Generic Asset inventory with all capacities enabled + * + * @return void + */ + public function testImportSmartphoneAllCapacities(): void + { + global $DB; + + //create Smartphone generic asset + $asset = $this->inventorySmartphone(array_keys(\Glpi\Asset\AssetDefinitionManager::getInstance()->getAvailableCapacities())); + $classname = $asset::class; + $assets_id = $asset->getID(); + + //operating system + $ios = new \Item_OperatingSystem(); + $iterator = $ios->getFromItem($asset); + $this->assertCount(1, $iterator); + $record = $iterator->current(); + + $expected = [ + 'assocID' => $record['assocID'], + 'name' => 'Q Android 10.0 api 29', + 'version' => '29', + 'architecture' => 'arm64-v8a,armeabi-v7a,armeabi', + 'servicepack' => null, + ]; + $this->assertSame($expected, $record); + + //remote management + $mgmt = new \Item_RemoteManagement(); + $iterator = $mgmt->getFromItem($asset); + $this->assertCount(0, $iterator); + + //volumes + $idisks = new \Item_Disk(); + $iterator = $idisks->getFromItem($asset); + $this->assertCount(4, $iterator); + + $expecteds = [ + [ + 'totalsize' => 3471, + 'freesize' => 23, + ], [ + 'totalsize' => 51913, + 'freesize' => 33722, + ], [ + 'totalsize' => 51913, + 'freesize' => 33722, + ], [ + 'totalsize' => 51913, + 'freesize' => 33722, + ] + ]; + + $i = 0; + foreach ($iterator as $volume) { + unset($volume['id']); + unset($volume['date_mod']); + unset($volume['date_creation']); + $expected = $expecteds[$i]; + $expected = $expected + [ + 'fsname' => null, + 'name' => null, + 'device' => null, + 'mountpoint' => null, + 'filesystems_id' => 0, + 'encryption_status' => 0, + 'encryption_tool' => null, + 'encryption_algorithm' => null, + 'encryption_type' => null, + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'entities_id' => 0, + 'is_deleted' => 0, + 'is_dynamic' => 1 + ]; + ksort($volume); + ksort($expected); + $this->assertIsArray($volume); + $this->assertEquals($expected, $volume); + ++$i; + } + + //check network ports + $iterator = $DB->request([ + 'FROM' => \NetworkPort::getTable(), + 'WHERE' => [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + ], + ]); + $this->assertCount(1, $iterator); + + $expecteds = [ + [ + 'logical_number' => 1, + 'name' => 'No description found', + 'instantiation_type' => 'NetworkPortWifi', + 'mac' => 'e0:dc:ff:ed:09:59', + 'ifstatus' => '1', + 'ifinternalstatus' => '1', + ] + ]; + + $ips = [ + 'No description found' => [ + 'v4' => '172.28.214.132', + ] + ]; + + $i = 0; + $netport = new \NetworkPort(); + foreach ($iterator as $port) { + $ports_id = $port['id']; + $this->assertTrue($netport->getFromDB($ports_id)); + $instantiation = $netport->getInstantiation(); + if ($port['instantiation_type'] === null) { + $this->assertFalse($instantiation); + } else { + $this->assertInstanceOf($port['instantiation_type'], $instantiation); + } + + unset($port['id']); + unset($port['date_creation']); + unset($port['date_mod']); + unset($port['comment']); + + $expected = $expecteds[$i]; + $expected = $expected + [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'entities_id' => 0, + 'is_recursive' => 0, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'ifmtu' => 0, + 'ifspeed' => 0, + 'ifinternalstatus' => null, + 'ifconnectionstatus' => 0, + 'iflastchange' => null, + 'ifinbytes' => 0, + 'ifinerrors' => 0, + 'ifoutbytes' => 0, + 'ifouterrors' => 0, + 'ifstatus' => null, + 'ifdescr' => null, + 'ifalias' => null, + 'portduplex' => null, + 'trunk' => 0, + 'lastup' => null + ]; + + $this->assertIsArray($port); + $this->assertEquals($expected, $port); + ++$i; + + //check for ips + $ip_iterator = $DB->request([ + 'SELECT' => [ + \IPAddress::getTable() . '.name', + \IPAddress::getTable() . '.version' + ], + 'FROM' => \IPAddress::getTable(), + 'INNER JOIN' => [ + \NetworkName::getTable() => [ + 'ON' => [ + \IPAddress::getTable() => 'items_id', + \NetworkName::getTable() => 'id', [ + 'AND' => [\IPAddress::getTable() . '.itemtype' => \NetworkName::getType()] + ] + ] + ] + ], + 'WHERE' => [ + \NetworkName::getTable() . '.itemtype' => \NetworkPort::getType(), + \NetworkName::getTable() . '.items_id' => $ports_id + ] + ]); + + $this->assertCount(count($ips[$port['name']] ?? []), $ip_iterator); + if (isset($ips[$port['name']])) { + //FIXME: missing all ipv6 :( + $ip = $ip_iterator->current(); + $this->assertSame(4, (int)$ip['version']); + $this->assertSame($ips[$port['name']]['v4'], $ip['name']); + } + } + + //check for components + $components = []; + foreach (\Item_Devices::getItemAffinities('Computer') as $link_type) { + $link = getItemForItemtype($link_type); + $iterator = $DB->request($link->getTableGroupCriteria($asset)); + $components[$link_type] = []; + + foreach ($iterator as $row) { + $lid = $row['id']; + unset($row['id']); + $components[$link_type][$lid] = $row; + } + } + + $expecteds = [ + 'Item_DeviceMotherboard' => 0, + 'Item_DeviceFirmware' => 1, + 'Item_DeviceProcessor' => 1, + 'Item_DeviceMemory' => 1, + 'Item_DeviceHardDrive' => 0, + 'Item_DeviceNetworkCard' => 1, + 'Item_DeviceDrive' => 0, + 'Item_DeviceBattery' => 1, + 'Item_DeviceGraphicCard' => 0, + 'Item_DeviceSoundCard' => 0, + 'Item_DeviceControl' => 0, + 'Item_DevicePci' => 0, + 'Item_DeviceCase' => 0, + 'Item_DevicePowerSupply' => 0, + 'Item_DeviceGeneric' => 0, + 'Item_DeviceSimcard' => 1, + 'Item_DeviceSensor' => 48, + 'Item_DeviceCamera' => 2 + ]; + + foreach ($expecteds as $type => $count) { + $this->assertCount($count, $components[$type], count($components[$type]) . ' ' . $type); + } + + $expecteds = [ + 'Item_DeviceMotherboard' => [], + 'Item_DeviceFirmware' => [ + [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicefirmwares_id' => 104, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ] + ], + 'Item_DeviceProcessor' => [ + [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'deviceprocessors_id' => 3060400, + 'frequency' => 1785, + 'serial' => null, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'nbcores' => 8, + 'nbthreads' => 8, + 'entities_id' => 0, + 'is_recursive' => 0, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], + ], + 'Item_DeviceMemory' => [ + [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicememories_id' => 4, + 'size' => 5523, + 'serial' => null, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0 + ], + ], + 'Item_DeviceHardDrive' => [], + 'Item_DeviceNetworkCard' => [ + [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicenetworkcards_id' => 66, + 'mac' => 'e0:dc:ff:ed:09:59', + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ] + ], + 'Item_DeviceDrive' => [], + 'Item_DeviceBattery' => [ + [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicebatteries_id' => 70, + 'manufacturing_date' => null, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + 'real_capacity' => 0 + ], + ], + 'Item_DeviceGraphicCard' => [], + 'Item_DeviceSoundCard' => [], + 'Item_DeviceControl' => [], + 'Item_DevicePci' => [], + 'Item_DeviceCase' => [], + 'Item_DevicePowerSupply' => [], + 'Item_DeviceGeneric' => [], + 'Item_DeviceSimcard' => [ + [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicesimcards_id' => 68, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => '8933150319050352521', + 'otherserial' => null, + 'states_id' => 0, + 'locations_id' => 0, + 'lines_id' => 0, + 'users_id' => 0, + 'users_id_tech' => 0, + 'pin' => '', + 'pin2' => '', + 'puk' => '', + 'puk2' => '', + 'msin' => '', + 'comment' => null, + ] + ], + 'Item_DeviceCamera' => [ + [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecameras_id' => 4, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecameras_id' => 4, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'locations_id' => 0, + 'states_id' => 0, + ] + ] + ]; + + foreach ($expecteds as $type => $expected) { + $component = array_values($components[$type]); + //hack to replace expected fkeys + foreach ($expected as $i => &$row) { + foreach (array_keys($row) as $key) { + if (isForeignKeyField($key)) { + $row[$key] = $component[$i][$key]; + } + } + } + $this->assertIsArray($component); + $this->assertEquals($expected, $component); + } + + //software + $isoft = new \Item_SoftwareVersion(); + $iterator = $isoft->getFromItem($asset); + $this->assertCount(4, $iterator); + + $expecteds = [ + [ + 'softname' => 'Boutique Amazon', + 'version' => '18.21.2.100', + 'dateinstall' => '2019-08-31', + ], [ + 'softname' => 'CameraTools', + 'version' => '1.0', + 'dateinstall' => '2008-12-31', + ], [ + 'softname' => 'Enregistreur d\'écran', + 'version' => '1.5.9', + 'dateinstall' => '2008-12-31', + ], [ + 'softname' => 'Q Android 10.0 api 29', + 'version' => '29', + 'dateinstall' => null, + ] + ]; + + $i = 0; + foreach ($iterator as $soft) { + $expected = $expecteds[$i]; + $this->assertEquals( + $expected, + [ + 'softname' => $soft['softname'], + 'version' => $soft['version'], + 'dateinstall' => $soft['dateinstall'] + ] + ); + ++$i; + } + } + + /** + * Inventory a generic smartphone asset + * + * @param array $capacities Capacities to activate + * + * @return \Glpi\Asset\Asset + */ + private function inventoryServer(array $capacities = []): \Glpi\Asset\Asset + { + /** @var \DBmysql $DB */ + global $DB; + + //create Server generic asset + $definition = $this->initAssetDefinition( + system_name: 'Server' . $this->getUniqueString(), + capacities: array_merge( + $capacities, + [ + \Glpi\Asset\Capacity\IsInventoriableCapacity::class + ] + ) + ); + $classname = $definition->getAssetClassName(); + + //we take a standard phone inventory and just change itemtype to Smartphone + $json = json_decode(file_get_contents(self::INV_FIXTURES . 'computer_1.json')); + $json->itemtype = $classname; + $inventory = $this->doInventory($json); + + //check inventory metadata + $metadata = $inventory->getMetadata(); + $this->assertCount(7, $metadata); + $this->assertSame('glpixps-2018-07-09-09-07-13', $metadata['deviceid']); + $this->assertSame('FusionInventory-Agent_v2.5.2-1.fc31', $metadata['version']); + $this->assertSame($classname, $metadata['itemtype']); + $this->assertNull($metadata['port']); + $this->assertSame('000005', $metadata['tag']); + $this->assertCount(10, $metadata['provider']); + + //check created agent + $agenttype = $DB->request(['FROM' => \AgentType::getTable(), 'WHERE' => ['name' => 'Core']])->current(); + $agents = $DB->request(['FROM' => \Agent::getTable()]); + $this->assertCount(1, $agents); + $agent = $agents->current(); + $this->assertIsArray($agent); + $this->assertSame('glpixps-2018-07-09-09-07-13', $agent['deviceid']); + $this->assertSame('glpixps-2018-07-09-09-07-13', $agent['name']); + $this->assertSame('2.5.2-1.fc31', $agent['version']); + $this->assertSame($classname, $agent['itemtype']); + $this->assertSame('000005', $agent['tag']); + $this->assertSame($agenttype['id'], $agent['agenttypes_id']); + $this->assertGreaterThan(0, $agent['items_id']); + + //check created asset + $assets_id = $inventory->getAgent()->fields['items_id']; + $this->assertGreaterThan(0, $assets_id); + $asset = new $classname(); + $this->assertTrue($asset->getFromDB($assets_id)); + + //get models, manufacturer, ... + $autoupdatesystems = $DB->request(['FROM' => \AutoupdateSystem::getTable(), 'WHERE' => ['name' => 'GLPI Native Inventory']])->current(); + $this->assertIsArray($autoupdatesystems); + $autoupdatesystems_id = $autoupdatesystems['id']; + + $cmodels = $DB->request(['FROM' => $definition->getAssetModelClassName()::getTable(), 'WHERE' => ['name' => 'XPS 13 9350']])->current(); + $this->assertIsArray($cmodels); + $models_id = $cmodels['id']; + + $ctypes = $DB->request(['FROM' => $definition->getAssetTypeClassName()::getTable(), 'WHERE' => ['name' => 'Laptop']])->current(); + $this->assertIsArray($ctypes); + $types_id = $ctypes['id']; + + $cmanuf = $DB->request(['FROM' => \Manufacturer::getTable(), 'WHERE' => ['name' => 'Dell Inc.']])->current(); + $this->assertIsArray($cmanuf); + $manufacturers_id = $cmanuf['id']; + + $expected = [ + 'id' => $assets_id, + 'entities_id' => 0, + 'name' => 'glpixps', + 'serial' => '640HP72', + 'otherserial' => null, + 'contact' => 'trasher/root', + 'contact_num' => null, + 'users_id_tech' => 0, + 'comment' => null, + 'date_mod' => $asset->fields['date_mod'], + 'autoupdatesystems_id' => $autoupdatesystems_id, + 'locations_id' => 0, + //'networks_id' => 0, + 'assets_assetdefinitions_id' => $definition->getID(), + 'assets_assettypes_id' => $types_id, + 'assets_assetmodels_id' => $models_id, + 'is_template' => 0, + 'template_name' => null, + 'manufacturers_id' => $manufacturers_id, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'users_id' => 0, + 'states_id' => 0, + //'ticket_tco' => '0.0000', + 'uuid' => '4c4c4544-0034-3010-8048-b6c04f503732', + 'date_creation' => $asset->fields['date_creation'], + 'is_recursive' => 0, + 'last_inventory_update' => $asset->fields['last_inventory_update'], + //'last_boot' => '2020-06-09 07:58:08', + 'groups_id' => [], + 'groups_id_tech' => [], + ]; + $this->assertIsArray($asset->fields); + ksort($expected); + ksort($asset->fields); + $this->assertSame($expected, $asset->fields); + + return $asset; + } + + /** + * Test basic Generic Asset inventory + * + * @return void + */ + public function testImportServer(): void + { + /** @var \DBmysql $DB */ + global $DB; + + //create Server generic asset + $asset = $this->inventoryServer(); + $classname = $asset::class; + $assets_id = $asset->getID(); + + //check matchedlogs + $mlogs = new \RuleMatchedLog(); + $found = $mlogs->find(); + $this->assertCount(1, $found); + + $criteria = [ + 'FROM' => \RuleMatchedLog::getTable(), + 'LEFT JOIN' => [ + \Rule::getTable() => [ + 'ON' => [ + \RuleMatchedLog::getTable() => 'rules_id', + \Rule::getTable() => 'id' + ] + ] + ], + 'WHERE' => [] + ]; + + $computer_criteria = $criteria; + $computer_criteria['WHERE'] = ['itemtype' => $classname]; + $iterator = $DB->request($computer_criteria); + $this->assertCount(1, $iterator); + //$this->assertSame('Computer import (by serial + uuid)', $iterator->current()['name']); + $this->assertSame('Global import (by serial)', $iterator->current()['name']); + $this->assertSame(\Glpi\Inventory\Request::INVENT_QUERY, $iterator->current()['method']); + + //operating system + $ios = new \Item_OperatingSystem(); + $iterator = $ios->getFromItem($asset); + $this->assertCount(0, $iterator); + + //remote management + $mgmt = new \Item_RemoteManagement(); + $iterator = $mgmt->getFromItem($asset); + $this->assertCount(0, $iterator); + + //connections + $connections = getAllDataFromTable( + \Glpi\Asset\Asset_PeripheralAsset::getTable(), + [ + 'itemtype_asset' => $classname, + 'items_id_asset' => $assets_id, + 'itemtype_peripheral' => 'Monitor', + ] + ); + $this->assertCount(0, $connections); + + //check network ports + $iterator = $DB->request([ + 'FROM' => \NetworkPort::getTable(), + 'WHERE' => [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + ], + ]); + $this->assertCount(0, $iterator); + + //check for components + $components = []; + $this->assertCount(0, \Item_Devices::getItemAffinities($classname)); + + //check printer + $connections = getAllDataFromTable( + \Glpi\Asset\Asset_PeripheralAsset::getTable(), + [ + 'itemtype_asset' => $classname, + 'items_id_asset' => $assets_id, + 'itemtype_peripheral' => 'Printer', + ] + ); + $this->assertCount(0, $connections); + + $idisks = new \Item_Disk(); + $iterator = $idisks->getFromItem($asset); + $this->assertCount(0, $iterator); + + $isoft = new \Item_SoftwareVersion(); + $iterator = $isoft->getFromItem($asset); + $this->assertCount(0, $iterator); + + $link = getItemForItemtype(\Item_DeviceBattery::class); + $iterator = $DB->request($link->getTableGroupCriteria($asset)); + $this->assertCount(0, $iterator); + } + + public function testImportServerWOS() + { + //create Server generic asset + $asset = $this->inventoryServer([\Glpi\Asset\Capacity\HasOperatingSystemCapacity::class]); + + //operating system + $ios = new \Item_OperatingSystem(); + $iterator = $ios->getFromItem($asset); + //OS capacity enabled + $this->assertCount(1, $iterator); + $record = $iterator->current(); + + $expected = [ + 'assocID' => $record['assocID'], + 'name' => 'Fedora 31 (Workstation Edition)', + 'version' => '31 (Workstation Edition)', + 'architecture' => 'x86_64', + 'servicepack' => null, + ]; + $this->assertSame($expected, $record); + } + + public function testImportServerAllCapacities(): void + { + /** @var \DBmysql $DB */ + global $DB; + + //create Server generic asset + $asset = $this->inventoryServer(array_keys(\Glpi\Asset\AssetDefinitionManager::getInstance()->getAvailableCapacities())); + $classname = $asset::class; + $assets_id = $asset->getID(); + + //check matchedlogs + $mlogs = new \RuleMatchedLog(); + $found = $mlogs->find(); + $this->assertCount(3, $found); + + $criteria = [ + 'FROM' => \RuleMatchedLog::getTable(), + 'LEFT JOIN' => [ + \Rule::getTable() => [ + 'ON' => [ + \RuleMatchedLog::getTable() => 'rules_id', + \Rule::getTable() => 'id' + ] + ] + ], + 'WHERE' => [] + ]; + + $monitor_criteria = $criteria; + $monitor_criteria['WHERE'] = ['itemtype' => \Monitor::getType()]; + $iterator = $DB->request($monitor_criteria); + $this->assertCount(1, $iterator); + $this->assertSame('Monitor import (by serial)', $iterator->current()['name']); + $this->assertSame(\Glpi\Inventory\Request::INVENT_QUERY, $iterator->current()['method']); + + $printer_criteria = $criteria; + $printer_criteria['WHERE'] = ['itemtype' => \Printer::getType()]; + $iterator = $DB->request($printer_criteria); + $this->assertCount(1, $iterator); + $this->assertSame('Printer import (by serial)', $iterator->current()['name']); + $this->assertSame(\Glpi\Inventory\Request::INVENT_QUERY, $iterator->current()['method']); + + $computer_criteria = $criteria; + $computer_criteria['WHERE'] = ['itemtype' => $classname]; + $iterator = $DB->request($computer_criteria); + $this->assertCount(1, $iterator); + //$this->assertSame('Computer import (by serial + uuid)', $iterator->current()['name']); + $this->assertSame('Global import (by serial)', $iterator->current()['name']); + $this->assertSame(\Glpi\Inventory\Request::INVENT_QUERY, $iterator->current()['method']); + + //operating system + $ios = new \Item_OperatingSystem(); + $iterator = $ios->getFromItem($asset); + $this->assertCount(1, $iterator); + $record = $iterator->current(); + $expected = [ + 'assocID' => $record['assocID'], + 'name' => 'Fedora 31 (Workstation Edition)', + 'version' => '31 (Workstation Edition)', + 'architecture' => 'x86_64', + 'servicepack' => null, + ]; + $this->assertIsArray($record); + $this->assertSame($expected, $record); + + //remote management + $mgmt = new \Item_RemoteManagement(); + $iterator = $mgmt->getFromItem($asset); + $this->assertCount(1, $iterator); + $remote = $iterator->current(); + unset($remote['id']); + $this->assertSame( + [ + 'itemtype' => $classname, + 'items_id' => $assets_id, + 'remoteid' => '123456789', + 'type' => 'teamviewer', + 'is_dynamic' => 1, + 'is_deleted' => 0 + ], + $remote + ); + + //connections + $connections = getAllDataFromTable( + \Glpi\Asset\Asset_PeripheralAsset::getTable(), + [ + 'itemtype_asset' => $classname, + 'items_id_asset' => $assets_id, + 'itemtype_peripheral' => 'Monitor', + ] + ); + $this->assertCount(1, $connections); + $connection = $connections[array_key_first($connections)]; + $monitor = new \Monitor(); + $this->assertTrue($monitor->getFromDB($connection['items_id_peripheral'])); + $monitor_fields = $monitor->fields; + unset($monitor_fields['date_mod'], $monitor_fields['date_creation']); + + $mmanuf = $DB->request(['FROM' => \Manufacturer::getTable(), 'WHERE' => ['name' => 'Sharp Corporation']])->current(); + $this->assertIsArray($mmanuf); + $manufacturers_id = $mmanuf['id']; + + $mmodel = $DB->request(['FROM' => \MonitorModel::getTable(), 'WHERE' => ['name' => 'DJCP6']])->current(); + $this->assertIsArray($mmodel); + $models_id = $mmodel['id']; + + $expected = [ + 'id' => $monitor_fields['id'], + 'entities_id' => 0, + 'name' => 'DJCP6', + 'contact' => 'trasher/root', + 'contact_num' => null, + 'users_id_tech' => 0, + 'comment' => null, + 'serial' => 'ABH55D', + 'otherserial' => null, + 'size' => '0.00', + 'have_micro' => 0, + 'have_speaker' => 0, + 'have_subd' => 0, + 'have_bnc' => 0, + 'have_dvi' => 0, + 'have_pivot' => 0, + 'have_hdmi' => 0, + 'have_displayport' => 0, + 'locations_id' => 0, + 'monitortypes_id' => 0, + 'monitormodels_id' => $models_id, + 'manufacturers_id' => $manufacturers_id, + 'is_global' => 0, + 'is_deleted' => 0, + 'is_template' => 0, + 'template_name' => null, + 'users_id' => 0, + 'states_id' => 0, + 'ticket_tco' => '0.0000', + 'is_dynamic' => 1, + 'autoupdatesystems_id' => 0, + 'uuid' => null, + 'is_recursive' => 0, + 'groups_id' => [], + 'groups_id_tech' => [], + ]; + $this->assertIsArray($monitor_fields); + $this->assertSame($expected, $monitor_fields); + + //check network ports + $iterator = $DB->request([ + 'FROM' => \NetworkPort::getTable(), + 'WHERE' => [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + ], + ]); + $this->assertCount(5, $iterator); + + $expecteds = [ + [ + 'logical_number' => 0, + 'name' => 'lo', + 'instantiation_type' => 'NetworkPortLocal', + 'mac' => '00:00:00:00:00:00', + 'ifinternalstatus' => '1', + ], [ + 'logical_number' => 1, + 'name' => 'enp57s0u1u4', + 'instantiation_type' => 'NetworkPortEthernet', + 'mac' => '00:e0:4c:68:01:db', + 'ifstatus' => '1', + 'ifinternalstatus' => '1', + ], [ + 'logical_number' => 1, + 'name' => 'wlp58s0', + 'instantiation_type' => 'NetworkPortWifi', + 'mac' => '44:85:00:2b:90:bc', + 'ifinternalstatus' => '1', + ], [ + 'logical_number' => 0, + 'name' => 'virbr0', + 'instantiation_type' => 'NetworkPortEthernet', + 'mac' => '52:54:00:fa:20:0e', + 'ifstatus' => '2', + 'ifinternalstatus' => '1', + ], [ + 'logical_number' => 0, + 'name' => 'virbr0-nic', + 'instantiation_type' => null, + 'mac' => '52:54:00:fa:20:0e', + 'ifstatus' => '2', + 'ifinternalstatus' => '2', + ] + ]; + + $ips = [ + 'lo' => [ + 'v4' => '127.0.0.1', + 'v6' => '::1' + ], + 'enp57s0u1u4' => [ + 'v4' => '192.168.1.142', + 'v6' => 'fe80::b283:4fa3:d3f2:96b1' + ], + 'wlp58s0' => [ + 'v4' => '192.168.1.118', + 'v6' => 'fe80::92a4:26c6:99dd:2d60' + ], + 'virbr0' => [ + 'v4' => '192.168.122.1' + ] + ]; + + $i = 0; + $netport = new \NetworkPort(); + foreach ($iterator as $port) { + $ports_id = $port['id']; + $this->assertTrue($netport->getFromDB($ports_id)); + $instantiation = $netport->getInstantiation(); + if ($port['instantiation_type'] === null) { + $this->assertFalse($instantiation); + } else { + $this->assertInstanceOf($port['instantiation_type'], $instantiation); + } + + unset($port['id']); + unset($port['date_creation']); + unset($port['date_mod']); + unset($port['comment']); + + $expected = $expecteds[$i]; + $expected = $expected + [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'entities_id' => 0, + 'is_recursive' => 0, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'ifmtu' => 0, + 'ifspeed' => 0, + 'ifinternalstatus' => null, + 'ifconnectionstatus' => 0, + 'iflastchange' => null, + 'ifinbytes' => 0, + 'ifinerrors' => 0, + 'ifoutbytes' => 0, + 'ifouterrors' => 0, + 'ifstatus' => null, + 'ifdescr' => null, + 'ifalias' => null, + 'portduplex' => null, + 'trunk' => 0, + 'lastup' => null + ]; + + $this->assertIsArray($port); + $this->assertEquals($expected, $port); + ++$i; + + //check for ips + $ip_iterator = $DB->request([ + 'SELECT' => [ + \IPAddress::getTable() . '.name', + \IPAddress::getTable() . '.version' + ], + 'FROM' => \IPAddress::getTable(), + 'INNER JOIN' => [ + \NetworkName::getTable() => [ + 'ON' => [ + \IPAddress::getTable() => 'items_id', + \NetworkName::getTable() => 'id', [ + 'AND' => [\IPAddress::getTable() . '.itemtype' => \NetworkName::getType()] + ] + ] + ] + ], + 'WHERE' => [ + \NetworkName::getTable() . '.itemtype' => \NetworkPort::getType(), + \NetworkName::getTable() . '.items_id' => $ports_id + ] + ]); + + $this->assertCount(count($ips[$port['name']] ?? []), $ip_iterator); + if (isset($ips[$port['name']])) { + //FIXME: missing all ipv6 :( + $ip = $ip_iterator->current(); + $this->assertSame(4, (int)$ip['version']); + $this->assertSame($ips[$port['name']]['v4'], $ip['name']); + } + } + + //check for components + $components = []; + $allcount = 0; + foreach (\Item_Devices::getItemAffinities($classname) as $link_type) { + $link = getItemForItemtype($link_type); + $iterator = $DB->request($link->getTableGroupCriteria($asset)); + $allcount += count($iterator); + $components[$link_type] = []; + + foreach ($iterator as $row) { + $lid = $row['id']; + unset($row['id']); + $components[$link_type][$lid] = $row; + } + } + + $expecteds = [ + 'Item_DeviceMotherboard' => 0, + 'Item_DeviceFirmware' => 1, + 'Item_DeviceProcessor' => 1, + 'Item_DeviceMemory' => 2, + 'Item_DeviceHardDrive' => 1, + 'Item_DeviceNetworkCard' => 0, + 'Item_DeviceDrive' => 0, + 'Item_DeviceBattery' => 1, + 'Item_DeviceGraphicCard' => 0, + 'Item_DeviceSoundCard' => 1, + 'Item_DeviceControl' => 25, + 'Item_DevicePci' => 0, + 'Item_DeviceCase' => 0, + 'Item_DevicePowerSupply' => 0, + 'Item_DeviceGeneric' => 0, + 'Item_DeviceSimcard' => 0, + 'Item_DeviceSensor' => 0, + ]; + + foreach ($expecteds as $type => $count) { + $this->assertSame( + $count, + count($components[$type]), + sprintf( + 'Expected %1$s %2$s, got %3$s', + $count, + $type, + count($components[$type]) + ) + ); + } + + $expecteds = [ + 'Item_DeviceMotherboard' => [], + 'Item_DeviceFirmware' => [ + [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicefirmwares_id' => 104, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ] + ], + 'Item_DeviceProcessor' => + [ + [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'deviceprocessors_id' => 3060400, + 'frequency' => 2300, + 'serial' => null, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'nbcores' => 2, + 'nbthreads' => 4, + 'entities_id' => 0, + 'is_recursive' => 0, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], + ], + 'Item_DeviceMemory' => + [ + [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicememories_id' => 104, + 'size' => 4096, + 'serial' => '12161217', + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'busID' => '1', + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicememories_id' => 104, + 'size' => 4096, + 'serial' => '12121212', + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'busID' => '2', + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], + ], + 'Item_DeviceHardDrive' => [ + [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'deviceharddrives_id' => 104, + 'capacity' => 256060, + 'serial' => 'S29NNXAH146409', + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], + ], + 'Item_DeviceNetworkCard' => [], + 'Item_DeviceDrive' => [], + // 'Item_DeviceBattery' is not tested here, see self::checkComputer1Batteries() + 'Item_DeviceGraphicCard' => [], + 'Item_DeviceSoundCard' => [ + [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicesoundcards_id' => 104, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], + ], + 'Item_DeviceControl' => [ + [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2246, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => 'xyz', + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2247, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2248, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2249, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2250, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2251, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2252, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2253, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2254, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2255, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2256, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2257, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2258, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2259, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2260, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2261, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2262, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2263, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2263, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2263, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2263, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2264, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2265, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2266, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicecontrols_id' => 2267, + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => null, + 'busID' => null, + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + ], + ], + 'Item_DevicePci' => [], + 'Item_DeviceCase' => [], + 'Item_DevicePowerSupply' => [], + 'Item_DeviceGeneric' => [], + 'Item_DeviceSimcard' => [], + 'Item_DeviceSensor' => [], + ]; + + foreach ($expecteds as $type => $expected) { + $component = array_values($components[$type]); + //hack to replace expected fkeys + foreach ($expected as $i => &$row) { + foreach (array_keys($row) as $key) { + if (isForeignKeyField($key)) { + $row[$key] = $component[$i][$key]; + } + } + } + $this->assertIsArray($component); + $this->assertSame($expected, $component); + } + + //check printer + $connections = getAllDataFromTable( + \Glpi\Asset\Asset_PeripheralAsset::getTable(), + [ + 'itemtype_asset' => $classname, + 'items_id_asset' => $assets_id, + 'itemtype_peripheral' => 'Printer', + ] + ); + $this->assertCount(1, $connections); + $connection = $connections[array_key_first($connections)]; + $printer = new \Printer(); + $this->assertTrue($printer->getFromDB($connection['items_id_peripheral'])); + $printer_fields = $printer->fields; + unset($printer_fields['date_mod'], $printer_fields['date_creation']); + + $expected = [ + 'id' => $printer_fields['id'], + 'entities_id' => 0, + 'is_recursive' => 0, + 'name' => 'Officejet_Pro_8600_34AF9E_', + 'contact' => 'trasher/root', + 'contact_num' => null, + 'users_id_tech' => 0, + 'serial' => 'MY47L1W1JHEB6', + 'otherserial' => null, + 'have_serial' => 0, + 'have_parallel' => 0, + 'have_usb' => 0, + 'have_wifi' => 0, + 'have_ethernet' => 0, + 'comment' => null, + 'memory_size' => null, + 'locations_id' => 0, + 'networks_id' => 0, + 'printertypes_id' => 0, + 'printermodels_id' => 0, + 'manufacturers_id' => 0, + 'is_global' => 0, + 'is_deleted' => 0, + 'is_template' => 0, + 'template_name' => null, + 'init_pages_counter' => 0, + 'last_pages_counter' => 0, + 'users_id' => 0, + 'states_id' => 0, + 'ticket_tco' => '0.0000', + 'is_dynamic' => 1, + 'uuid' => null, + 'sysdescr' => null, + 'last_inventory_update' => $_SESSION['glpi_currenttime'], + 'snmpcredentials_id' => 0, + 'autoupdatesystems_id' => $asset->fields['autoupdatesystems_id'], + 'groups_id' => [], + 'groups_id_tech' => [], + ]; + $this->assertIsArray($printer_fields); + $this->assertSame($expected, $printer_fields); + + //check volumes + $idisks = new \Item_Disk(); + $iterator = $idisks->getFromItem($asset); + $this->assertCount(6, $iterator); + + $expecteds = [ + [ + 'fsname' => 'ext4', + 'name' => '/', + 'device' => '/dev/mapper/xps-root', + 'mountpoint' => '/', + 'filesystems_id' => 4, + 'totalsize' => 40189, + 'freesize' => 11683, + 'encryption_status' => 1, + 'encryption_tool' => 'LUKS1', + 'encryption_algorithm' => 'aes-xts-plain64', + 'encryption_type' => null, + ], [ + 'fsname' => 'ext4', + 'name' => '/var/www', + 'device' => '/dev/mapper/xps-www', + 'mountpoint' => '/var/www', + 'filesystems_id' => 4, + 'totalsize' => 20030, + 'freesize' => 11924, + 'encryption_status' => 0, + 'encryption_tool' => null, + 'encryption_algorithm' => null, + 'encryption_type' => null, + ], [ + 'fsname' => 'ext4', + 'name' => '/boot', + 'device' => '/dev/nvme0n1p2', + 'mountpoint' => '/boot', + 'filesystems_id' => 4, + 'totalsize' => 975, + 'freesize' => 703, + 'encryption_status' => 0, + 'encryption_tool' => null, + 'encryption_algorithm' => null, + 'encryption_type' => null, + ], [ + 'fsname' => 'ext4', + 'name' => '/var/lib/mysql', + 'device' => '/dev/mapper/xps-maria', + 'mountpoint' => '/var/lib/mysql', + 'filesystems_id' => 4, + 'totalsize' => 20030, + 'freesize' => 15740, + 'encryption_status' => 1, + 'encryption_tool' => 'LUKS1', + 'encryption_algorithm' => 'aes-xts-plain64', + 'encryption_type' => null, + ], [ + 'fsname' => 'ext4', + 'name' => '/home', + 'device' => '/dev/mapper/xps-home', + 'mountpoint' => '/home', + 'filesystems_id' => 4, + 'totalsize' => 120439, + 'freesize' => 24872, + 'encryption_status' => 1, + 'encryption_tool' => 'LUKS1', + 'encryption_algorithm' => 'aes-xts-plain64', + 'encryption_type' => null, + ], [ + 'fsname' => 'VFAT', + 'name' => '/boot/efi', + 'device' => '/dev/nvme0n1p1', + 'mountpoint' => '/boot/efi', + 'filesystems_id' => 7, + 'totalsize' => 199, + 'freesize' => 191, + 'encryption_status' => 0, + 'encryption_tool' => null, + 'encryption_algorithm' => null, + 'encryption_type' => null, + ] + ]; + + $i = 0; + foreach ($iterator as $volume) { + unset($volume['id'], $volume['date_mod'], $volume['date_creation']); + $expected = $expecteds[$i]; + $expected += [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'entities_id' => 0, + 'is_deleted' => 0, + 'is_dynamic' => 1 + ]; + + ksort($expected); + ksort($volume); + + $this->assertIsArray($volume); + $this->assertEquals($expected, $volume); + ++$i; + } + + $isoft = new \Item_SoftwareVersion(); + $iterator = $isoft->getFromItem($asset); + $this->assertCount(7, $iterator); + + $link = getItemForItemtype(\Item_DeviceBattery::class); + $iterator = $DB->request($link->getTableGroupCriteria($asset)); + $this->assertCount(1, $iterator); + + $battery = []; + foreach ($iterator as $row) { + unset($row['id']); + $battery = $row; + } + + $expected = [ + 'items_id' => $assets_id, + 'itemtype' => $classname, + 'devicebatteries_id' => 104, + 'manufacturing_date' => '2019-07-06', + 'is_deleted' => 0, + 'is_dynamic' => 1, + 'entities_id' => 0, + 'is_recursive' => 0, + 'serial' => '34605', + 'otherserial' => null, + 'locations_id' => 0, + 'states_id' => 0, + 'real_capacity' => 50570 + ]; + + //hack to replace expected fkeys + foreach (array_keys($expected) as $key) { + if (isForeignKeyField($key)) { + $expected[$key] = $battery[$key]; + } + } + + $this->assertIsArray($battery); + $this->assertSame($expected, $battery); + } +} diff --git a/phpunit/functional/Glpi/Inventory/InventoryTest.php b/phpunit/functional/Glpi/Inventory/InventoryTest.php index b5b0ea1d854..da68547a3d2 100644 --- a/phpunit/functional/Glpi/Inventory/InventoryTest.php +++ b/phpunit/functional/Glpi/Inventory/InventoryTest.php @@ -1125,7 +1125,7 @@ public function testImportComputer() $inventory = $this->doInventory($json); - //check inventory metadata + //check inventory metadata $metadata = $inventory->getMetadata(); $this->assertCount(7, $metadata); $this->assertSame('glpixps-2018-07-09-09-07-13', $metadata['deviceid']); diff --git a/src/Glpi/Asset/Asset.php b/src/Glpi/Asset/Asset.php index c148aabcdf6..b60baa6e03b 100644 --- a/src/Glpi/Asset/Asset.php +++ b/src/Glpi/Asset/Asset.php @@ -51,6 +51,7 @@ abstract class Asset extends CommonDBTM use \Glpi\Features\AssignableItem; use \Glpi\Features\Clonable; use \Glpi\Features\State; + use \Glpi\Features\Inventoriable; /** * Asset definition. diff --git a/src/Glpi/Asset/Asset_PeripheralAsset.php b/src/Glpi/Asset/Asset_PeripheralAsset.php index a9ba93ecb1e..1dfd50e07fc 100644 --- a/src/Glpi/Asset/Asset_PeripheralAsset.php +++ b/src/Glpi/Asset/Asset_PeripheralAsset.php @@ -107,7 +107,8 @@ public function prepareInputForAdd($input) $asset = self::getItemFromArray(self::$itemtype_1, self::$items_id_1, $input); if ( - self::isAlreadyConnected($asset, $peripheral) + !($asset instanceof CommonDBTM) + || self::isAlreadyConnected($asset, $peripheral) || !(in_array($asset::class, self::getPeripheralHostItemtypes(), true)) ) { // no duplicates diff --git a/src/Glpi/Asset/Capacity/AbstractCapacity.php b/src/Glpi/Asset/Capacity/AbstractCapacity.php index 95493f4bc4a..d845d67bef1 100644 --- a/src/Glpi/Asset/Capacity/AbstractCapacity.php +++ b/src/Glpi/Asset/Capacity/AbstractCapacity.php @@ -77,6 +77,10 @@ public function getCloneRelations(): array return []; } + /** + * @param class-string $classname + * @return bool + */ public function isUsed(string $classname): bool { return $classname::getDefinition()->hasCapacityEnabled($this); @@ -160,13 +164,15 @@ protected function countAssetsLinkedToPeerItem(string $asset_classname, string $ * Count the number of assets for the given asset definition. * * @param class-string<\Glpi\Asset\Asset> $classname + * @param array $where_clause + * * @return int */ - protected function countAssets(string $classname): int + protected function countAssets(string $classname, array $where_clause = []): int { return countElementsInTable( Asset::getTable(), - [ + $where_clause + [ AssetDefinition::getForeignKeyField() => $classname::getDefinition()->fields['id'] ] ); diff --git a/src/Glpi/Asset/Capacity/IsInventoriableCapacity.php b/src/Glpi/Asset/Capacity/IsInventoriableCapacity.php new file mode 100644 index 00000000000..43cac62715f --- /dev/null +++ b/src/Glpi/Asset/Capacity/IsInventoriableCapacity.php @@ -0,0 +1,104 @@ +. + * + * --------------------------------------------------------------------- + */ + +namespace Glpi\Asset\Capacity; + +use AutoUpdateSystem; +use Glpi\Inventory\Inventory; +use Session; + +class IsInventoriableCapacity extends AbstractCapacity +{ + public function getLabel(): string + { + return Inventory::getTypeName(Session::getPluralNumber()); + } + + public function getIcon(): string + { + return Inventory::getIcon(); + } + + public function getSearchOptions(string $classname): array + { + $tab = \Agent::rawSearchOptionsToAdd(); + $tab[] = [ + 'id' => 42, + 'table' => 'glpi_autoupdatesystems', + 'field' => 'name', + 'name' => \AutoUpdateSystem::getTypeName(1), + 'datatype' => 'dropdown' + ]; + return $tab; + } + + public function isUsed(string $classname): bool + { + return parent::isUsed($classname) + && ($this->countAssets($classname, ['is_dynamic' => 1]) > 0); + } + + public function getCapacityUsageDescription(string $classname): string + { + $count = $this->countAssets($classname, ['is_dynamic' => 1]); + if ($count === 0) { + return __('Not used'); + } + return sprintf( + _n( + 'Used by %1$s asset', + 'Used by %1$s assets', + $count + ), + $count + ); + } + + public function onClassBootstrap(string $classname): void + { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + $this->registerToTypeConfig('inventory_types', $classname); + $this->registerToTypeConfig('agent_types', $classname); + } + + public function onCapacityDisabled(string $classname): void + { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + $this->unregisterFromTypeConfig('inventory_types', $classname); + $this->unregisterFromTypeConfig('agent_types', $classname); + } +} diff --git a/src/Glpi/Features/Inventoriable.php b/src/Glpi/Features/Inventoriable.php index ecd4c3a220d..c36467a145a 100644 --- a/src/Glpi/Features/Inventoriable.php +++ b/src/Glpi/Features/Inventoriable.php @@ -284,6 +284,7 @@ public function getInventoryAgent(): ?Agent $itemtype_ids[$relation_data['itemtype_peripheral']][] = $relation_data['items_id_peripheral']; } foreach ($itemtype_ids as $itemtype => $ids) { + /** @phpstan-ignore-next-line */ if (count($ids) > 0) { $conditions['OR'][] = [ 'itemtype' => $itemtype, diff --git a/src/Glpi/Inventory/Asset/Antivirus.php b/src/Glpi/Inventory/Asset/Antivirus.php index 969d14989e1..44e1e2b09e2 100644 --- a/src/Glpi/Inventory/Asset/Antivirus.php +++ b/src/Glpi/Inventory/Asset/Antivirus.php @@ -161,7 +161,9 @@ public function handle() public function checkConf(Conf $conf): bool { - return $conf->import_antivirus == 1; + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + return $conf->import_antivirus == 1 && in_array($this->item::class, $CFG_GLPI['itemantivirus_types']); } public function getItemtype(): string diff --git a/src/Glpi/Inventory/Asset/Battery.php b/src/Glpi/Inventory/Asset/Battery.php index 897732d312e..3390d7528eb 100644 --- a/src/Glpi/Inventory/Asset/Battery.php +++ b/src/Glpi/Inventory/Asset/Battery.php @@ -76,7 +76,7 @@ public function prepare(): array public function checkConf(Conf $conf): bool { - return $conf->component_battery == 1; + return $conf->component_battery == 1 && parent::checkConf($conf); } public function getItemtype(): string diff --git a/src/Glpi/Inventory/Asset/Bios.php b/src/Glpi/Inventory/Asset/Bios.php index dee79eb82e1..89164b9076f 100644 --- a/src/Glpi/Inventory/Asset/Bios.php +++ b/src/Glpi/Inventory/Asset/Bios.php @@ -77,11 +77,6 @@ public function handle() parent::handle(); } - public function checkConf(Conf $conf): bool - { - return true; - } - public function getItemtype(): string { return \Item_DeviceFirmware::class; diff --git a/src/Glpi/Inventory/Asset/Camera.php b/src/Glpi/Inventory/Asset/Camera.php index 176ab067972..cdcd3486cc1 100644 --- a/src/Glpi/Inventory/Asset/Camera.php +++ b/src/Glpi/Inventory/Asset/Camera.php @@ -148,11 +148,6 @@ private function handleFormats($itemdevice, $val) } } - public function checkConf(Conf $conf): bool - { - return true; - } - public function getItemtype(): string { return \Item_DeviceCamera::class; diff --git a/src/Glpi/Inventory/Asset/Computer.php b/src/Glpi/Inventory/Asset/Computer.php index 0f301c848bb..fdb0e937caa 100644 --- a/src/Glpi/Inventory/Asset/Computer.php +++ b/src/Glpi/Inventory/Asset/Computer.php @@ -49,9 +49,4 @@ protected function getTypesFieldName(): string { return ComputerType::getForeignKeyField(); } - - public function getItemtype(): string - { - return \Computer::class; - } } diff --git a/src/Glpi/Inventory/Asset/Controller.php b/src/Glpi/Inventory/Asset/Controller.php index fbc52f59386..4904624e70b 100644 --- a/src/Glpi/Inventory/Asset/Controller.php +++ b/src/Glpi/Inventory/Asset/Controller.php @@ -35,7 +35,6 @@ namespace Glpi\Inventory\Asset; -use CommonDBTM; use Glpi\Inventory\Conf; class Controller extends Device @@ -95,7 +94,7 @@ public function handle() public function checkConf(Conf $conf): bool { - return $conf->component_control == 1; + return $conf->component_control == 1 && parent::checkConf($conf); } public function getItemtype(): string diff --git a/src/Glpi/Inventory/Asset/DatabaseInstance.php b/src/Glpi/Inventory/Asset/DatabaseInstance.php index 24422a94ec4..93a0872fe14 100644 --- a/src/Glpi/Inventory/Asset/DatabaseInstance.php +++ b/src/Glpi/Inventory/Asset/DatabaseInstance.php @@ -225,7 +225,9 @@ public function handle() public function checkConf(Conf $conf): bool { - return true; + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + return in_array($this->item::class, $CFG_GLPI['databaseinstance_types']); } public function getItemtype(): string diff --git a/src/Glpi/Inventory/Asset/Device.php b/src/Glpi/Inventory/Asset/Device.php index a7ec36436ab..f840481485e 100644 --- a/src/Glpi/Inventory/Asset/Device.php +++ b/src/Glpi/Inventory/Asset/Device.php @@ -35,6 +35,7 @@ namespace Glpi\Inventory\Asset; +use Glpi\Inventory\Conf; use Item_Devices; abstract class Device extends InventoryAsset @@ -197,4 +198,14 @@ protected function itemdeviceAdded(Item_Devices $itemdevice, $val) { //to be overrided } + + public function checkConf(Conf $conf): bool + { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + /** @var \Item_Devices $item_device */ + $item_device = $this->getItemtype(); + $affinities = $item_device::itemAffinity(); + return in_array('*', $affinities) || in_array($this->item->getType(), $item_device::itemAffinity()); + } } diff --git a/src/Glpi/Inventory/Asset/Drive.php b/src/Glpi/Inventory/Asset/Drive.php index 481baca08de..57efbf42267 100644 --- a/src/Glpi/Inventory/Asset/Drive.php +++ b/src/Glpi/Inventory/Asset/Drive.php @@ -124,7 +124,7 @@ public function handle() public function checkConf(Conf $conf): bool { - return $conf->component_drive == 1; + return $conf->component_drive == 1 && parent::checkConf($conf); } /** diff --git a/src/Glpi/Inventory/Asset/Environment.php b/src/Glpi/Inventory/Asset/Environment.php index ec1d475f7e2..bc4d21c4359 100644 --- a/src/Glpi/Inventory/Asset/Environment.php +++ b/src/Glpi/Inventory/Asset/Environment.php @@ -131,8 +131,10 @@ public function handle() public function checkConf(Conf $conf): bool { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; $this->conf = $conf; - return $conf->import_env == 1; + return $conf->import_env == 1 && in_array($this->item::class, $CFG_GLPI['environment_types']); } public function getItemtype(): string diff --git a/src/Glpi/Inventory/Asset/Firmware.php b/src/Glpi/Inventory/Asset/Firmware.php index b9f448e398f..6fa727b0b60 100644 --- a/src/Glpi/Inventory/Asset/Firmware.php +++ b/src/Glpi/Inventory/Asset/Firmware.php @@ -60,11 +60,6 @@ public function prepare(): array return $this->data; } - public function checkConf(Conf $conf): bool - { - return true; - } - public function getItemtype(): string { return \Item_DeviceFirmware::class; diff --git a/src/Glpi/Inventory/Asset/GenericAsset.php b/src/Glpi/Inventory/Asset/GenericAsset.php new file mode 100644 index 00000000000..e1bd1ea74c5 --- /dev/null +++ b/src/Glpi/Inventory/Asset/GenericAsset.php @@ -0,0 +1,60 @@ +. + * + * --------------------------------------------------------------------- + */ + +namespace Glpi\Inventory\Asset; + +use PhoneModel; +use PhoneType; + +class GenericAsset extends MainAsset +{ + protected function getModelsFieldName(): string + { + /** @var \Glpi\Asset\Asset $item */ + $item = $this->item; + $model_classname = $item->getDefinition()->getAssetModelClassName(); + + return getForeignKeyFieldForItemType($model_classname); + } + + protected function getTypesFieldName(): string + { + /** @var \Glpi\Asset\Asset $item */ + $item = $this->item; + $type_classname = $item->getDefinition()->getAssetTypeClassName(); + + return getForeignKeyFieldForItemType($type_classname); + } +} diff --git a/src/Glpi/Inventory/Asset/GraphicCard.php b/src/Glpi/Inventory/Asset/GraphicCard.php index 74a3beb12b3..ad221dd8158 100644 --- a/src/Glpi/Inventory/Asset/GraphicCard.php +++ b/src/Glpi/Inventory/Asset/GraphicCard.php @@ -71,7 +71,7 @@ public function prepare(): array public function checkConf(Conf $conf): bool { - return $conf->component_graphiccard == 1; + return $conf->component_graphiccard == 1 && parent::checkConf($conf); } public function getItemtype(): string diff --git a/src/Glpi/Inventory/Asset/HardDrive.php b/src/Glpi/Inventory/Asset/HardDrive.php index 089b44fde9c..e5a32667537 100644 --- a/src/Glpi/Inventory/Asset/HardDrive.php +++ b/src/Glpi/Inventory/Asset/HardDrive.php @@ -73,7 +73,7 @@ public function prepare(): array public function checkConf(Conf $conf): bool { - return $conf->component_harddrive == 1; + return $conf->component_harddrive == 1 && parent::checkConf($conf); } public function getItemtype(): string diff --git a/src/Glpi/Inventory/Asset/InventoryAsset.php b/src/Glpi/Inventory/Asset/InventoryAsset.php index 8502c189b3c..5fb7c2d439d 100644 --- a/src/Glpi/Inventory/Asset/InventoryAsset.php +++ b/src/Glpi/Inventory/Asset/InventoryAsset.php @@ -457,7 +457,10 @@ protected function handleInput(\stdClass $value, ?CommonDBTM $item = null): arra return $input; } - abstract public function getItemtype(): string; + public function getItemtype(): string + { + return $this->item::class; + } final protected function cleanName(string $string): string { diff --git a/src/Glpi/Inventory/Asset/InventoryNetworkPort.php b/src/Glpi/Inventory/Asset/InventoryNetworkPort.php index ad1dde764fb..b5018632de4 100644 --- a/src/Glpi/Inventory/Asset/InventoryNetworkPort.php +++ b/src/Glpi/Inventory/Asset/InventoryNetworkPort.php @@ -108,6 +108,10 @@ private function isMainPartial(): bool */ public function handlePorts($itemtype = null, $items_id = null) { + if (!$this->checkPortsConf($this->conf)) { + return; + } + $this->itemtype = $itemtype ?? $this->item->getType(); $this->items_id = $items_id ?? $this->item->fields['id']; @@ -678,8 +682,10 @@ protected function portCreated(\stdClass $port, int $netports_id) //does nothing } - public function checkConf(Conf $conf): bool + public function checkPortsConf(Conf $conf): bool { - return $conf->component_networkcard == 1; + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + return $conf->component_networkcard == 1 && in_array($this->item::class, $CFG_GLPI['networkport_types']); } } diff --git a/src/Glpi/Inventory/Asset/MainAsset.php b/src/Glpi/Inventory/Asset/MainAsset.php index 3ed7aa056d2..f9f91f8b0a6 100644 --- a/src/Glpi/Inventory/Asset/MainAsset.php +++ b/src/Glpi/Inventory/Asset/MainAsset.php @@ -103,14 +103,14 @@ public function __construct(CommonDBTM $item, $data) * * @return string */ - abstract protected function getModelsFieldName(); + abstract protected function getModelsFieldName(): string; /** * Get model foreign key field name * * @return string */ - abstract protected function getTypesFieldName(); + abstract protected function getTypesFieldName(): string; public function prepare(): array { diff --git a/src/Glpi/Inventory/Asset/Memory.php b/src/Glpi/Inventory/Asset/Memory.php index a8c2082c78e..c806cf4b18f 100644 --- a/src/Glpi/Inventory/Asset/Memory.php +++ b/src/Glpi/Inventory/Asset/Memory.php @@ -109,7 +109,7 @@ public function prepare(): array public function checkConf(Conf $conf): bool { - return $conf->component_memory == 1; + return $conf->component_memory == 1 && parent::checkConf($conf); } public function getItemtype(): string diff --git a/src/Glpi/Inventory/Asset/Monitor.php b/src/Glpi/Inventory/Asset/Monitor.php index 9bda0e7afb8..92118f34559 100644 --- a/src/Glpi/Inventory/Asset/Monitor.php +++ b/src/Glpi/Inventory/Asset/Monitor.php @@ -122,7 +122,7 @@ protected function getExisting(): array ], 'WHERE' => [ 'itemtype_peripheral' => 'Monitor', - 'itemtype_asset' => 'Computer', + 'itemtype_asset' => $this->item::class, 'items_id_asset' => $this->item->getID(), 'entities_id' => $this->entities_id, $relation_table . '.is_dynamic' => 1, @@ -192,7 +192,7 @@ public function handle() if (count($db_monitors) == 0) { foreach ($monitors as $monitors_id) { $input = [ - 'itemtype_asset' => \Computer::class, + 'itemtype_asset' => $this->item::class, 'items_id_asset' => $this->item->fields['id'], 'itemtype_peripheral' => \Monitor::class, 'items_id_peripheral' => $monitors_id, @@ -232,12 +232,15 @@ public function handle() public function checkConf(Conf $conf): bool { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; $this->import_monitor_on_partial_sn = $conf->import_monitor_on_partial_sn; - return $conf->import_monitor == 1; + return $conf->import_monitor == 1 && in_array($this->item::class, $CFG_GLPI['peripheralhost_types']); } public function getItemtype(): string { + //FIXME: check if this is correct - should be the same as Peripheral::getItemtype() return Asset_PeripheralAsset::class; } } diff --git a/src/Glpi/Inventory/Asset/NetworkCard.php b/src/Glpi/Inventory/Asset/NetworkCard.php index d4f43c8ca5f..3b2aecaa0fb 100644 --- a/src/Glpi/Inventory/Asset/NetworkCard.php +++ b/src/Glpi/Inventory/Asset/NetworkCard.php @@ -296,7 +296,7 @@ public function prepare(): array public function checkConf(Conf $conf): bool { $this->conf = $conf; - return $conf->component_networkcard == 1; + return $conf->component_networkcard == 1 && parent::checkConf($conf); } public function handlePorts($itemtype = null, $items_id = null) diff --git a/src/Glpi/Inventory/Asset/NetworkEquipment.php b/src/Glpi/Inventory/Asset/NetworkEquipment.php index fc185de0d7f..5fbc6d704bf 100644 --- a/src/Glpi/Inventory/Asset/NetworkEquipment.php +++ b/src/Glpi/Inventory/Asset/NetworkEquipment.php @@ -412,9 +412,4 @@ public function getStackId() return preg_replace('/.+\s(\d+)$/', '$1', $data->name); } } - - public function getItemtype(): string - { - return \NetworkEquipment::class; - } } diff --git a/src/Glpi/Inventory/Asset/NetworkPort.php b/src/Glpi/Inventory/Asset/NetworkPort.php index 91395f27858..d9afa2f6c35 100644 --- a/src/Glpi/Inventory/Asset/NetworkPort.php +++ b/src/Glpi/Inventory/Asset/NetworkPort.php @@ -60,6 +60,7 @@ class NetworkPort extends InventoryAsset private $current_connection; private $vlan_stmt; private $pvlan_stmt; + protected Conf $conf; public function prepare(): array { @@ -909,7 +910,10 @@ public function handleHub($found_macs, $netports_id) public function checkConf(Conf $conf): bool { - return true; + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + $this->conf = $conf; + return in_array($this->item::class, $CFG_GLPI['networkport_types']); } public function getPart($part) diff --git a/src/Glpi/Inventory/Asset/OperatingSystem.php b/src/Glpi/Inventory/Asset/OperatingSystem.php index d9ac3af1dbf..328b7f09ad7 100644 --- a/src/Glpi/Inventory/Asset/OperatingSystem.php +++ b/src/Glpi/Inventory/Asset/OperatingSystem.php @@ -201,7 +201,9 @@ public function handle() public function checkConf(Conf $conf): bool { - return true; + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + return in_array($this->item::class, $CFG_GLPI['operatingsystem_types']); } /** diff --git a/src/Glpi/Inventory/Asset/Peripheral.php b/src/Glpi/Inventory/Asset/Peripheral.php index b2b795bf351..3c637907727 100644 --- a/src/Glpi/Inventory/Asset/Peripheral.php +++ b/src/Glpi/Inventory/Asset/Peripheral.php @@ -259,11 +259,14 @@ public function handle() public function checkConf(Conf $conf): bool { - return $conf->import_peripheral == 1; + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + return $conf->import_peripheral == 1 && in_array($this->item::class, $CFG_GLPI['peripheralhost_types']); } public function getItemtype(): string { + //FIXME: check if this is correct - should be the same as Monitor::getItemtype() return \Peripheral::class; } } diff --git a/src/Glpi/Inventory/Asset/Phone.php b/src/Glpi/Inventory/Asset/Phone.php index 899dc525c96..6bcd4da35fa 100644 --- a/src/Glpi/Inventory/Asset/Phone.php +++ b/src/Glpi/Inventory/Asset/Phone.php @@ -49,9 +49,4 @@ protected function getTypesFieldName(): string { return PhoneType::getForeignKeyField(); } - - public function getItemtype(): string - { - return \Phone::class; - } } diff --git a/src/Glpi/Inventory/Asset/PowerSupply.php b/src/Glpi/Inventory/Asset/PowerSupply.php index b9e19ebcbf2..f6cf6d52662 100644 --- a/src/Glpi/Inventory/Asset/PowerSupply.php +++ b/src/Glpi/Inventory/Asset/PowerSupply.php @@ -61,7 +61,7 @@ public function prepare(): array public function checkConf(Conf $conf): bool { - return $conf->component_powersupply == 1; + return $conf->component_powersupply == 1 && parent::checkConf($conf); } public function getItemtype(): string diff --git a/src/Glpi/Inventory/Asset/Printer.php b/src/Glpi/Inventory/Asset/Printer.php index a4c323e5661..1dc9a6e1bb3 100644 --- a/src/Glpi/Inventory/Asset/Printer.php +++ b/src/Glpi/Inventory/Asset/Printer.php @@ -39,6 +39,7 @@ use Blacklist; use CommonDBTM; use Glpi\Asset\Asset_PeripheralAsset; +use Glpi\Inventory\Conf; use IPAddress; use Printer as GPrinter; use PrinterLog; @@ -212,6 +213,10 @@ protected function handleConnectedPrinter() /** @var \DBmysql $DB */ global $DB; + if (!$this->checkPrinterConf($this->conf)) { + return; + } + $rule = new RuleImportAssetCollection(); $printer = new GPrinter(); $printers = []; @@ -230,7 +235,7 @@ protected function handleConnectedPrinter() foreach ($this->data as $key => $val) { $input = [ - 'itemtype' => "Printer", + 'itemtype' => \Printer::class, 'name' => $val->name, 'serial' => $val->serial ?? '', 'is_dynamic' => 1 @@ -238,7 +243,7 @@ protected function handleConnectedPrinter() $data = $rule->processAllRules($input, [], ['class' => $this, 'return' => true]); if (isset($data['found_inventories'])) { $items_id = null; - $itemtype = 'Printer'; + $itemtype = \Printer::class; if ($data['found_inventories'][0] == 0) { // add printer $val->entities_id = $entities_id; @@ -284,7 +289,7 @@ protected function handleConnectedPrinter() ], 'WHERE' => [ 'itemtype_peripheral' => \Printer::class, - 'itemtype_asset' => \Computer::class, + 'itemtype_asset' => $this->item::class, 'items_id_asset' => $this->item->fields['id'], 'entities_id' => $entities_id, $relation_table . '.is_dynamic' => 1, @@ -318,7 +323,7 @@ protected function handleConnectedPrinter() foreach ($printers as $printers_id) { $input = [ 'entities_id' => $entities_id, - 'itemtype_asset' => \Computer::class, + 'itemtype_asset' => $this->item::class, 'items_id_asset' => $this->item->fields['id'], 'itemtype_peripheral' => \Printer::class, 'items_id_peripheral' => $printers_id, @@ -398,4 +403,11 @@ public function getItemtype(): string { return \Printer::class; } + + public function checkPrinterConf(Conf $conf): bool + { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + return $conf->import_printer == 1 && in_array($this->item::class, $CFG_GLPI['peripheralhost_types']); + } } diff --git a/src/Glpi/Inventory/Asset/Process.php b/src/Glpi/Inventory/Asset/Process.php index 4c0eef5c299..bf5781852f5 100644 --- a/src/Glpi/Inventory/Asset/Process.php +++ b/src/Glpi/Inventory/Asset/Process.php @@ -152,8 +152,10 @@ public function handle() public function checkConf(Conf $conf): bool { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; $this->conf = $conf; - return $conf->import_process == 1; + return $conf->import_process == 1 && in_array($this->item::class, $CFG_GLPI['process_types']); } public function getItemtype(): string diff --git a/src/Glpi/Inventory/Asset/Processor.php b/src/Glpi/Inventory/Asset/Processor.php index bf02138e036..eaabf80ea45 100644 --- a/src/Glpi/Inventory/Asset/Processor.php +++ b/src/Glpi/Inventory/Asset/Processor.php @@ -76,7 +76,7 @@ public function prepare(): array public function checkConf(Conf $conf): bool { - return $conf->component_processor == 1; + return $conf->component_processor == 1 && parent::checkConf($conf); } public function getItemtype(): string diff --git a/src/Glpi/Inventory/Asset/RemoteManagement.php b/src/Glpi/Inventory/Asset/RemoteManagement.php index 9e96c469ae8..8fedcef751a 100644 --- a/src/Glpi/Inventory/Asset/RemoteManagement.php +++ b/src/Glpi/Inventory/Asset/RemoteManagement.php @@ -141,7 +141,9 @@ public function handle() public function checkConf(Conf $conf): bool { - return true; + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + return in_array($this->item::class, $CFG_GLPI['remote_management_types']); } public function getItemtype(): string diff --git a/src/Glpi/Inventory/Asset/Sensor.php b/src/Glpi/Inventory/Asset/Sensor.php index d057012e463..b67d2992d47 100644 --- a/src/Glpi/Inventory/Asset/Sensor.php +++ b/src/Glpi/Inventory/Asset/Sensor.php @@ -62,11 +62,6 @@ public function prepare(): array return $this->data; } - public function checkConf(Conf $conf): bool - { - return true; - } - public function getItemtype(): string { return \Item_DeviceSensor::class; diff --git a/src/Glpi/Inventory/Asset/Simcard.php b/src/Glpi/Inventory/Asset/Simcard.php index 5917092f003..3006ae1ae8f 100644 --- a/src/Glpi/Inventory/Asset/Simcard.php +++ b/src/Glpi/Inventory/Asset/Simcard.php @@ -60,7 +60,7 @@ public function prepare(): array public function checkConf(Conf $conf): bool { - return $conf->component_simcard == 1; + return $conf->component_simcard == 1 && parent::checkConf($conf); } public function getItemtype(): string diff --git a/src/Glpi/Inventory/Asset/Software.php b/src/Glpi/Inventory/Asset/Software.php index e62e2f8fa27..a6780291bdc 100644 --- a/src/Glpi/Inventory/Asset/Software.php +++ b/src/Glpi/Inventory/Asset/Software.php @@ -1032,7 +1032,9 @@ public function logSoftwares() public function checkConf(Conf $conf): bool { - return $conf->import_software == 1; + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + return $conf->import_software == 1 && in_array($this->item::class, $CFG_GLPI['software_types']); } public function getItemtype(): string diff --git a/src/Glpi/Inventory/Asset/SoundCard.php b/src/Glpi/Inventory/Asset/SoundCard.php index afd8f8ad185..28e9d03d409 100644 --- a/src/Glpi/Inventory/Asset/SoundCard.php +++ b/src/Glpi/Inventory/Asset/SoundCard.php @@ -63,7 +63,7 @@ public function prepare(): array public function checkConf(Conf $conf): bool { - return $conf->component_soundcard == 1; + return $conf->component_soundcard == 1 && parent::checkConf($conf); } public function getItemtype(): string diff --git a/src/Glpi/Inventory/Asset/Unmanaged.php b/src/Glpi/Inventory/Asset/Unmanaged.php index 6ed84c77af6..122be01466b 100644 --- a/src/Glpi/Inventory/Asset/Unmanaged.php +++ b/src/Glpi/Inventory/Asset/Unmanaged.php @@ -342,9 +342,4 @@ public function checkConf(Conf $conf): bool $this->states_id_default = $conf->states_id_default; return $conf->import_unmanaged == 1; } - - public function getItemtype(): string - { - return \Unmanaged::class; - } } diff --git a/src/Glpi/Inventory/Asset/VirtualMachine.php b/src/Glpi/Inventory/Asset/VirtualMachine.php index 9dabe13da88..9fb3649bac2 100644 --- a/src/Glpi/Inventory/Asset/VirtualMachine.php +++ b/src/Glpi/Inventory/Asset/VirtualMachine.php @@ -413,8 +413,10 @@ public function getExistingVMAsComputer(\stdClass $vm): int public function checkConf(Conf $conf): bool { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; $this->conf = $conf; - return $conf->import_vm == 1; + return $conf->import_vm == 1 && in_array($this->item::class, $CFG_GLPI['itemvirtualmachines_types']); } public function getItemtype(): string diff --git a/src/Glpi/Inventory/Asset/Volume.php b/src/Glpi/Inventory/Asset/Volume.php index 8fa37903e2b..33ec95990ff 100644 --- a/src/Glpi/Inventory/Asset/Volume.php +++ b/src/Glpi/Inventory/Asset/Volume.php @@ -212,8 +212,10 @@ public function isRemovableDrive(\stdClass $raw_data): bool public function checkConf(Conf $conf): bool { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; $this->conf = $conf; - return $conf->import_volume == 1; + return $conf->import_volume == 1 && in_array($this->item::class, $CFG_GLPI['disk_types']); } public function getItemtype(): string diff --git a/src/Glpi/Inventory/Inventory.php b/src/Glpi/Inventory/Inventory.php index 973b0d325d8..6149fdee4c4 100644 --- a/src/Glpi/Inventory/Inventory.php +++ b/src/Glpi/Inventory/Inventory.php @@ -37,6 +37,8 @@ use Agent; use CommonDBTM; +use Glpi\Asset\AssetDefinitionManager; +use Glpi\Asset\Capacity\IsInventoriableCapacity; use Glpi\Inventory\Asset\InventoryAsset; use Glpi\Inventory\Asset\MainAsset; use Lockedfield; @@ -125,6 +127,8 @@ public function setData($data, $format = Request::JSON_MODE): bool } $converter = new Converter(); + $converter->setExtraItemtypes($this->getExtraItemtypes()); + if (method_exists($this, 'getSchemaExtraProps')) { $converter->setExtraProperties($this->getSchemaExtraProps()); } @@ -564,8 +568,12 @@ public static function getMenuContent() public function getMainClass() { $agent = $this->getAgent(); - $main_class = '\Glpi\Inventory\Asset\\' . $agent->fields['itemtype']; - return $main_class; + $class_ns = '\Glpi\Inventory\Asset\\'; + $main_class = $class_ns . $agent->fields['itemtype']; + if (class_exists($main_class)) { + return $main_class; + } + return $class_ns . 'GenericAsset'; } /** @@ -698,10 +706,10 @@ final public function processInventoryData() } if ($assettype !== false) { - //handle if asset type has been found. + //handle if asset type has been found. $asset = new $assettype($this->item, (array)$value); + $asset->setMainAsset($this->mainasset); if ($asset->checkConf($this->conf)) { - $asset->setMainAsset($this->mainasset); $asset->setAgent($this->getAgent()); $asset->setExtraData($this->data); $asset->setEntityID($this->mainasset->getEntityID()); @@ -991,4 +999,16 @@ public function setDiscovery(bool $disco): self $this->is_discovery = $disco; return $this; } + + protected function getExtraItemtypes(): array + { + $definitions = AssetDefinitionManager::getInstance()->getDefinitions(true); + $itemtypes = []; + foreach ($definitions as $definition) { + if ($definition->hasCapacityEnabled(new IsInventoriableCapacity())) { + $itemtypes[] = $definition->getAssetClassName(); + } + } + return $itemtypes; + } } diff --git a/src/autoload/CFG_GLPI.php b/src/autoload/CFG_GLPI.php index e83983f8a3e..8861e236ee4 100644 --- a/src/autoload/CFG_GLPI.php +++ b/src/autoload/CFG_GLPI.php @@ -166,7 +166,7 @@ ]; // `peripheralhost_types` contains assets that can host peripherals -// `directconnect_types` contains the list of assets that are considred as peripherals +// `directconnect_types` contains the list of assets that are considered as peripherals $CFG_GLPI["peripheralhost_types"] = ['Computer']; $CFG_GLPI["directconnect_types"] = ['Monitor', 'Peripheral', 'Phone', 'Printer']; @@ -315,6 +315,10 @@ $CFG_GLPI['itemdevicepci_types'] = ['*']; +$CFG_GLPI['itemdevicecontrol_types'] = ['Computer']; + +$CFG_GLPI['itemdevicedrive_types'] = ['Computer']; + $CFG_GLPI['itemdevicesensor_types'] = ['Computer', 'Peripheral', 'Phone']; $CFG_GLPI['itemdeviceprocessor_types'] = ['Computer', 'Phone']; @@ -633,3 +637,6 @@ $CFG_GLPI['admin_types'] = [ 'User', 'Group', 'Entity', 'Profile' ]; + +$CFG_GLPI['process_types'] = ['Computer']; +$CFG_GLPI['environment_types'] = ['Computer']; diff --git a/tests/functional/Glpi/Asset/Capacity/IsInventoriableCapacity.php b/tests/functional/Glpi/Asset/Capacity/IsInventoriableCapacity.php new file mode 100644 index 00000000000..40f5dd4e13f --- /dev/null +++ b/tests/functional/Glpi/Asset/Capacity/IsInventoriableCapacity.php @@ -0,0 +1,228 @@ +. + * + * --------------------------------------------------------------------- + */ + +namespace tests\units\Glpi\Asset\Capacity; + +use DbTestCase; +use DisplayPreference; +use Entity; +use Glpi\Tests\Asset\CapacityUsageTestTrait; +use Log; +use ReservationItem; + +class IsInventoriableCapacity extends DbTestCase +{ + protected function getTargetCapacity(): string + { + return \Glpi\Asset\Capacity\IsInventoriableCapacity::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\IsInventoriableCapacity::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\IsInventoriableCapacity::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 + if ($has_capacity) { + $this->array($CFG_GLPI['inventory_types'])->contains($classname); + } else { + $this->array($CFG_GLPI['inventory_types'])->notContains($classname); + } + } + } + + 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\IsInventoriableCapacity::class, + \Glpi\Asset\Capacity\HasHistoryCapacity::class, + ] + ); + $classname_1 = $definition_1->getAssetClassName(); + $definition_2 = $this->initAssetDefinition( + capacities: [ + \Glpi\Asset\Capacity\IsInventoriableCapacity::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, + ] + ); + + // Ensure class is registered to global config + $this->array($CFG_GLPI['inventory_types'])->contains($classname_1); + $this->array($CFG_GLPI['agent_types'])->contains($classname_1); + $this->array($CFG_GLPI['inventory_types'])->contains($classname_2); + $this->array($CFG_GLPI['agent_types'])->contains($classname_2); + + // Disable capacity and check class is unregistered from global config + $this->boolean($definition_1->update(['id' => $definition_1->getID(), 'capacities' => []]))->isTrue(); + $this->array($CFG_GLPI['inventory_types'])->notContains($classname_1); + $this->array($CFG_GLPI['agent_types'])->notContains($classname_1); + + // Ensure global registration is preserved for other definition + $this->array($CFG_GLPI['inventory_types'])->contains($classname_2); + $this->array($CFG_GLPI['agent_types'])->contains($classname_2); + } + + public function testIsUsed(): void + { + global $DB; + + // Retrieve the test root entity + $entity_id = $this->getTestRootEntity(true); + + // Create custom asset definition with the target capacity enabled + $definition = $this->initAssetDefinition( + capacities: [$this->getTargetCapacity()] + ); + + // Create a non-dynamic test subject + $this->createItem($definition->getAssetClassName(), [ + 'name' => 'Test asset', + 'entities_id' => $entity_id, + 'is_dynamic' => 0, + ]); + + // Check that the capacity can be disabled + $capacity = new ($this->getTargetCapacity()); + $this->boolean($capacity->isUsed($definition->getAssetClassName()))->isFalse(); + + // Create a dynamic test subject + $this->createItem($definition->getAssetClassName(), [ + 'name' => 'Test asset 2', + 'entities_id' => $entity_id, + 'is_dynamic' => 1, + ]); + + // Check that the capacity can't be safely disabled + $capacity = new ($this->getTargetCapacity()); + $this->boolean($capacity->isUsed($definition->getAssetClassName()))->isTrue(); + } + + /** + * Test if the getCapacityUsageDescription method returns a correct description + * of the capacity usage. + * + * @return void + */ + public function testGetCapacityUsageDescription(): void + { + global $DB; + + $capacity = new ($this->getTargetCapacity()); + + // Retrieve the test root entity + $entity_id = $this->getTestRootEntity(true); + + // Create custom asset definition with the target capacity enabled + $definition = $this->initAssetDefinition( + capacities: [$this->getTargetCapacity()] + ); + + // Create a non-dynamic test subject + $this->createItem($definition->getAssetClassName(), [ + 'name' => 'Test asset', + 'entities_id' => $entity_id, + 'is_dynamic' => 0, + ]); + + $this->string($capacity->getCapacityUsageDescription($definition->getAssetClassName()))->isEqualTo('Not used'); + + // Create a dynamic test subject + $this->createItem($definition->getAssetClassName(), [ + 'name' => 'Test asset 2', + 'entities_id' => $entity_id, + 'is_dynamic' => 1, + ]); + $this->string($capacity->getCapacityUsageDescription($definition->getAssetClassName()))->isEqualTo('Used by 1 asset'); + + // Create another dynamic test subject + $this->createItem($definition->getAssetClassName(), [ + 'name' => 'Test asset 3', + 'entities_id' => $entity_id, + 'is_dynamic' => 1, + ]); + $this->string($capacity->getCapacityUsageDescription($definition->getAssetClassName()))->isEqualTo('Used by 2 assets'); + } +} diff --git a/tests/src/autoload/functions.php b/tests/src/autoload/functions.php index edea695a6f3..ede006c783e 100644 --- a/tests/src/autoload/functions.php +++ b/tests/src/autoload/functions.php @@ -689,6 +689,7 @@ function loadDataset() $_SESSION['glpiactive_entity'] = 0; $_SESSION['glpiactiveentities'] = [0]; $_SESSION['glpiactiveentities_string'] = "'0'"; + $_SESSION["glpi_currenttime"] = date("Y-m-d H:i:s"); $CFG_GLPI['root_doc'] = '/glpi'; $DB->beginTransaction();