Skip to content

Commit 0092f64

Browse files
committed
Added wiremock tests to assert read/write flows for empty strings and binary on low level DynamoDb and DynamoDbStreaming SDK
1 parent fd28318 commit 0092f64

File tree

1 file changed

+334
-0
lines changed

1 file changed

+334
-0
lines changed
Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
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+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.services.dynamodb;
17+
18+
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
19+
import static com.github.tomakehurst.wiremock.client.WireMock.any;
20+
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
21+
import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
22+
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
23+
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
24+
import static com.github.tomakehurst.wiremock.client.WireMock.verify;
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
27+
import com.github.tomakehurst.wiremock.junit.WireMockRule;
28+
import java.net.URI;
29+
import java.util.Collections;
30+
import org.junit.Before;
31+
import org.junit.Rule;
32+
import org.junit.Test;
33+
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
34+
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
35+
import software.amazon.awssdk.core.SdkBytes;
36+
import software.amazon.awssdk.regions.Region;
37+
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
38+
import software.amazon.awssdk.services.dynamodb.model.GetItemResponse;
39+
import software.amazon.awssdk.services.dynamodb.model.GetRecordsResponse;
40+
import software.amazon.awssdk.services.dynamodb.model.StreamRecord;
41+
import software.amazon.awssdk.services.dynamodb.streams.DynamoDbStreamsAsyncClient;
42+
import software.amazon.awssdk.services.dynamodb.streams.DynamoDbStreamsClient;
43+
44+
public class EmptyAttributeTest {
45+
private static final AttributeValue EMPTY_STRING = AttributeValue.builder().s("").build();
46+
private static final AttributeValue EMPTY_BINARY =
47+
AttributeValue.builder().b(SdkBytes.fromByteArray(new byte[]{})).build();
48+
49+
@Rule
50+
public WireMockRule mockServer = new WireMockRule(0);
51+
52+
private DynamoDbClient dynamoDbClient;
53+
private DynamoDbAsyncClient dynamoDbAsyncClient;
54+
private DynamoDbStreamsClient dynamoDbStreamsClient;
55+
private DynamoDbStreamsAsyncClient dynamoDbStreamsAsyncClient;
56+
57+
@Before
58+
public void setup() {
59+
dynamoDbClient =
60+
DynamoDbClient.builder()
61+
.credentialsProvider(
62+
StaticCredentialsProvider.create(AwsBasicCredentials.create("test", "test")))
63+
.region(Region.US_WEST_2)
64+
.endpointOverride(URI.create("http://localhost:" + mockServer.port()))
65+
.build();
66+
67+
dynamoDbAsyncClient =
68+
DynamoDbAsyncClient.builder()
69+
.credentialsProvider(
70+
StaticCredentialsProvider.create(AwsBasicCredentials.create("test", "test")))
71+
.region(Region.US_WEST_2)
72+
.endpointOverride(URI.create("http://localhost:" + mockServer.port()))
73+
.build();
74+
75+
dynamoDbStreamsClient =
76+
DynamoDbStreamsClient.builder()
77+
.credentialsProvider(
78+
StaticCredentialsProvider.create(AwsBasicCredentials.create("test", "test")))
79+
.region(Region.US_WEST_2)
80+
.endpointOverride(URI.create("http://localhost:" + mockServer.port()))
81+
.build();
82+
83+
dynamoDbStreamsAsyncClient =
84+
DynamoDbStreamsAsyncClient.builder()
85+
.credentialsProvider(
86+
StaticCredentialsProvider.create(AwsBasicCredentials.create("test", "test")))
87+
.region(Region.US_WEST_2)
88+
.endpointOverride(URI.create("http://localhost:" + mockServer.port()))
89+
.build(); }
90+
91+
@Test
92+
public void syncClient_getItem_emptyString() {
93+
stubFor(any(urlEqualTo("/"))
94+
.willReturn(aResponse().withStatus(200).withBody("{\"Item\": {\"attribute\": {\"S\": \"\"}}}")));
95+
96+
GetItemResponse response = dynamoDbClient.getItem(r -> r.tableName("test"));
97+
assertThat(response.item()).containsKey("attribute");
98+
AttributeValue attributeValue = response.item().get("attribute");
99+
assertThat(attributeValue.s()).isEmpty();
100+
}
101+
102+
@Test
103+
public void asyncClient_getItem_emptyString() {
104+
stubFor(any(urlEqualTo("/"))
105+
.willReturn(aResponse().withStatus(200).withBody("{\"Item\": {\"attribute\": {\"S\": \"\"}}}")));
106+
107+
GetItemResponse response = dynamoDbAsyncClient.getItem(r -> r.tableName("test")).join();
108+
assertThat(response.item()).containsKey("attribute");
109+
AttributeValue attributeValue = response.item().get("attribute");
110+
assertThat(attributeValue.s()).isEmpty();
111+
}
112+
113+
@Test
114+
public void syncClient_getItem_emptyBinary() {
115+
stubFor(any(urlEqualTo("/"))
116+
.willReturn(aResponse().withStatus(200).withBody("{\"Item\": {\"attribute\": {\"B\": \"\"}}}")));
117+
118+
GetItemResponse response = dynamoDbClient.getItem(r -> r.tableName("test"));
119+
assertThat(response.item()).containsKey("attribute");
120+
AttributeValue attributeValue = response.item().get("attribute");
121+
assertThat(attributeValue.b().asByteArray()).isEmpty();
122+
}
123+
124+
@Test
125+
public void asyncClient_getItem_emptyBinary() {
126+
stubFor(any(urlEqualTo("/"))
127+
.willReturn(aResponse().withStatus(200).withBody("{\"Item\": {\"attribute\": {\"B\": \"\"}}}")));
128+
129+
GetItemResponse response = dynamoDbAsyncClient.getItem(r -> r.tableName("test")).join();
130+
assertThat(response.item()).containsKey("attribute");
131+
AttributeValue attributeValue = response.item().get("attribute");
132+
assertThat(attributeValue.b().asByteArray()).isEmpty();
133+
}
134+
135+
@Test
136+
public void syncClient_putItem_emptyString() {
137+
stubFor(any(urlEqualTo("/")).willReturn((aResponse().withStatus(200))));
138+
139+
dynamoDbClient.putItem(r -> r.item(Collections.singletonMap("stringAttribute", EMPTY_STRING)));
140+
141+
verify(postRequestedFor(urlEqualTo("/"))
142+
.withRequestBody(equalTo("{\"Item\":{\"stringAttribute\":{\"S\":\"\"}}}")));
143+
}
144+
145+
@Test
146+
public void asyncClient_putItem_emptyString() {
147+
stubFor(any(urlEqualTo("/")).willReturn((aResponse().withStatus(200))));
148+
149+
dynamoDbAsyncClient.putItem(r -> r.item(Collections.singletonMap("stringAttribute", EMPTY_STRING))).join();
150+
151+
verify(postRequestedFor(urlEqualTo("/"))
152+
.withRequestBody(equalTo("{\"Item\":{\"stringAttribute\":{\"S\":\"\"}}}")));
153+
}
154+
155+
@Test
156+
public void syncClient_putItem_emptyBinary() {
157+
stubFor(any(urlEqualTo("/")).willReturn((aResponse().withStatus(200))));
158+
159+
dynamoDbClient.putItem(r -> r.item(Collections.singletonMap("binaryAttribute", EMPTY_BINARY)));
160+
161+
verify(postRequestedFor(urlEqualTo("/"))
162+
.withRequestBody(equalTo("{\"Item\":{\"binaryAttribute\":{\"B\":\"\"}}}")));
163+
}
164+
165+
@Test
166+
public void asyncClient_putItem_emptyStrring() {
167+
stubFor(any(urlEqualTo("/")).willReturn((aResponse().withStatus(200))));
168+
169+
dynamoDbAsyncClient.putItem(r -> r.item(Collections.singletonMap("binaryAttribute", EMPTY_BINARY))).join();
170+
171+
verify(postRequestedFor(urlEqualTo("/"))
172+
.withRequestBody(equalTo("{\"Item\":{\"binaryAttribute\":{\"B\":\"\"}}}")));
173+
}
174+
175+
@Test
176+
public void syncClient_getRecords_emptyString() {
177+
stubFor(any(urlEqualTo("/"))
178+
.willReturn(aResponse().withStatus(200).withBody(
179+
"{" +
180+
" \"NextShardIterator\": \"arn:aws:dynamodb:us-west-2:111122223333:table/Forum/stream/2015-05-20T20:51:10.252|1|AAAAAAAAAAGQBYshYDEe\",\n" +
181+
" \"Records\": [\n" +
182+
" {\n" +
183+
" \"awsRegion\": \"us-west-2\",\n" +
184+
" \"dynamodb\": {\n" +
185+
" \"ApproximateCreationDateTime\": 1.46480431E9,\n" +
186+
" \"Keys\": {\n" +
187+
" \"stringKey\": {\"S\": \"DynamoDB\"}\n" +
188+
" },\n" +
189+
" \"NewImage\": {\n" +
190+
" \"stringAttribute\": {\"S\": \"\"}\n" +
191+
" },\n" +
192+
" \"OldImage\": {\n" +
193+
" \"stringAttribute\": {\"S\": \"\"}\n" +
194+
" },\n" +
195+
" \"SequenceNumber\": \"300000000000000499659\",\n" +
196+
" \"SizeBytes\": 41,\n" +
197+
" \"StreamViewType\": \"NEW_AND_OLD_IMAGES\"\n" +
198+
" },\n" +
199+
" \"eventID\": \"e2fd9c34eff2d779b297b26f5fef4206\",\n" +
200+
" \"eventName\": \"INSERT\",\n" +
201+
" \"eventSource\": \"aws:dynamodb\",\n" +
202+
" \"eventVersion\": \"1.0\"\n" +
203+
" }\n" +
204+
" ]\n" +
205+
"}")));
206+
207+
GetRecordsResponse response = dynamoDbStreamsClient.getRecords(r -> r.shardIterator("test"));
208+
209+
assertThat(response.records()).hasSize(1);
210+
StreamRecord record = response.records().get(0).dynamodb();
211+
assertThat(record.oldImage()).containsEntry("stringAttribute", EMPTY_STRING);
212+
assertThat(record.newImage()).containsEntry("stringAttribute", EMPTY_STRING);
213+
}
214+
215+
@Test
216+
public void asyncClient_getRecords_emptyString() {
217+
stubFor(any(urlEqualTo("/"))
218+
.willReturn(aResponse().withStatus(200).withBody(
219+
"{" +
220+
" \"NextShardIterator\": \"arn:aws:dynamodb:us-west-2:111122223333:table/Forum/stream/2015-05-20T20:51:10.252|1|AAAAAAAAAAGQBYshYDEe\",\n" +
221+
" \"Records\": [\n" +
222+
" {\n" +
223+
" \"awsRegion\": \"us-west-2\",\n" +
224+
" \"dynamodb\": {\n" +
225+
" \"ApproximateCreationDateTime\": 1.46480431E9,\n" +
226+
" \"Keys\": {\n" +
227+
" \"stringKey\": {\"S\": \"DynamoDB\"}\n" +
228+
" },\n" +
229+
" \"NewImage\": {\n" +
230+
" \"stringAttribute\": {\"S\": \"\"}\n" +
231+
" },\n" +
232+
" \"OldImage\": {\n" +
233+
" \"stringAttribute\": {\"S\": \"\"}\n" +
234+
" },\n" +
235+
" \"SequenceNumber\": \"300000000000000499659\",\n" +
236+
" \"SizeBytes\": 41,\n" +
237+
" \"StreamViewType\": \"NEW_AND_OLD_IMAGES\"\n" +
238+
" },\n" +
239+
" \"eventID\": \"e2fd9c34eff2d779b297b26f5fef4206\",\n" +
240+
" \"eventName\": \"INSERT\",\n" +
241+
" \"eventSource\": \"aws:dynamodb\",\n" +
242+
" \"eventVersion\": \"1.0\"\n" +
243+
" }\n" +
244+
" ]\n" +
245+
"}")));
246+
247+
GetRecordsResponse response = dynamoDbStreamsAsyncClient.getRecords(r -> r.shardIterator("test")).join();
248+
249+
assertThat(response.records()).hasSize(1);
250+
StreamRecord record = response.records().get(0).dynamodb();
251+
assertThat(record.oldImage()).containsEntry("stringAttribute", EMPTY_STRING);
252+
assertThat(record.newImage()).containsEntry("stringAttribute", EMPTY_STRING);
253+
}
254+
255+
@Test
256+
public void syncClient_getRecords_emptyBinary() {
257+
stubFor(any(urlEqualTo("/"))
258+
.willReturn(aResponse().withStatus(200).withBody(
259+
"{" +
260+
" \"NextShardIterator\": \"arn:aws:dynamodb:us-west-2:111122223333:table/Forum/stream/2015-05-20T20:51:10.252|1|AAAAAAAAAAGQBYshYDEe\",\n" +
261+
" \"Records\": [\n" +
262+
" {\n" +
263+
" \"awsRegion\": \"us-west-2\",\n" +
264+
" \"dynamodb\": {\n" +
265+
" \"ApproximateCreationDateTime\": 1.46480431E9,\n" +
266+
" \"Keys\": {\n" +
267+
" \"stringKey\": {\"S\": \"DynamoDB\"}\n" +
268+
" },\n" +
269+
" \"NewImage\": {\n" +
270+
" \"binaryAttribute\": {\"B\": \"\"}\n" +
271+
" },\n" +
272+
" \"OldImage\": {\n" +
273+
" \"binaryAttribute\": {\"B\": \"\"}\n" +
274+
" },\n" +
275+
" \"SequenceNumber\": \"300000000000000499659\",\n" +
276+
" \"SizeBytes\": 41,\n" +
277+
" \"StreamViewType\": \"NEW_AND_OLD_IMAGES\"\n" +
278+
" },\n" +
279+
" \"eventID\": \"e2fd9c34eff2d779b297b26f5fef4206\",\n" +
280+
" \"eventName\": \"INSERT\",\n" +
281+
" \"eventSource\": \"aws:dynamodb\",\n" +
282+
" \"eventVersion\": \"1.0\"\n" +
283+
" }\n" +
284+
" ]\n" +
285+
"}")));
286+
287+
GetRecordsResponse response = dynamoDbStreamsClient.getRecords(r -> r.shardIterator("test"));
288+
289+
assertThat(response.records()).hasSize(1);
290+
StreamRecord record = response.records().get(0).dynamodb();
291+
assertThat(record.oldImage()).containsEntry("binaryAttribute", EMPTY_BINARY);
292+
assertThat(record.newImage()).containsEntry("binaryAttribute", EMPTY_BINARY);
293+
}
294+
295+
@Test
296+
public void asyncClient_getRecords_emptyBinary() {
297+
stubFor(any(urlEqualTo("/"))
298+
.willReturn(aResponse().withStatus(200).withBody(
299+
"{" +
300+
" \"NextShardIterator\": \"arn:aws:dynamodb:us-west-2:111122223333:table/Forum/stream/2015-05-20T20:51:10.252|1|AAAAAAAAAAGQBYshYDEe\",\n" +
301+
" \"Records\": [\n" +
302+
" {\n" +
303+
" \"awsRegion\": \"us-west-2\",\n" +
304+
" \"dynamodb\": {\n" +
305+
" \"ApproximateCreationDateTime\": 1.46480431E9,\n" +
306+
" \"Keys\": {\n" +
307+
" \"stringKey\": {\"S\": \"DynamoDB\"}\n" +
308+
" },\n" +
309+
" \"NewImage\": {\n" +
310+
" \"binaryAttribute\": {\"B\": \"\"}\n" +
311+
" },\n" +
312+
" \"OldImage\": {\n" +
313+
" \"binaryAttribute\": {\"B\": \"\"}\n" +
314+
" },\n" +
315+
" \"SequenceNumber\": \"300000000000000499659\",\n" +
316+
" \"SizeBytes\": 41,\n" +
317+
" \"StreamViewType\": \"NEW_AND_OLD_IMAGES\"\n" +
318+
" },\n" +
319+
" \"eventID\": \"e2fd9c34eff2d779b297b26f5fef4206\",\n" +
320+
" \"eventName\": \"INSERT\",\n" +
321+
" \"eventSource\": \"aws:dynamodb\",\n" +
322+
" \"eventVersion\": \"1.0\"\n" +
323+
" }\n" +
324+
" ]\n" +
325+
"}")));
326+
327+
GetRecordsResponse response = dynamoDbStreamsAsyncClient.getRecords(r -> r.shardIterator("test")).join();
328+
329+
assertThat(response.records()).hasSize(1);
330+
StreamRecord record = response.records().get(0).dynamodb();
331+
assertThat(record.oldImage()).containsEntry("binaryAttribute", EMPTY_BINARY);
332+
assertThat(record.newImage()).containsEntry("binaryAttribute", EMPTY_BINARY);
333+
}
334+
}

0 commit comments

Comments
 (0)