Skip to content

Commit 523a0e8

Browse files
committed
DDB Enhanced: Added functional tests to assert that empty strings and bytes are mapped properly
1 parent 3d2e2e5 commit 523a0e8

File tree

2 files changed

+350
-0
lines changed

2 files changed

+350
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
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.enhanced.dynamodb.functionaltests;
17+
18+
import static java.util.Collections.singletonMap;
19+
import static org.assertj.core.api.Assertions.assertThat;
20+
import static org.mockito.ArgumentMatchers.any;
21+
import static org.mockito.Mockito.verify;
22+
import static org.mockito.Mockito.when;
23+
24+
import java.util.HashMap;
25+
import java.util.Map;
26+
import org.junit.Before;
27+
import org.junit.Test;
28+
import org.junit.runner.RunWith;
29+
import org.mockito.Mock;
30+
import org.mockito.junit.MockitoJUnitRunner;
31+
import software.amazon.awssdk.core.SdkBytes;
32+
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
33+
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
34+
import software.amazon.awssdk.enhanced.dynamodb.Expression;
35+
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
36+
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
37+
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
38+
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
39+
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
40+
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
41+
import software.amazon.awssdk.services.dynamodb.model.GetItemResponse;
42+
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
43+
import software.amazon.awssdk.services.dynamodb.model.ReturnValue;
44+
import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;
45+
import software.amazon.awssdk.services.dynamodb.model.UpdateItemResponse;
46+
47+
@RunWith(MockitoJUnitRunner.class)
48+
public class EmptyBinaryTest {
49+
private static final String TABLE_NAME = "TEST_TABLE";
50+
private static final SdkBytes EMPTY_BYTES = SdkBytes.fromUtf8String("");
51+
private static final AttributeValue EMPTY_BINARY = AttributeValue.builder().b(EMPTY_BYTES).build();
52+
53+
@Mock
54+
private DynamoDbClient mockDynamoDbClient;
55+
56+
private DynamoDbTable<TestBean> dynamoDbTable;
57+
58+
@DynamoDbBean
59+
public static class TestBean {
60+
private String id;
61+
private SdkBytes b;
62+
63+
@DynamoDbPartitionKey
64+
public String getId() {
65+
return id;
66+
}
67+
68+
public void setId(String id) {
69+
this.id = id;
70+
}
71+
72+
public SdkBytes getB() {
73+
return b;
74+
}
75+
76+
public void setB(SdkBytes b) {
77+
this.b = b;
78+
}
79+
}
80+
81+
private static final TableSchema<TestBean> TABLE_SCHEMA = TableSchema.fromBean(TestBean.class);
82+
83+
@Before
84+
public void initializeTable() {
85+
DynamoDbEnhancedClient dynamoDbEnhancedClient = DynamoDbEnhancedClient.builder()
86+
.dynamoDbClient(mockDynamoDbClient)
87+
.build();
88+
89+
this.dynamoDbTable = dynamoDbEnhancedClient.table(TABLE_NAME, TABLE_SCHEMA);
90+
}
91+
92+
@Test
93+
public void putEmptyBytes() {
94+
TestBean testBean = new TestBean();
95+
testBean.setId("id123");
96+
testBean.setB(EMPTY_BYTES);
97+
98+
dynamoDbTable.putItem(testBean);
99+
100+
Map<String, AttributeValue> expectedItemMap = new HashMap<>();
101+
expectedItemMap.put("id", AttributeValue.builder().s("id123").build());
102+
expectedItemMap.put("b", EMPTY_BINARY);
103+
104+
PutItemRequest expectedRequest = PutItemRequest.builder()
105+
.tableName(TABLE_NAME)
106+
.item(expectedItemMap)
107+
.build();
108+
109+
verify(mockDynamoDbClient).putItem(expectedRequest);
110+
}
111+
112+
@Test
113+
public void getEmptyBytes() {
114+
Map<String, AttributeValue> itemMap = new HashMap<>();
115+
itemMap.put("id", AttributeValue.builder().s("id123").build());
116+
itemMap.put("b", EMPTY_BINARY);
117+
118+
GetItemResponse response = GetItemResponse.builder()
119+
.item(itemMap)
120+
.build();
121+
122+
when(mockDynamoDbClient.getItem(any(GetItemRequest.class))).thenReturn(response);
123+
124+
TestBean result = dynamoDbTable.getItem(r -> r.key(k -> k.partitionValue("id123")));
125+
126+
assertThat(result.getId()).isEqualTo("id123");
127+
assertThat(result.getB()).isEqualTo(EMPTY_BYTES);
128+
}
129+
130+
@Test
131+
public void updateEmptyBytesWithCondition() {
132+
Map<String, AttributeValue> expectedItemMap = new HashMap<>();
133+
expectedItemMap.put("id", AttributeValue.builder().s("id123").build());
134+
expectedItemMap.put("b", EMPTY_BINARY);
135+
TestBean testBean = new TestBean();
136+
testBean.setId("id123");
137+
testBean.setB(EMPTY_BYTES);
138+
139+
UpdateItemResponse response = UpdateItemResponse.builder()
140+
.attributes(expectedItemMap)
141+
.build();
142+
when(mockDynamoDbClient.updateItem(any(UpdateItemRequest.class))).thenReturn(response);
143+
144+
Expression conditionExpression = Expression.builder()
145+
.expression("#attr = :val")
146+
.expressionNames(singletonMap("#attr", "b"))
147+
.expressionValues(singletonMap(":val", EMPTY_BINARY))
148+
.build();
149+
150+
TestBean result = dynamoDbTable.updateItem(r -> r.item(testBean).conditionExpression(conditionExpression));
151+
152+
Map<String, String> expectedExpressionAttributeNames = new HashMap<>();
153+
expectedExpressionAttributeNames.put("#AMZN_MAPPED_b", "b");
154+
expectedExpressionAttributeNames.put("#attr", "b");
155+
Map<String, AttributeValue> expectedExpressionAttributeValues = new HashMap<>();
156+
expectedExpressionAttributeValues.put(":AMZN_MAPPED_b", EMPTY_BINARY);
157+
expectedExpressionAttributeValues.put(":val", EMPTY_BINARY);
158+
Map<String, AttributeValue> expectedKeyMap = new HashMap<>();
159+
expectedKeyMap.put("id", AttributeValue.builder().s("id123").build());
160+
161+
UpdateItemRequest expectedRequest =
162+
UpdateItemRequest.builder()
163+
.tableName(TABLE_NAME)
164+
.key(expectedKeyMap)
165+
.returnValues(ReturnValue.ALL_NEW)
166+
.updateExpression("SET #AMZN_MAPPED_b = :AMZN_MAPPED_b")
167+
.conditionExpression("#attr = :val")
168+
.expressionAttributeNames(expectedExpressionAttributeNames)
169+
.expressionAttributeValues(expectedExpressionAttributeValues)
170+
.build();
171+
172+
verify(mockDynamoDbClient).updateItem(expectedRequest);
173+
assertThat(result.getId()).isEqualTo("id123");
174+
assertThat(result.getB()).isEqualTo(EMPTY_BYTES);
175+
}
176+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
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.enhanced.dynamodb.functionaltests;
17+
18+
import static java.util.Collections.singletonMap;
19+
import static org.assertj.core.api.Assertions.assertThat;
20+
import static org.mockito.ArgumentMatchers.any;
21+
import static org.mockito.Mockito.verify;
22+
import static org.mockito.Mockito.when;
23+
24+
import java.util.HashMap;
25+
import java.util.Map;
26+
import org.junit.Before;
27+
import org.junit.Test;
28+
import org.junit.runner.RunWith;
29+
import org.mockito.Mock;
30+
import org.mockito.junit.MockitoJUnitRunner;
31+
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
32+
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
33+
import software.amazon.awssdk.enhanced.dynamodb.Expression;
34+
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
35+
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
36+
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
37+
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
38+
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
39+
import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
40+
import software.amazon.awssdk.services.dynamodb.model.GetItemResponse;
41+
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
42+
import software.amazon.awssdk.services.dynamodb.model.ReturnValue;
43+
import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;
44+
import software.amazon.awssdk.services.dynamodb.model.UpdateItemResponse;
45+
46+
@RunWith(MockitoJUnitRunner.class)
47+
public class EmptyStringTest {
48+
private static final String TABLE_NAME = "TEST_TABLE";
49+
private static final AttributeValue EMPTY_STRING = AttributeValue.builder().s("").build();
50+
51+
@Mock
52+
private DynamoDbClient mockDynamoDbClient;
53+
54+
private DynamoDbTable<TestBean> dynamoDbTable;
55+
56+
@DynamoDbBean
57+
public static class TestBean {
58+
private String id;
59+
private String s;
60+
61+
@DynamoDbPartitionKey
62+
public String getId() {
63+
return id;
64+
}
65+
66+
public void setId(String id) {
67+
this.id = id;
68+
}
69+
70+
public String getS() {
71+
return s;
72+
}
73+
74+
public void setS(String s) {
75+
this.s = s;
76+
}
77+
}
78+
79+
private static final TableSchema<TestBean> TABLE_SCHEMA = TableSchema.fromBean(TestBean.class);
80+
81+
@Before
82+
public void initializeTable() {
83+
DynamoDbEnhancedClient dynamoDbEnhancedClient = DynamoDbEnhancedClient.builder()
84+
.dynamoDbClient(mockDynamoDbClient)
85+
.build();
86+
87+
this.dynamoDbTable = dynamoDbEnhancedClient.table(TABLE_NAME, TABLE_SCHEMA);
88+
}
89+
90+
@Test
91+
public void putEmptyString() {
92+
TestBean testBean = new TestBean();
93+
testBean.setId("id123");
94+
testBean.setS("");
95+
96+
dynamoDbTable.putItem(testBean);
97+
98+
Map<String, AttributeValue> expectedItemMap = new HashMap<>();
99+
expectedItemMap.put("id", AttributeValue.builder().s("id123").build());
100+
expectedItemMap.put("s", EMPTY_STRING);
101+
102+
PutItemRequest expectedRequest = PutItemRequest.builder()
103+
.tableName(TABLE_NAME)
104+
.item(expectedItemMap)
105+
.build();
106+
107+
verify(mockDynamoDbClient).putItem(expectedRequest);
108+
}
109+
110+
@Test
111+
public void getEmptyString() {
112+
Map<String, AttributeValue> itemMap = new HashMap<>();
113+
itemMap.put("id", AttributeValue.builder().s("id123").build());
114+
itemMap.put("s", EMPTY_STRING);
115+
116+
GetItemResponse response = GetItemResponse.builder()
117+
.item(itemMap)
118+
.build();
119+
120+
when(mockDynamoDbClient.getItem(any(GetItemRequest.class))).thenReturn(response);
121+
122+
TestBean result = dynamoDbTable.getItem(r -> r.key(k -> k.partitionValue("id123")));
123+
124+
assertThat(result.getId()).isEqualTo("id123");
125+
assertThat(result.getS()).isEmpty();
126+
}
127+
128+
@Test
129+
public void updateEmptyStringWithCondition() {
130+
Map<String, AttributeValue> expectedItemMap = new HashMap<>();
131+
expectedItemMap.put("id", AttributeValue.builder().s("id123").build());
132+
expectedItemMap.put("s", EMPTY_STRING);
133+
TestBean testBean = new TestBean();
134+
testBean.setId("id123");
135+
testBean.setS("");
136+
137+
UpdateItemResponse response = UpdateItemResponse.builder()
138+
.attributes(expectedItemMap)
139+
.build();
140+
when(mockDynamoDbClient.updateItem(any(UpdateItemRequest.class))).thenReturn(response);
141+
142+
Expression conditionExpression = Expression.builder()
143+
.expression("#attr = :val")
144+
.expressionNames(singletonMap("#attr", "s"))
145+
.expressionValues(singletonMap(":val", EMPTY_STRING))
146+
.build();
147+
148+
TestBean result = dynamoDbTable.updateItem(r -> r.item(testBean).conditionExpression(conditionExpression));
149+
150+
Map<String, String> expectedExpressionAttributeNames = new HashMap<>();
151+
expectedExpressionAttributeNames.put("#AMZN_MAPPED_s", "s");
152+
expectedExpressionAttributeNames.put("#attr", "s");
153+
Map<String, AttributeValue> expectedExpressionAttributeValues = new HashMap<>();
154+
expectedExpressionAttributeValues.put(":AMZN_MAPPED_s", EMPTY_STRING);
155+
expectedExpressionAttributeValues.put(":val", EMPTY_STRING);
156+
Map<String, AttributeValue> expectedKeyMap = new HashMap<>();
157+
expectedKeyMap.put("id", AttributeValue.builder().s("id123").build());
158+
159+
UpdateItemRequest expectedRequest =
160+
UpdateItemRequest.builder()
161+
.tableName(TABLE_NAME)
162+
.key(expectedKeyMap)
163+
.returnValues(ReturnValue.ALL_NEW)
164+
.updateExpression("SET #AMZN_MAPPED_s = :AMZN_MAPPED_s")
165+
.conditionExpression("#attr = :val")
166+
.expressionAttributeNames(expectedExpressionAttributeNames)
167+
.expressionAttributeValues(expectedExpressionAttributeValues)
168+
.build();
169+
170+
verify(mockDynamoDbClient).updateItem(expectedRequest);
171+
assertThat(result.getId()).isEqualTo("id123");
172+
assertThat(result.getS()).isEmpty();
173+
}
174+
}

0 commit comments

Comments
 (0)