1+ /*
2+ * Copyright 2024 - 2024 the original author or authors.
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * https://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+ package spring .ai .experimental .mcp .client .stdio ;
17+
18+ import java .io .BufferedReader ;
19+ import java .io .BufferedWriter ;
20+ import java .io .IOException ;
21+ import java .io .InputStream ;
22+ import java .io .OutputStream ;
23+ import java .util .HashMap ;
24+ import java .util .List ;
25+ import java .util .Map ;
26+
27+ import com .fasterxml .jackson .databind .ObjectMapper ;
28+ import org .junit .jupiter .api .BeforeEach ;
29+ import org .junit .jupiter .api .Test ;
30+ import org .mockito .Mock ;
31+ import org .mockito .MockitoAnnotations ;
32+
33+ import static org .assertj .core .api .Assertions .assertThat ;
34+ import static org .junit .jupiter .api .Assertions .assertThrows ;
35+ import static org .mockito .Mockito .mock ;
36+ import static org .mockito .Mockito .verify ;
37+ import static org .mockito .Mockito .when ;
38+
39+ /**
40+ * @author Christian Tzolov
41+ *
42+ */
43+ public class StdioServerTransportTests {
44+
45+ @ Mock
46+ private ServerParameters mockParams ;
47+
48+ @ Mock
49+ private Process mockProcess ;
50+
51+ @ Mock
52+ private BufferedReader mockErrorReader ;
53+
54+ @ Mock
55+ private BufferedReader mockReader ;
56+
57+ @ Mock
58+ private BufferedWriter mockWriter ;
59+
60+ @ Mock
61+ ProcessBuilder mockProcessBuilder ;
62+
63+ private StdioServerTransport stdioServerTransport ;
64+
65+ @ BeforeEach
66+ public void setUp () {
67+ MockitoAnnotations .openMocks (this );
68+ when (mockParams .getCommand ()).thenReturn ("dummyCommand" );
69+ when (mockParams .getArgs ()).thenReturn (List .of ("arg1" , "arg2" ));
70+ when (mockParams .getEnv ()).thenReturn (new HashMap <>(Map .of ("key" , "value" )));
71+ stdioServerTransport = new StdioServerTransport (mockParams , new ObjectMapper ()) {
72+ @ Override
73+ protected ProcessBuilder getProcessBuilder () {
74+ return mockProcessBuilder ;
75+ }
76+ };
77+ }
78+
79+ @ Test
80+ public void testStart_Success () throws IOException {
81+ // Arrange
82+ when (mockProcessBuilder .start ()).thenReturn (mockProcess );
83+ when (mockProcess .getInputStream ()).thenReturn (mock (InputStream .class ));
84+ when (mockProcess .getOutputStream ()).thenReturn (mock (OutputStream .class ));
85+ when (mockProcess .errorReader ()).thenReturn (mockErrorReader );
86+ when (mockProcess .inputReader ()).thenReturn (mockReader );
87+ when (mockProcess .outputWriter ()).thenReturn (mockWriter );
88+
89+ // Act
90+ stdioServerTransport .start ();
91+
92+ // Assert
93+ // TODO: assertThat(stdioServerTransport.isRunning).isTrue();
94+ verify (mockProcessBuilder ).start ();
95+ }
96+
97+ @ Test
98+ public void testStart_ProcessStartFailure () throws IOException {
99+ // Arrange
100+ when (mockProcessBuilder .start ()).thenThrow (new IOException ("Failed to start process" ));
101+
102+ // Act & Assert
103+ RuntimeException exception = assertThrows (RuntimeException .class , () -> stdioServerTransport .start ());
104+ assertThat (exception .getMessage ()).contains ("Failed to start process with command" );
105+ }
106+
107+ @ Test
108+ public void testStart_NullInputStream () throws IOException {
109+ // Arrange
110+ when (mockProcessBuilder .start ()).thenReturn (mockProcess );
111+ when (mockProcess .getInputStream ()).thenReturn (null );
112+ when (mockProcess .getOutputStream ()).thenReturn (mock (OutputStream .class ));
113+
114+ // Act & Assert
115+ RuntimeException exception = assertThrows (RuntimeException .class , () -> stdioServerTransport .start ());
116+ assertThat (exception .getMessage ()).contains ("Process input or output stream is null" );
117+ verify (mockProcess ).destroy ();
118+ }
119+
120+ @ Test
121+ public void testStart_NullOutputStream () throws IOException {
122+ // Arrange
123+ when (mockProcessBuilder .start ()).thenReturn (mockProcess );
124+ when (mockProcess .getInputStream ()).thenReturn (mock (InputStream .class ));
125+ when (mockProcess .getOutputStream ()).thenReturn (null );
126+
127+ // Act & Assert
128+ RuntimeException exception = assertThrows (RuntimeException .class , () -> stdioServerTransport .start ());
129+ assertThat (exception .getMessage ()).contains ("Process input or output stream is null" );
130+ verify (mockProcess ).destroy ();
131+ }
132+ }
0 commit comments