Skip to content

Commit 4c8f870

Browse files
author
klapaudius
committed
Add and enhance MCPServer test coverage
Added unit tests for MCPServer methods, including tool repository registration, connection handling, notification handling, and initialization logic. These tests improve coverage, verify proper functionality, and ensure correct error handling.
1 parent c390e74 commit 4c8f870

File tree

1 file changed

+212
-3
lines changed

1 file changed

+212
-3
lines changed

tests/Server/MCPServerTest.php

Lines changed: 212 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,70 @@
22

33
namespace KLP\KlpMcpServer\Tests\Server;
44

5+
use KLP\KlpMcpServer\Data\Requests\InitializeData;
6+
use KLP\KlpMcpServer\Data\Resources\InitializeResource;
7+
use KLP\KlpMcpServer\Exceptions\JsonRpcErrorException;
8+
use KLP\KlpMcpServer\Protocol\Handlers\NotificationHandler;
59
use KLP\KlpMcpServer\Protocol\Handlers\RequestHandler;
10+
use KLP\KlpMcpServer\Protocol\MCPProtocol;
611
use KLP\KlpMcpServer\Protocol\MCPProtocolInterface;
712
use KLP\KlpMcpServer\Server\MCPServer;
13+
use KLP\KlpMcpServer\Server\Request\ToolsCallHandler;
14+
use KLP\KlpMcpServer\Server\Request\ToolsListHandler;
815
use KLP\KlpMcpServer\Server\ServerCapabilitiesInterface;
16+
use KLP\KlpMcpServer\Services\ToolService\ToolRepository;
17+
use PHPUnit\Framework\Attributes\Small;
918
use PHPUnit\Framework\TestCase;
1019
use ReflectionClass;
1120

21+
#[Small]
1222
class MCPServerTest extends TestCase
1323
{
14-
public function test_register_request_handler(): void
24+
public function testRegisterToolRepository(): void
25+
{
26+
// Arrange
27+
$mockProtocol = $this->createMock(MCPProtocolInterface::class);
28+
$mockToolRepository = $this->createMock(ToolRepository::class);
29+
30+
$invocations = [
31+
new ToolsListHandler($mockToolRepository),
32+
new ToolsCallHandler($mockToolRepository)
33+
];
34+
$mockProtocol->expects($matcher = $this->exactly(count($invocations)))
35+
->method('registerRequestHandler')
36+
->with($this->callback(function ($arg) use (&$invocations, $matcher) {
37+
$this->assertEquals($invocations[$matcher->numberOfInvocations()-1], $arg);
38+
return true;
39+
}));
40+
41+
$server = new ReflectionClass(MCPServer::class);
42+
$instance = $server->newInstanceWithoutConstructor();
43+
$server->getProperty('protocol')->setValue($instance, $mockProtocol);
44+
45+
// Act
46+
$instance->registerToolRepository($mockToolRepository);
47+
48+
// Assert: Expectations set on the mock protocol are automatically verified.
49+
}
50+
51+
public function testRegisterToolRepositoryReturnsInstance(): void
52+
{
53+
// Arrange
54+
$mockProtocol = $this->createMock(MCPProtocolInterface::class);
55+
$mockToolRepository = $this->createMock(ToolRepository::class);
56+
57+
$server = new ReflectionClass(MCPServer::class);
58+
$instance = $server->newInstanceWithoutConstructor();
59+
$server->getProperty('protocol')->setValue($instance, $mockProtocol);
60+
61+
// Act
62+
$result = $instance->registerToolRepository($mockToolRepository);
63+
64+
// Assert
65+
$this->assertSame($instance, $result);
66+
}
67+
68+
public function testRegisterRequestHandler(): void
1569
{
1670
// Arrange
1771
$mockProtocol = $this->createMock(MCPProtocolInterface::class);
@@ -30,7 +84,7 @@ public function test_register_request_handler(): void
3084
// Assert: Expectations set on the mock objects are automatically verified
3185
}
3286

33-
public function test_create(): void
87+
public function testCreate(): void
3488
{
3589
// Arrange
3690
$mockProtocol = $this->createMock(MCPProtocolInterface::class);
@@ -46,7 +100,7 @@ public function test_create(): void
46100
$this->assertSame(['name' => $name, 'version' => $version], $this->getPrivateProperty($server, 'serverInfo'));
47101
}
48102

49-
public function test_create_with_capabilities(): void
103+
public function testCreateWithCapabilities(): void
50104
{
51105
// Arrange
52106
$mockProtocol = $this->createMock(MCPProtocolInterface::class);
@@ -72,4 +126,159 @@ private function getPrivateProperty(object $object, string $property)
72126

73127
return $prop->getValue($object);
74128
}
129+
130+
public function testConnect(): void
131+
{
132+
// Arrange
133+
$mockProtocol = $this->createMock(MCPProtocolInterface::class);
134+
135+
$mockProtocol->expects($this->once())
136+
->method('connect');
137+
138+
$server = new ReflectionClass(MCPServer::class);
139+
$instance = $server->newInstanceWithoutConstructor();
140+
$server->getProperty('protocol')->setValue($instance, $mockProtocol);
141+
142+
// Act
143+
$instance->connect();
144+
145+
// Assert: Expectations set on the mock objects are automatically verified.
146+
}
147+
148+
public function testDisconnect(): void
149+
{
150+
// Arrange
151+
$mockProtocol = $this->createMock(MCPProtocolInterface::class);
152+
153+
$mockProtocol->expects($this->once())
154+
->method('disconnect');
155+
156+
$server = new ReflectionClass(MCPServer::class);
157+
$instance = $server->newInstanceWithoutConstructor();
158+
$server->getProperty('protocol')->setValue($instance, $mockProtocol);
159+
160+
// Act
161+
$instance->disconnect();
162+
163+
// Assert: Expectations set on the mock objects are automatically verified.
164+
}
165+
166+
public function testRegisterNotificationHandler(): void
167+
{
168+
// Arrange
169+
$mockProtocol = $this->createMock(MCPProtocolInterface::class);
170+
$mockHandler = $this->createMock(NotificationHandler::class);
171+
172+
$mockProtocol->expects($this->once())
173+
->method('registerNotificationHandler')
174+
->with($mockHandler);
175+
176+
$server = new ReflectionClass(MCPServer::class);
177+
$instance = $server->newInstanceWithoutConstructor();
178+
$server->getProperty('protocol')->setValue($instance, $mockProtocol);
179+
180+
// Act
181+
$instance->registerNotificationHandler($mockHandler);
182+
183+
// Assert: Expectations set on the mock objects are automatically verified.
184+
}
185+
186+
public function testRequestMessage(): void
187+
{
188+
// Arrange
189+
$mockProtocol = $this->createMock(MCPProtocolInterface::class);
190+
$clientId = 'some-client-id';
191+
$message = ['method' => 'testMethod', 'params' => ['key' => 'value']];
192+
193+
$mockProtocol->expects($this->once())
194+
->method('requestMessage')
195+
->with($clientId, $message);
196+
197+
$server = new ReflectionClass(MCPServer::class);
198+
$instance = $server->newInstanceWithoutConstructor();
199+
$server->getProperty('protocol')->setValue($instance, $mockProtocol);
200+
201+
// Act
202+
$instance->requestMessage($clientId, $message);
203+
204+
// Assert: Expectations set on the mock objects are automatically verified.
205+
}
206+
207+
/**
208+
* Tests that the initialize method correctly sets the client capabilities,
209+
* assigns the protocol version, and marks the server as initialized.
210+
*/
211+
public function testInitializeSetsCapabilitiesAndMarksInitialized(): void
212+
{
213+
// Arrange
214+
$mockProtocol = $this->createMock(MCPProtocolInterface::class);
215+
$serverInfo = ['name' => 'TestServer', 'version' => '1.0'];
216+
$mockCapabilities = $this->createMock(ServerCapabilitiesInterface::class);
217+
$mockCapabilities->expects($this->once())
218+
->method('toArray')
219+
->willReturn(['mock-capability' => true]);
220+
221+
$server = MCPServer::create($mockProtocol, $serverInfo['name'], $serverInfo['version'], $mockCapabilities);
222+
$initializeData = new InitializeData('2.0', ['mock-capability' => true]);
223+
224+
// Act
225+
$initializeResource = $server->initialize($initializeData);
226+
227+
// Assert
228+
$this->assertTrue($this->getPrivateProperty($server, 'initialized'));
229+
$this->assertSame(['mock-capability' => true], $this->getPrivateProperty($server, 'clientCapabilities'));
230+
$this->assertEquals(MCPProtocol::PROTOCOL_VERSION, $initializeResource->protocolVersion);
231+
$this->assertSame($serverInfo, $initializeResource->serverInfo);
232+
}
233+
234+
/**
235+
* Tests that the initialize method throws an exception if the server
236+
* has already been initialized.
237+
*/
238+
public function testInitializeThrowsWhenAlreadyInitialized(): void
239+
{
240+
// Arrange
241+
$mockProtocol = $this->createMock(MCPProtocolInterface::class);
242+
$serverInfo = ['name' => 'TestServer', 'version' => '1.0'];
243+
$mockCapabilities = $this->createMock(ServerCapabilitiesInterface::class);
244+
245+
$server = MCPServer::create($mockProtocol, $serverInfo['name'], $serverInfo['version'], $mockCapabilities);
246+
$initializeData = new InitializeData('2.0', ['mock-capability' => true]);
247+
248+
$server->initialize($initializeData);
249+
250+
// Expect
251+
$this->expectException(JsonRpcErrorException::class);
252+
$this->expectExceptionMessage('Server already initialized');
253+
254+
// Act
255+
$server->initialize($initializeData);
256+
}
257+
258+
/**
259+
* Tests that the initialize method returns a correctly constructed
260+
* InitializeResource object with expected values.
261+
*/
262+
public function testInitializeReturnsCorrectResource(): void
263+
{
264+
// Arrange
265+
$mockProtocol = $this->createMock(MCPProtocolInterface::class);
266+
$serverInfo = ['name' => 'TestServer', 'version' => '1.0'];
267+
$mockCapabilities = $this->createMock(ServerCapabilitiesInterface::class);
268+
$mockCapabilities->expects($this->once())
269+
->method('toArray')
270+
->willReturn(['mock-capability' => true]);
271+
272+
$server = MCPServer::create($mockProtocol, $serverInfo['name'], $serverInfo['version'], $mockCapabilities);
273+
$initializeData = new InitializeData('2024-11-05', ['mock-capability' => true]);
274+
275+
// Act
276+
$initializeResource = $server->initialize($initializeData);
277+
278+
// Assert
279+
$this->assertInstanceOf(InitializeResource::class, $initializeResource);
280+
$this->assertEquals('2024-11-05', $initializeResource->protocolVersion);
281+
$this->assertSame(['mock-capability' => true], $initializeResource->capabilities);
282+
$this->assertEquals($serverInfo, $initializeResource->serverInfo);
283+
}
75284
}

0 commit comments

Comments
 (0)