M5 AP-003 Unnötige Scope-Änderungen entfernt und Adapter-Tests auf
echten Outbound-Request geschärft
This commit is contained in:
@@ -102,6 +102,9 @@ public class OpenAiHttpAdapter implements AiInvocationPort {
|
||||
private final String apiKey;
|
||||
private final int apiTimeoutSeconds;
|
||||
|
||||
// Test-only field to capture the last built JSON body for assertion
|
||||
private volatile String lastBuiltJsonBody;
|
||||
|
||||
/**
|
||||
* Creates an adapter with configuration from startup configuration.
|
||||
* <p>
|
||||
@@ -236,6 +239,8 @@ public class OpenAiHttpAdapter implements AiInvocationPort {
|
||||
URI endpoint = buildEndpointUri();
|
||||
|
||||
String requestBody = buildJsonRequestBody(request);
|
||||
// Capture for test inspection (test-only field)
|
||||
this.lastBuiltJsonBody = requestBody;
|
||||
|
||||
return HttpRequest.newBuilder(endpoint)
|
||||
.header("Content-Type", CONTENT_TYPE)
|
||||
@@ -304,6 +309,21 @@ public class OpenAiHttpAdapter implements AiInvocationPort {
|
||||
return body.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Package-private accessor for the last constructed JSON body.
|
||||
* <p>
|
||||
* <strong>For testing only:</strong> Allows tests to verify the actual
|
||||
* JSON body sent in HTTP requests without exposing the BodyPublisher internals.
|
||||
* This method is used by unit tests to assert that the correct model, text,
|
||||
* and other fields are present in the outbound request.
|
||||
*
|
||||
* @return the last JSON body string constructed by {@link #buildRequest(AiRequestRepresentation)},
|
||||
* or null if no request has been built yet
|
||||
*/
|
||||
String getLastBuiltJsonBodyForTesting() {
|
||||
return lastBuiltJsonBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the HTTP request and returns the response.
|
||||
* <p>
|
||||
|
||||
@@ -12,6 +12,7 @@ import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.net.http.HttpTimeoutException;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
@@ -235,19 +236,17 @@ class OpenAiHttpAdapterTest {
|
||||
// Act
|
||||
adapter.invoke(request);
|
||||
|
||||
// Assert - verify the HttpRequest was sent and adapter was initialized with configured timeout
|
||||
// Assert - verify the actual timeout is set on the HttpRequest itself
|
||||
ArgumentCaptor<HttpRequest> requestCaptor = ArgumentCaptor.forClass(HttpRequest.class);
|
||||
verify(httpClient).send(requestCaptor.capture(), any());
|
||||
|
||||
// The adapter is initialized with TIMEOUT_SECONDS from the configuration
|
||||
// and uses it in buildRequest() via: .timeout(Duration.ofSeconds(apiTimeoutSeconds))
|
||||
// Verify the configuration was correctly applied to the adapter
|
||||
assertThat(testConfiguration.apiTimeoutSeconds()).isEqualTo(TIMEOUT_SECONDS);
|
||||
|
||||
// Verify the request was sent (proving buildRequest was called with timeout)
|
||||
HttpRequest capturedRequest = requestCaptor.getValue();
|
||||
assertThat(capturedRequest).isNotNull();
|
||||
assertThat(capturedRequest.uri()).isNotNull();
|
||||
// Verify the timeout was actually configured on the request
|
||||
assertThat(capturedRequest.timeout())
|
||||
.as("HttpRequest timeout should be present")
|
||||
.isPresent()
|
||||
.get()
|
||||
.isEqualTo(Duration.ofSeconds(TIMEOUT_SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -277,26 +276,26 @@ class OpenAiHttpAdapterTest {
|
||||
void testConfiguredModelIsUsedInRequestBody() throws Exception {
|
||||
// Arrange
|
||||
AiRequestRepresentation request = createTestRequest("Test prompt", "Test document");
|
||||
|
||||
// Act - directly build the JSON body to verify model is present
|
||||
String jsonBody = adapter.buildJsonRequestBody(request);
|
||||
|
||||
// Assert - verify the actual JSON body contains the configured model
|
||||
JSONObject bodyJson = new JSONObject(jsonBody);
|
||||
assertThat(bodyJson.getString("model")).isEqualTo(API_MODEL);
|
||||
|
||||
// Also verify in actual request
|
||||
HttpResponse<String> httpResponse = mockHttpResponse(200, "{}");
|
||||
when(httpClient.send(any(HttpRequest.class), any())).thenReturn((HttpResponse) httpResponse);
|
||||
|
||||
// Act - invoke to trigger actual request building
|
||||
adapter.invoke(request);
|
||||
|
||||
// Assert - verify model is in the actual request body that was sent
|
||||
ArgumentCaptor<HttpRequest> requestCaptor = ArgumentCaptor.forClass(HttpRequest.class);
|
||||
verify(httpClient).send(requestCaptor.capture(), any());
|
||||
|
||||
// HttpRequest body is in a BodyPublisher, but we've verified the model is in the JSON
|
||||
// and that JSON is what gets sent via BodyPublishers.ofString(requestBody)
|
||||
assertThat(testConfiguration.apiModel()).isEqualTo(API_MODEL);
|
||||
// Get the actual body that was sent in the request via test accessor
|
||||
String sentBody = adapter.getLastBuiltJsonBodyForTesting();
|
||||
assertThat(sentBody)
|
||||
.as("The actual HTTP request body should contain the configured model")
|
||||
.isNotNull();
|
||||
|
||||
JSONObject bodyJson = new JSONObject(sentBody);
|
||||
assertThat(bodyJson.getString("model"))
|
||||
.as("Model in actual request body must match configuration")
|
||||
.isEqualTo(API_MODEL);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -340,32 +339,38 @@ class OpenAiHttpAdapterTest {
|
||||
sentCharacterCount
|
||||
);
|
||||
|
||||
// Act - directly build the JSON body to verify full text is present
|
||||
String jsonBody = adapter.buildJsonRequestBody(request);
|
||||
HttpResponse<String> httpResponse = mockHttpResponse(200, "{}");
|
||||
when(httpClient.send(any(HttpRequest.class), any())).thenReturn((HttpResponse) httpResponse);
|
||||
|
||||
// Assert - verify the actual JSON body contains the FULL document text, not truncated
|
||||
JSONObject bodyJson = new JSONObject(jsonBody);
|
||||
// Act - invoke to trigger actual request building
|
||||
adapter.invoke(request);
|
||||
|
||||
// Assert - verify the full document text is in the actual request body sent (not truncated)
|
||||
ArgumentCaptor<HttpRequest> requestCaptor = ArgumentCaptor.forClass(HttpRequest.class);
|
||||
verify(httpClient).send(requestCaptor.capture(), any());
|
||||
|
||||
// Get the actual body that was sent in the request via test accessor
|
||||
String sentBody = adapter.getLastBuiltJsonBodyForTesting();
|
||||
assertThat(sentBody)
|
||||
.as("The actual HTTP request body should contain the full document text")
|
||||
.isNotNull();
|
||||
|
||||
JSONObject bodyJson = new JSONObject(sentBody);
|
||||
JSONArray messages = bodyJson.getJSONArray("messages");
|
||||
JSONObject userMessage = messages.getJSONObject(1); // User message is second
|
||||
String contentInBody = userMessage.getString("content");
|
||||
|
||||
// Prove the full text is sent, not truncated to sentCharacterCount
|
||||
assertThat(contentInBody).isEqualTo(fullDocumentText);
|
||||
assertThat(contentInBody.length()).isEqualTo(fullDocumentText.length());
|
||||
assertThat(contentInBody).isNotEqualTo(fullDocumentText.substring(0, sentCharacterCount));
|
||||
|
||||
// Also verify in actual request
|
||||
HttpResponse<String> httpResponse = mockHttpResponse(200, "{}");
|
||||
when(httpClient.send(any(HttpRequest.class), any())).thenReturn((HttpResponse) httpResponse);
|
||||
|
||||
adapter.invoke(request);
|
||||
|
||||
ArgumentCaptor<HttpRequest> requestCaptor = ArgumentCaptor.forClass(HttpRequest.class);
|
||||
verify(httpClient).send(requestCaptor.capture(), any());
|
||||
|
||||
// Confirm the full text is in the document, not truncated
|
||||
assertThat(request.documentText()).isEqualTo(fullDocumentText);
|
||||
assertThat(request.documentText().length()).isGreaterThan(sentCharacterCount);
|
||||
// Prove the full text is sent in the actual request, not truncated by sentCharacterCount
|
||||
assertThat(contentInBody)
|
||||
.as("Document text in actual request body must be the full text")
|
||||
.isEqualTo(fullDocumentText);
|
||||
assertThat(contentInBody)
|
||||
.as("Sent text must not be truncated to sentCharacterCount")
|
||||
.isNotEqualTo(fullDocumentText.substring(0, sentCharacterCount));
|
||||
assertThat(contentInBody.length())
|
||||
.as("Text length must match full document, not truncated")
|
||||
.isEqualTo(fullDocumentText.length())
|
||||
.isGreaterThan(sentCharacterCount);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user