22
33namespace 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 ;
59use KLP \KlpMcpServer \Protocol \Handlers \RequestHandler ;
10+ use KLP \KlpMcpServer \Protocol \MCPProtocol ;
611use KLP \KlpMcpServer \Protocol \MCPProtocolInterface ;
712use KLP \KlpMcpServer \Server \MCPServer ;
13+ use KLP \KlpMcpServer \Server \Request \ToolsCallHandler ;
14+ use KLP \KlpMcpServer \Server \Request \ToolsListHandler ;
815use KLP \KlpMcpServer \Server \ServerCapabilitiesInterface ;
16+ use KLP \KlpMcpServer \Services \ToolService \ToolRepository ;
17+ use PHPUnit \Framework \Attributes \Small ;
918use PHPUnit \Framework \TestCase ;
1019use ReflectionClass ;
1120
21+ #[Small]
1222class 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