Skip to content

Commit e40f689

Browse files
authored
fix: OData Create, Update, Delete eager response evaluation (#849)
1 parent d567cb4 commit e40f689

File tree

11 files changed

+441
-3
lines changed

11 files changed

+441
-3
lines changed

datamodel/odata-v4/odata-v4-core/src/main/java/com/sap/cloud/sdk/datamodel/odatav4/core/CollectionValueActionRequestBuilder.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,10 @@ public CollectionValueActionRequestBuilder(
9797
public ActionResponseCollection<ResultT> execute( @Nonnull final Destination destination )
9898
{
9999
final HttpClient httpClient = HttpClientAccessor.getHttpClient(destination);
100+
100101
final ODataRequestResultGeneric response = toRequest().execute(httpClient);
102+
response.getHttpResponse(); // ensure HTTP response consumption
103+
101104
return ActionResponseCollection.of(response, resultClass);
102105
}
103106
}

datamodel/odata-v4/odata-v4-core/src/main/java/com/sap/cloud/sdk/datamodel/odatav4/core/CreateRequestBuilder.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ public ModificationResponse<EntityT> execute( @Nonnull final Destination destina
103103
final HttpClient httpClient = HttpClientAccessor.getHttpClient(destination);
104104

105105
final ODataRequestResultGeneric response = toRequest().execute(httpClient);
106+
response.getHttpResponse(); // ensure HTTP response consumption
107+
106108
return ModificationResponse.of(response, getEntity());
107109
}
108110

datamodel/odata-v4/odata-v4-core/src/main/java/com/sap/cloud/sdk/datamodel/odatav4/core/DeleteRequestBuilder.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,9 @@ public DeleteRequestBuilder(
9393
public ModificationResponse<EntityT> execute( @Nonnull final Destination destination )
9494
{
9595
final HttpClient httpClient = HttpClientAccessor.getHttpClient(destination);
96+
9697
final ODataRequestResultGeneric response = toRequest().execute(httpClient);
98+
response.getHttpResponse(); // ensure HTTP response consumption
9799

98100
return ModificationResponse.of(response, getEntity());
99101
}

datamodel/odata-v4/odata-v4-core/src/main/java/com/sap/cloud/sdk/datamodel/odatav4/core/SingleValueActionRequestBuilder.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,10 @@ public SingleValueActionRequestBuilder(
9898
public ActionResponseSingle<ResultT> execute( @Nonnull final Destination destination )
9999
{
100100
final HttpClient httpClient = HttpClientAccessor.getHttpClient(destination);
101+
101102
final ODataRequestResultGeneric response = toRequest().execute(httpClient);
103+
response.getHttpResponse(); // ensure HTTP response consumption
104+
102105
return ActionResponseSingle.of(response, resultClass);
103106
}
104107
}

datamodel/odata-v4/odata-v4-core/src/main/java/com/sap/cloud/sdk/datamodel/odatav4/core/UpdateRequestBuilder.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ public ModificationResponse<EntityT> execute( @Nonnull final Destination destina
117117
final HttpClient httpClient = HttpClientAccessor.getHttpClient(destination);
118118

119119
final ODataRequestResultGeneric response = toRequest().execute(httpClient);
120+
response.getHttpResponse(); // ensure HTTP response consumption
120121

121122
return ModificationResponse.of(response, getEntity());
122123
}
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
package com.sap.cloud.sdk.datamodel.odatav4.core;
2+
3+
import static java.nio.charset.StandardCharsets.UTF_8;
4+
5+
import static org.apache.http.entity.ContentType.APPLICATION_JSON;
6+
import static org.apache.http.entity.ContentType.TEXT_PLAIN;
7+
import static org.assertj.core.api.Assertions.assertThat;
8+
import static org.mockito.ArgumentMatchers.any;
9+
import static org.mockito.Mockito.mock;
10+
import static org.mockito.Mockito.spy;
11+
import static org.mockito.Mockito.times;
12+
import static org.mockito.Mockito.verify;
13+
import static org.mockito.Mockito.when;
14+
15+
import java.io.ByteArrayInputStream;
16+
import java.io.InputStream;
17+
import java.io.OutputStream;
18+
import java.util.List;
19+
import java.util.Map;
20+
21+
import org.apache.http.HttpStatus;
22+
import org.apache.http.HttpVersion;
23+
import org.apache.http.client.HttpClient;
24+
import org.apache.http.client.methods.HttpUriRequest;
25+
import org.apache.http.entity.ContentType;
26+
import org.apache.http.entity.InputStreamEntity;
27+
import org.apache.http.message.BasicHttpResponse;
28+
import org.junit.jupiter.api.AfterEach;
29+
import org.junit.jupiter.api.Test;
30+
31+
import com.sap.cloud.sdk.cloudplatform.connectivity.DefaultHttpDestination;
32+
import com.sap.cloud.sdk.cloudplatform.connectivity.Destination;
33+
import com.sap.cloud.sdk.cloudplatform.connectivity.HttpClientAccessor;
34+
35+
import lombok.SneakyThrows;
36+
37+
public class HttpResponseEvaluationTest
38+
{
39+
private static final Destination DESTINATION = DefaultHttpDestination.builder("foo").build();
40+
41+
private HttpClient httpClient;
42+
private BasicHttpResponse httpResponse;
43+
private InputStreamEntity httpEntity;
44+
private InputStream inputStream;
45+
46+
@SneakyThrows
47+
void mockHttpResponse( final ContentType contentType, final String payload )
48+
{
49+
httpClient = mock(HttpClient.class);
50+
inputStream = spy(new ByteArrayInputStream(payload.getBytes(UTF_8)));
51+
httpEntity = spy(new InputStreamEntity(inputStream, contentType));
52+
httpResponse = spy(new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"));
53+
httpResponse.setEntity(httpEntity);
54+
HttpClientAccessor.setHttpClientFactory(destination -> httpClient);
55+
when(httpClient.execute(any())).thenReturn(httpResponse);
56+
}
57+
58+
@AfterEach
59+
void teardown()
60+
{
61+
HttpClientAccessor.setHttpClientFactory(null);
62+
HttpClientAccessor.setHttpClientCache(null);
63+
}
64+
65+
@SneakyThrows
66+
@Test
67+
void testCreate()
68+
{
69+
mockHttpResponse(APPLICATION_JSON, "{}");
70+
71+
final ModificationResponse<TestEntity> result =
72+
new CreateRequestBuilder<>("/path", new TestEntity(), "TestEntitySet")
73+
.withoutCsrfToken()
74+
.execute(DESTINATION);
75+
76+
verify(httpClient, times(1)).execute(any(HttpUriRequest.class));
77+
verify(httpResponse, times(1)).getEntity();
78+
verify(httpEntity, times(1)).writeTo(any(OutputStream.class));
79+
verify(inputStream, times(1)).close();
80+
81+
assertThat(result.getResponseStatusCode()).isEqualTo(200);
82+
}
83+
84+
@SneakyThrows
85+
@Test
86+
void testUpdate()
87+
{
88+
mockHttpResponse(APPLICATION_JSON, "{}");
89+
90+
final TestEntity testEntity = new TestEntity();
91+
testEntity.setId("id");
92+
93+
final ModificationResponse<TestEntity> result =
94+
new UpdateRequestBuilder<>("/path", testEntity, "TestEntitySet").withoutCsrfToken().execute(DESTINATION);
95+
96+
verify(httpClient, times(1)).execute(any(HttpUriRequest.class));
97+
verify(httpResponse, times(1)).getEntity();
98+
verify(httpEntity, times(1)).writeTo(any(OutputStream.class));
99+
verify(inputStream, times(1)).close();
100+
101+
assertThat(result.getResponseStatusCode()).isEqualTo(200);
102+
}
103+
104+
@SneakyThrows
105+
@Test
106+
void testDelete()
107+
{
108+
mockHttpResponse(APPLICATION_JSON, "{}");
109+
110+
final ModificationResponse<TestEntity> result =
111+
new DeleteRequestBuilder<>("/path", new TestEntity(), "TestEntitySet")
112+
.withoutCsrfToken()
113+
.execute(DESTINATION);
114+
115+
verify(httpClient, times(1)).execute(any(HttpUriRequest.class));
116+
verify(httpResponse, times(1)).getEntity();
117+
verify(httpEntity, times(1)).writeTo(any(OutputStream.class));
118+
verify(inputStream, times(1)).close();
119+
120+
assertThat(result.getResponseStatusCode()).isEqualTo(200);
121+
}
122+
123+
@SneakyThrows
124+
@Test
125+
void testReadAll()
126+
{
127+
mockHttpResponse(APPLICATION_JSON, "{\"value\": []}");
128+
129+
final List<TestEntity> result =
130+
new GetAllRequestBuilder<>("/path", TestEntity.class, "TestEntitySet").execute(DESTINATION);
131+
132+
assertThat(result).isNotNull();
133+
134+
verify(httpClient, times(1)).execute(any(HttpUriRequest.class));
135+
verify(httpResponse, times(1)).getEntity();
136+
verify(httpEntity, times(1)).writeTo(any(OutputStream.class));
137+
verify(inputStream, times(1)).close();
138+
}
139+
140+
@SneakyThrows
141+
@Test
142+
void testReadByKey()
143+
{
144+
mockHttpResponse(APPLICATION_JSON, "{}");
145+
146+
final TestEntity result =
147+
new GetByKeyRequestBuilder<>("/path", TestEntity.class, Map.of("id", "foo"), "TestEntitySet")
148+
.execute(DESTINATION);
149+
150+
assertThat(result).isNotNull();
151+
152+
verify(httpClient, times(1)).execute(any(HttpUriRequest.class));
153+
verify(httpResponse, times(1)).getEntity();
154+
verify(httpEntity, times(1)).writeTo(any(OutputStream.class));
155+
verify(inputStream, times(1)).close();
156+
}
157+
158+
@SneakyThrows
159+
@Test
160+
void testReadCount()
161+
{
162+
mockHttpResponse(TEXT_PLAIN, "42");
163+
164+
final Long result = new CountRequestBuilder<>("/path", TestEntity.class, "TestEntitySet").execute(DESTINATION);
165+
166+
assertThat(result).isNotNull();
167+
168+
verify(httpClient, times(1)).execute(any(HttpUriRequest.class));
169+
verify(httpResponse, times(1)).getEntity();
170+
verify(httpEntity, times(1)).writeTo(any(OutputStream.class));
171+
verify(inputStream, times(1)).close();
172+
}
173+
174+
@SneakyThrows
175+
@Test
176+
void testAction()
177+
{
178+
mockHttpResponse(APPLICATION_JSON, "{}");
179+
180+
final ActionResponseSingle<TestEntity> result =
181+
new SingleValueActionRequestBuilder<>("/path", "ActionName", TestEntity.class)
182+
.withoutCsrfToken()
183+
.execute(DESTINATION);
184+
185+
assertThat(result).isNotNull();
186+
187+
verify(httpClient, times(1)).execute(any(HttpUriRequest.class));
188+
verify(httpResponse, times(1)).getEntity();
189+
verify(httpEntity, times(1)).writeTo(any(OutputStream.class));
190+
verify(inputStream, times(1)).close();
191+
}
192+
193+
@SneakyThrows
194+
@Test
195+
void testFunction()
196+
{
197+
mockHttpResponse(APPLICATION_JSON, "{\"value\":[]}");
198+
199+
final List<TestEntity> result =
200+
new CollectionValueFunctionRequestBuilder<>("/path", "FunctionName", TestEntity.class).execute(DESTINATION);
201+
202+
assertThat(result).isNotNull();
203+
204+
verify(httpClient, times(1)).execute(any(HttpUriRequest.class));
205+
verify(httpResponse, times(1)).getEntity();
206+
verify(httpEntity, times(1)).writeTo(any(OutputStream.class));
207+
verify(inputStream, times(1)).close();
208+
}
209+
210+
// count function action
211+
}

datamodel/odata/odata-core/src/main/java/com/sap/cloud/sdk/datamodel/odata/helper/FluentHelperCreate.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ protected Class<? extends EntityT> getEntityClass()
7070
public ModificationResponse<EntityT> executeRequest( @Nonnull final Destination destination )
7171
{
7272
final HttpClient httpClient = HttpClientAccessor.getHttpClient(destination);
73+
7374
final ODataRequestResultGeneric result = toRequest().execute(httpClient);
75+
result.getHttpResponse(); // ensure HTTP response consumption
7476

7577
return ModificationResponse.of(result, getEntity(), destination);
7678
}

datamodel/odata/odata-core/src/main/java/com/sap/cloud/sdk/datamodel/odata/helper/FluentHelperDelete.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,9 @@ public FluentHelperT matchAnyVersionIdentifier()
9595
public ModificationResponse<EntityT> executeRequest( @Nonnull final Destination destination )
9696
{
9797
final HttpClient httpClient = HttpClientAccessor.getHttpClient(destination);
98+
9899
final ODataRequestResultGeneric result = toRequest().execute(httpClient);
100+
result.getHttpResponse(); // ensure HTTP response consumption
99101

100102
return ModificationResponse.of(result, getEntity(), destination);
101103
}

datamodel/odata/odata-core/src/main/java/com/sap/cloud/sdk/datamodel/odata/helper/FluentHelperUpdate.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,10 @@ public ModificationResponse<EntityT> executeRequest( @Nonnull final Destination
110110
{
111111
final HttpClient httpClient = HttpClientAccessor.getHttpClient(destination);
112112

113-
final ODataRequestResultGeneric response = toRequest().execute(httpClient);
114-
return ModificationResponse.of(response, getEntity(), destination);
113+
final ODataRequestResultGeneric result = toRequest().execute(httpClient);
114+
result.getHttpResponse(); // ensure HTTP response consumption
115+
116+
return ModificationResponse.of(result, getEntity(), destination);
115117
}
116118

117119
@Override

0 commit comments

Comments
 (0)