@@ -157,6 +157,102 @@ public void vertexAiGeminiChatWithEmptyResponse() throws Exception {
157157 assertThat (this .retryListener .onErrorRetryCount ).isEqualTo (1 );
158158 }
159159
160+ @ Test
161+ public void vertexAiGeminiChatMaxRetriesExceeded () throws Exception {
162+ // Test that after max retries, the exception is propagated
163+ given (this .mockGenerativeModel .generateContent (any (List .class )))
164+ .willThrow (new TransientAiException ("Persistent Error" ))
165+ .willThrow (new TransientAiException ("Persistent Error" ))
166+ .willThrow (new TransientAiException ("Persistent Error" ))
167+ .willThrow (new TransientAiException ("Persistent Error" ));
168+
169+ // Should throw the last TransientAiException after exhausting retries
170+ assertThrows (TransientAiException .class , () -> this .chatModel .call (new Prompt ("test prompt" )));
171+
172+ // Verify retry attempts were made
173+ assertThat (this .retryListener .onErrorRetryCount ).isGreaterThan (0 );
174+ }
175+
176+ @ Test
177+ public void vertexAiGeminiChatWithMultipleCandidatesResponse () throws Exception {
178+ // Test response with multiple candidates
179+ GenerateContentResponse multiCandidateResponse = GenerateContentResponse .newBuilder ()
180+ .addCandidates (Candidate .newBuilder ()
181+ .setContent (Content .newBuilder ().addParts (Part .newBuilder ().setText ("First candidate" ).build ()).build ())
182+ .build ())
183+ .addCandidates (Candidate .newBuilder ()
184+ .setContent (
185+ Content .newBuilder ().addParts (Part .newBuilder ().setText ("Second candidate" ).build ()).build ())
186+ .build ())
187+ .build ();
188+
189+ given (this .mockGenerativeModel .generateContent (any (List .class )))
190+ .willThrow (new TransientAiException ("Temporary failure" ))
191+ .willReturn (multiCandidateResponse );
192+
193+ ChatResponse result = this .chatModel .call (new Prompt ("test prompt" ));
194+
195+ assertThat (result ).isNotNull ();
196+ // Assuming the implementation uses the first candidate
197+ assertThat (result .getResult ().getOutput ().getText ()).isEqualTo ("First candidate" );
198+ assertThat (this .retryListener .onSuccessRetryCount ).isEqualTo (1 );
199+ }
200+
201+ @ Test
202+ public void vertexAiGeminiChatWithNullPrompt () throws Exception {
203+ // Test handling of null prompt
204+ Prompt prompt = null ;
205+ assertThrows (Exception .class , () -> this .chatModel .call (prompt ));
206+
207+ // Should not trigger any retries for validation errors
208+ assertThat (this .retryListener .onErrorRetryCount ).isEqualTo (0 );
209+ assertThat (this .retryListener .onSuccessRetryCount ).isEqualTo (0 );
210+ }
211+
212+ @ Test
213+ public void vertexAiGeminiChatWithEmptyPrompt () throws Exception {
214+ // Test handling of empty prompt
215+ GenerateContentResponse mockedResponse = GenerateContentResponse .newBuilder ()
216+ .addCandidates (Candidate .newBuilder ()
217+ .setContent (Content .newBuilder ()
218+ .addParts (Part .newBuilder ().setText ("Response to empty prompt" ).build ())
219+ .build ())
220+ .build ())
221+ .build ();
222+
223+ given (this .mockGenerativeModel .generateContent (any (List .class ))).willReturn (mockedResponse );
224+
225+ ChatResponse result = this .chatModel .call (new Prompt ("" ));
226+
227+ assertThat (result ).isNotNull ();
228+ assertThat (result .getResult ().getOutput ().getText ()).isEqualTo ("Response to empty prompt" );
229+ assertThat (this .retryListener .onSuccessRetryCount ).isEqualTo (0 );
230+ }
231+
232+ @ Test
233+ public void vertexAiGeminiChatAlternatingErrorsAndSuccess () throws Exception {
234+ // Test pattern of error -> success -> error -> success
235+ GenerateContentResponse successResponse = GenerateContentResponse .newBuilder ()
236+ .addCandidates (Candidate .newBuilder ()
237+ .setContent (Content .newBuilder ()
238+ .addParts (Part .newBuilder ().setText ("Success after alternating errors" ).build ())
239+ .build ())
240+ .build ())
241+ .build ();
242+
243+ given (this .mockGenerativeModel .generateContent (any (List .class )))
244+ .willThrow (new TransientAiException ("First error" ))
245+ .willThrow (new TransientAiException ("Second error" ))
246+ .willReturn (successResponse );
247+
248+ ChatResponse result = this .chatModel .call (new Prompt ("test prompt" ));
249+
250+ assertThat (result ).isNotNull ();
251+ assertThat (result .getResult ().getOutput ().getText ()).isEqualTo ("Success after alternating errors" );
252+ assertThat (this .retryListener .onSuccessRetryCount ).isEqualTo (2 );
253+ assertThat (this .retryListener .onErrorRetryCount ).isEqualTo (2 );
254+ }
255+
160256 private static class TestRetryListener implements RetryListener {
161257
162258 int onErrorRetryCount = 0 ;
0 commit comments