feat(mcp) : add Slots, Machine Links, Structure, and Clone tools
- list_slots + update_slots for composant/piece slots - list/add/update/remove machine links (component, piece, product) - get_machine_structure with full hierarchy - clone_machine with all links and custom fields - 52 MCP tests pass total Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
164
tests/Mcp/Tool/Machine/MachineStructureToolTest.php
Normal file
164
tests/Mcp/Tool/Machine/MachineStructureToolTest.php
Normal file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Mcp\Tool\Machine;
|
||||
|
||||
use App\Tests\AbstractApiTestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class MachineStructureToolTest extends AbstractApiTestCase
|
||||
{
|
||||
public function testGetMachineStructure(): void
|
||||
{
|
||||
$site = $this->createSite(name: 'Site Structure');
|
||||
$machine = $this->createMachine(name: 'Machine Structure', site: $site, reference: 'REF-STRUCT');
|
||||
$composant = $this->createComposant(name: 'Composant Alpha');
|
||||
$piece = $this->createPiece(name: 'Piece Alpha', reference: 'REF-P1');
|
||||
$product = $this->createProduct(name: 'Product Alpha', reference: 'REF-PR1');
|
||||
|
||||
$componentLink = $this->createMachineComponentLink($machine, $composant);
|
||||
$this->createMachinePieceLink($machine, $piece, $componentLink, quantity: 3);
|
||||
$this->createMachineProductLink($machine, $product);
|
||||
|
||||
$session = $this->createMcpClient('ROLE_VIEWER');
|
||||
|
||||
$data = $this->callMcpTool($session, 'get_machine_structure', [
|
||||
'machineId' => $machine->getId(),
|
||||
]);
|
||||
|
||||
$this->assertArrayHasKey('_parsed', $data);
|
||||
$parsed = $data['_parsed'];
|
||||
|
||||
// Machine info
|
||||
$this->assertSame('Machine Structure', $parsed['machine']['name']);
|
||||
$this->assertSame('REF-STRUCT', $parsed['machine']['reference']);
|
||||
$this->assertSame($site->getId(), $parsed['machine']['siteId']);
|
||||
|
||||
// Component links
|
||||
$this->assertCount(1, $parsed['componentLinks']);
|
||||
$this->assertSame($composant->getId(), $parsed['componentLinks'][0]['composantId']);
|
||||
$this->assertSame('Composant Alpha', $parsed['componentLinks'][0]['composant']['name']);
|
||||
|
||||
// Piece links
|
||||
$this->assertCount(1, $parsed['pieceLinks']);
|
||||
$this->assertSame($piece->getId(), $parsed['pieceLinks'][0]['pieceId']);
|
||||
$this->assertSame('Piece Alpha', $parsed['pieceLinks'][0]['piece']['name']);
|
||||
$this->assertSame(3, $parsed['pieceLinks'][0]['quantity']);
|
||||
|
||||
// Product links
|
||||
$this->assertCount(1, $parsed['productLinks']);
|
||||
$this->assertSame($product->getId(), $parsed['productLinks'][0]['productId']);
|
||||
$this->assertSame('Product Alpha', $parsed['productLinks'][0]['product']['name']);
|
||||
}
|
||||
|
||||
public function testGetMachineStructureNotFound(): void
|
||||
{
|
||||
$session = $this->createMcpClient('ROLE_VIEWER');
|
||||
|
||||
$data = $this->callMcpTool($session, 'get_machine_structure', [
|
||||
'machineId' => 'nonexistent-id',
|
||||
]);
|
||||
|
||||
$this->assertArrayHasKey('error', $data);
|
||||
}
|
||||
|
||||
public function testGetMachineStructureWithOverrides(): void
|
||||
{
|
||||
$site = $this->createSite(name: 'Site Overrides');
|
||||
$machine = $this->createMachine(name: 'Machine Overrides', site: $site);
|
||||
$composant = $this->createComposant(name: 'Composant Override');
|
||||
|
||||
$componentLink = $this->createMachineComponentLink($machine, $composant);
|
||||
$componentLink->setNameOverride('Custom Name');
|
||||
$componentLink->setReferenceOverride('CUSTOM-REF');
|
||||
$this->getEntityManager()->flush();
|
||||
|
||||
$session = $this->createMcpClient('ROLE_VIEWER');
|
||||
|
||||
$data = $this->callMcpTool($session, 'get_machine_structure', [
|
||||
'machineId' => $machine->getId(),
|
||||
]);
|
||||
|
||||
$this->assertArrayHasKey('_parsed', $data);
|
||||
$overrides = $data['_parsed']['componentLinks'][0]['overrides'];
|
||||
$this->assertSame('Custom Name', $overrides['name']);
|
||||
$this->assertSame('CUSTOM-REF', $overrides['reference']);
|
||||
}
|
||||
|
||||
public function testCloneMachine(): void
|
||||
{
|
||||
$site = $this->createSite(name: 'Site Source');
|
||||
$targetSite = $this->createSite(name: 'Site Target');
|
||||
$machine = $this->createMachine(name: 'Machine Source', site: $site, reference: 'REF-SRC');
|
||||
$composant = $this->createComposant(name: 'Composant Clone');
|
||||
$piece = $this->createPiece(name: 'Piece Clone');
|
||||
$product = $this->createProduct(name: 'Product Clone');
|
||||
|
||||
$componentLink = $this->createMachineComponentLink($machine, $composant);
|
||||
$this->createMachinePieceLink($machine, $piece, $componentLink, quantity: 2);
|
||||
$this->createMachineProductLink($machine, $product);
|
||||
|
||||
$session = $this->createMcpClient('ROLE_GESTIONNAIRE');
|
||||
|
||||
$data = $this->callMcpTool($session, 'clone_machine', [
|
||||
'machineId' => $machine->getId(),
|
||||
'name' => 'Machine Cloned',
|
||||
'siteId' => $targetSite->getId(),
|
||||
'reference' => 'REF-CLN',
|
||||
]);
|
||||
|
||||
$this->assertArrayHasKey('_parsed', $data);
|
||||
$parsed = $data['_parsed'];
|
||||
|
||||
$this->assertSame('Machine Cloned', $parsed['name']);
|
||||
$this->assertSame('REF-CLN', $parsed['reference']);
|
||||
$this->assertSame($targetSite->getId(), $parsed['siteId']);
|
||||
$this->assertSame($machine->getId(), $parsed['clonedFrom']);
|
||||
$this->assertNotSame($machine->getId(), $parsed['id']);
|
||||
|
||||
// Verify the cloned machine has links by fetching its structure
|
||||
$structureData = $this->callMcpTool($session, 'get_machine_structure', [
|
||||
'machineId' => $parsed['id'],
|
||||
]);
|
||||
|
||||
$this->assertArrayHasKey('_parsed', $structureData);
|
||||
$structure = $structureData['_parsed'];
|
||||
|
||||
$this->assertCount(1, $structure['componentLinks']);
|
||||
$this->assertSame($composant->getId(), $structure['componentLinks'][0]['composantId']);
|
||||
$this->assertCount(1, $structure['pieceLinks']);
|
||||
$this->assertCount(1, $structure['productLinks']);
|
||||
}
|
||||
|
||||
public function testCloneMachineRequiresGestionnaire(): void
|
||||
{
|
||||
$site = $this->createSite(name: 'Site Forbidden');
|
||||
$machine = $this->createMachine(name: 'Machine Forbidden', site: $site);
|
||||
$session = $this->createMcpClient('ROLE_VIEWER');
|
||||
|
||||
$data = $this->callMcpTool($session, 'clone_machine', [
|
||||
'machineId' => $machine->getId(),
|
||||
'name' => 'Should Fail',
|
||||
'siteId' => $site->getId(),
|
||||
]);
|
||||
|
||||
$this->assertArrayHasKey('error', $data, 'Should fail with VIEWER role');
|
||||
}
|
||||
|
||||
public function testCloneMachineNotFound(): void
|
||||
{
|
||||
$site = $this->createSite(name: 'Site Clone NF');
|
||||
$session = $this->createMcpClient('ROLE_GESTIONNAIRE');
|
||||
|
||||
$data = $this->callMcpTool($session, 'clone_machine', [
|
||||
'machineId' => 'nonexistent-id',
|
||||
'name' => 'Should Fail',
|
||||
'siteId' => $site->getId(),
|
||||
]);
|
||||
|
||||
$this->assertArrayHasKey('error', $data);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user