diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/ContainerServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/ContainerServiceAsyncImpl.kt index 38e95900c..6f5d6a668 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/ContainerServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/ContainerServiceAsyncImpl.kt @@ -74,7 +74,7 @@ class ContainerServiceAsyncImpl internal constructor(private val clientOptions: requestOptions: RequestOptions, ): CompletableFuture = // delete /containers/{container_id} - withRawResponse().delete(params, requestOptions).thenAccept {} + withRawResponse().delete(params, requestOptions).thenAccept { it.close() } class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : ContainerServiceAsync.WithRawResponse { diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/ResponseServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/ResponseServiceAsyncImpl.kt index 8a38b0adb..03902d3ca 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/ResponseServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/ResponseServiceAsyncImpl.kt @@ -104,7 +104,7 @@ class ResponseServiceAsyncImpl internal constructor(private val clientOptions: C requestOptions: RequestOptions, ): CompletableFuture = // delete /responses/{response_id} - withRawResponse().delete(params, requestOptions).thenAccept {} + withRawResponse().delete(params, requestOptions).thenAccept { it.close() } override fun cancel( params: ResponseCancelParams, diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/containers/FileServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/containers/FileServiceAsyncImpl.kt index f68071ed5..6b197ccff 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/containers/FileServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/containers/FileServiceAsyncImpl.kt @@ -75,7 +75,7 @@ class FileServiceAsyncImpl internal constructor(private val clientOptions: Clien requestOptions: RequestOptions, ): CompletableFuture = // delete /containers/{container_id}/files/{file_id} - withRawResponse().delete(params, requestOptions).thenAccept {} + withRawResponse().delete(params, requestOptions).thenAccept { it.close() } class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : FileServiceAsync.WithRawResponse { diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/realtime/CallServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/realtime/CallServiceAsyncImpl.kt index a06552be7..e9ba45b03 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/realtime/CallServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/realtime/CallServiceAsyncImpl.kt @@ -41,28 +41,28 @@ class CallServiceAsyncImpl internal constructor(private val clientOptions: Clien requestOptions: RequestOptions, ): CompletableFuture = // post /realtime/calls/{call_id}/accept - withRawResponse().accept(params, requestOptions).thenAccept {} + withRawResponse().accept(params, requestOptions).thenAccept { it.close() } override fun hangup( params: CallHangupParams, requestOptions: RequestOptions, ): CompletableFuture = // post /realtime/calls/{call_id}/hangup - withRawResponse().hangup(params, requestOptions).thenAccept {} + withRawResponse().hangup(params, requestOptions).thenAccept { it.close() } override fun refer( params: CallReferParams, requestOptions: RequestOptions, ): CompletableFuture = // post /realtime/calls/{call_id}/refer - withRawResponse().refer(params, requestOptions).thenAccept {} + withRawResponse().refer(params, requestOptions).thenAccept { it.close() } override fun reject( params: CallRejectParams, requestOptions: RequestOptions, ): CompletableFuture = // post /realtime/calls/{call_id}/reject - withRawResponse().reject(params, requestOptions).thenAccept {} + withRawResponse().reject(params, requestOptions).thenAccept { it.close() } class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : CallServiceAsync.WithRawResponse { diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/ContainerServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/ContainerServiceImpl.kt index f1f839ac0..02ddf1d26 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/ContainerServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/ContainerServiceImpl.kt @@ -70,7 +70,7 @@ class ContainerServiceImpl internal constructor(private val clientOptions: Clien override fun delete(params: ContainerDeleteParams, requestOptions: RequestOptions) { // delete /containers/{container_id} - withRawResponse().delete(params, requestOptions) + withRawResponse().delete(params, requestOptions).close() } class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/ResponseServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/ResponseServiceImpl.kt index 6fd9eda32..de1795f18 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/ResponseServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/ResponseServiceImpl.kt @@ -85,7 +85,7 @@ class ResponseServiceImpl internal constructor(private val clientOptions: Client override fun delete(params: ResponseDeleteParams, requestOptions: RequestOptions) { // delete /responses/{response_id} - withRawResponse().delete(params, requestOptions) + withRawResponse().delete(params, requestOptions).close() } override fun cancel(params: ResponseCancelParams, requestOptions: RequestOptions): Response = diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/containers/FileServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/containers/FileServiceImpl.kt index 682db828e..f1702ebfe 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/containers/FileServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/containers/FileServiceImpl.kt @@ -67,7 +67,7 @@ class FileServiceImpl internal constructor(private val clientOptions: ClientOpti override fun delete(params: FileDeleteParams, requestOptions: RequestOptions) { // delete /containers/{container_id}/files/{file_id} - withRawResponse().delete(params, requestOptions) + withRawResponse().delete(params, requestOptions).close() } class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/realtime/CallServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/realtime/CallServiceImpl.kt index 213d1afec..5ad138887 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/realtime/CallServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/realtime/CallServiceImpl.kt @@ -36,22 +36,22 @@ class CallServiceImpl internal constructor(private val clientOptions: ClientOpti override fun accept(params: CallAcceptParams, requestOptions: RequestOptions) { // post /realtime/calls/{call_id}/accept - withRawResponse().accept(params, requestOptions) + withRawResponse().accept(params, requestOptions).close() } override fun hangup(params: CallHangupParams, requestOptions: RequestOptions) { // post /realtime/calls/{call_id}/hangup - withRawResponse().hangup(params, requestOptions) + withRawResponse().hangup(params, requestOptions).close() } override fun refer(params: CallReferParams, requestOptions: RequestOptions) { // post /realtime/calls/{call_id}/refer - withRawResponse().refer(params, requestOptions) + withRawResponse().refer(params, requestOptions).close() } override fun reject(params: CallRejectParams, requestOptions: RequestOptions) { // post /realtime/calls/{call_id}/reject - withRawResponse().reject(params, requestOptions) + withRawResponse().reject(params, requestOptions).close() } class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : diff --git a/openai-java-core/src/test/kotlin/com/openai/services/HighLevelUnitMethodsCloseResponseTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/HighLevelUnitMethodsCloseResponseTest.kt new file mode 100644 index 000000000..239af34d0 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/services/HighLevelUnitMethodsCloseResponseTest.kt @@ -0,0 +1,211 @@ +package com.openai.services + +import com.openai.core.ClientOptions +import com.openai.core.http.Headers +import com.openai.core.http.HttpClient +import com.openai.core.http.HttpResponse +import com.openai.models.containers.ContainerDeleteParams +import com.openai.models.containers.files.FileDeleteParams +import com.openai.models.realtime.RealtimeSessionCreateRequest +import com.openai.models.realtime.calls.CallAcceptParams +import com.openai.models.realtime.calls.CallHangupParams +import com.openai.models.realtime.calls.CallReferParams +import com.openai.models.realtime.calls.CallRejectParams +import com.openai.models.responses.ResponseDeleteParams +import com.openai.services.async.ContainerServiceAsyncImpl +import com.openai.services.async.ResponseServiceAsyncImpl +import com.openai.services.async.containers.FileServiceAsyncImpl +import com.openai.services.async.realtime.CallServiceAsyncImpl +import com.openai.services.blocking.ContainerServiceImpl +import com.openai.services.blocking.ResponseServiceImpl +import com.openai.services.blocking.containers.FileServiceImpl +import com.openai.services.blocking.realtime.CallServiceImpl +import java.util.concurrent.CompletableFuture +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@ExtendWith(MockitoExtension::class) +internal class HighLevelUnitMethodsCloseResponseTest { + + @Test + fun containerDelete_closesSuccessfulBlockingResponse() { + assertBlockingResponseClosed { options -> + ContainerServiceImpl(options) + .delete(ContainerDeleteParams.builder().containerId("container_id").build()) + } + } + + @Test + fun responseDelete_closesSuccessfulBlockingResponse() { + assertBlockingResponseClosed { options -> + ResponseServiceImpl(options) + .delete(ResponseDeleteParams.builder().responseId("response_id").build()) + } + } + + @Test + fun containerFileDelete_closesSuccessfulBlockingResponse() { + assertBlockingResponseClosed { options -> + FileServiceImpl(options) + .delete( + FileDeleteParams.builder().containerId("container_id").fileId("file_id").build() + ) + } + } + + @Test + fun realtimeCallAccept_closesSuccessfulBlockingResponse() { + assertBlockingResponseClosed { options -> + CallServiceImpl(options) + .accept( + CallAcceptParams.builder() + .callId("call_id") + .realtimeSessionCreateRequest( + RealtimeSessionCreateRequest.builder().build() + ) + .build() + ) + } + } + + @Test + fun realtimeCallHangup_closesSuccessfulBlockingResponse() { + assertBlockingResponseClosed { options -> + CallServiceImpl(options).hangup(CallHangupParams.builder().callId("call_id").build()) + } + } + + @Test + fun realtimeCallRefer_closesSuccessfulBlockingResponse() { + assertBlockingResponseClosed { options -> + CallServiceImpl(options) + .refer( + CallReferParams.builder() + .callId("call_id") + .targetUri("tel:+14155550123") + .build() + ) + } + } + + @Test + fun realtimeCallReject_closesSuccessfulBlockingResponse() { + assertBlockingResponseClosed { options -> + CallServiceImpl(options) + .reject(CallRejectParams.builder().callId("call_id").statusCode(486L).build()) + } + } + + @Test + fun containerDelete_closesSuccessfulAsyncResponse() { + assertAsyncResponseClosed { options -> + ContainerServiceAsyncImpl(options) + .delete(ContainerDeleteParams.builder().containerId("container_id").build()) + } + } + + @Test + fun responseDelete_closesSuccessfulAsyncResponse() { + assertAsyncResponseClosed { options -> + ResponseServiceAsyncImpl(options) + .delete(ResponseDeleteParams.builder().responseId("response_id").build()) + } + } + + @Test + fun containerFileDelete_closesSuccessfulAsyncResponse() { + assertAsyncResponseClosed { options -> + FileServiceAsyncImpl(options) + .delete( + FileDeleteParams.builder().containerId("container_id").fileId("file_id").build() + ) + } + } + + @Test + fun realtimeCallAccept_closesSuccessfulAsyncResponse() { + assertAsyncResponseClosed { options -> + CallServiceAsyncImpl(options) + .accept( + CallAcceptParams.builder() + .callId("call_id") + .realtimeSessionCreateRequest( + RealtimeSessionCreateRequest.builder().build() + ) + .build() + ) + } + } + + @Test + fun realtimeCallHangup_closesSuccessfulAsyncResponse() { + assertAsyncResponseClosed { options -> + CallServiceAsyncImpl(options) + .hangup(CallHangupParams.builder().callId("call_id").build()) + } + } + + @Test + fun realtimeCallRefer_closesSuccessfulAsyncResponse() { + assertAsyncResponseClosed { options -> + CallServiceAsyncImpl(options) + .refer( + CallReferParams.builder() + .callId("call_id") + .targetUri("tel:+14155550123") + .build() + ) + } + } + + @Test + fun realtimeCallReject_closesSuccessfulAsyncResponse() { + assertAsyncResponseClosed { options -> + CallServiceAsyncImpl(options) + .reject(CallRejectParams.builder().callId("call_id").statusCode(486L).build()) + } + } + + private fun assertBlockingResponseClosed(call: (ClientOptions) -> Unit) { + val httpClient = mock() + val response = mockResponse() + doReturn(response).whenever(httpClient).execute(any(), any()) + + call(clientOptions(httpClient)) + + verify(response, times(1)).close() + } + + private fun assertAsyncResponseClosed(call: (ClientOptions) -> CompletableFuture) { + val httpClient = mock() + val response = mockResponse() + doReturn(CompletableFuture.completedFuture(response)) + .whenever(httpClient) + .executeAsync(any(), any()) + + call(clientOptions(httpClient)).get() + + verify(response, times(1)).close() + } + + private fun clientOptions(httpClient: HttpClient): ClientOptions = + ClientOptions.builder() + .httpClient(httpClient) + .checkJacksonVersionCompatibility(false) + .apiKey("My API Key") + .adminApiKey("My Admin API Key") + .build() + + private fun mockResponse(): HttpResponse = + mock().also { + whenever(it.statusCode()).thenReturn(204) + whenever(it.headers()).thenReturn(Headers.builder().build()) + } +}