1
2
3
4
5 package com.jcabi.dynamo;
6
7 import com.jcabi.immutable.Array;
8 import java.io.IOException;
9 import java.util.Collections;
10 import java.util.NoSuchElementException;
11 import org.hamcrest.MatcherAssert;
12 import org.hamcrest.Matchers;
13 import org.junit.jupiter.api.Assertions;
14 import org.junit.jupiter.api.Test;
15 import org.mockito.Mockito;
16 import software.amazon.awssdk.core.exception.SdkClientException;
17 import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
18 import software.amazon.awssdk.services.dynamodb.model.AttributeAction;
19 import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
20 import software.amazon.awssdk.services.dynamodb.model.AttributeValueUpdate;
21 import software.amazon.awssdk.services.dynamodb.model.ConsumedCapacity;
22 import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
23 import software.amazon.awssdk.services.dynamodb.model.GetItemResponse;
24 import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;
25 import software.amazon.awssdk.services.dynamodb.model.UpdateItemResponse;
26
27
28
29
30
31 @SuppressWarnings("PMD.TooManyMethods")
32 final class AwsItemTest {
33
34 @Test
35 void comparesToItself() {
36 final Credentials creds = new Credentials.Simple("key", "secret");
37 final AwsTable table = new AwsTable(
38 creds, new Region.Simple(creds), "table-name"
39 );
40 final AwsFrame frame = new AwsFrame(creds, table, table.name());
41 MatcherAssert.assertThat(
42 "should equal to itself",
43 new AwsItem(
44 creds, frame, table.name(),
45 new Attributes(), new Array<>()
46 ),
47 Matchers.equalTo(
48 new AwsItem(
49 creds, frame, table.name(),
50 new Attributes(), new Array<>()
51 )
52 )
53 );
54 }
55
56 @Test
57 void checksPreloadedAttribute() throws IOException {
58 MatcherAssert.assertThat(
59 "did not find pre-loaded attribute",
60 new AwsItem(
61 Mockito.mock(Credentials.class),
62 Mockito.mock(AwsFrame.class),
63 "t\u00e9st-tbl",
64 new Attributes().with(
65 "k\u00e9y",
66 AttributeValue.builder().s("v\u00e1l").build()
67 ),
68 new Array<>("k\u00e9y")
69 ).has("k\u00e9y"),
70 Matchers.is(true)
71 );
72 }
73
74 @Test
75 void returnsPreloadedAttribute() throws IOException {
76 MatcherAssert.assertThat(
77 "did not return pre-loaded attribute value",
78 new AwsItem(
79 Mockito.mock(Credentials.class),
80 Mockito.mock(AwsFrame.class),
81 "t\u00e9st-tbl",
82 new Attributes().with(
83 "n\u00e4me",
84 AttributeValue.builder().s("d\u00e4ta").build()
85 ),
86 new Array<>("n\u00e4me")
87 ).get("n\u00e4me"),
88 Matchers.equalTo(
89 AttributeValue.builder().s("d\u00e4ta").build()
90 )
91 );
92 }
93
94 @Test
95 void fetchesAttributeFromDynamo() throws IOException {
96 final Credentials creds = Mockito.mock(Credentials.class);
97 final DynamoDbClient aws = Mockito.mock(DynamoDbClient.class);
98 Mockito.doReturn(aws).when(creds).aws();
99 final String attr = "\u00e4ttr";
100 Mockito.doReturn(
101 GetItemResponse.builder()
102 .item(
103 Collections.singletonMap(
104 attr,
105 AttributeValue.builder().s("r\u00e9sult").build()
106 )
107 )
108 .consumedCapacity(
109 ConsumedCapacity.builder().capacityUnits(1.0).build()
110 )
111 .build()
112 ).when(aws).getItem(Mockito.any(GetItemRequest.class));
113 MatcherAssert.assertThat(
114 "did not fetch attribute from DynamoDB",
115 new AwsItem(
116 creds, Mockito.mock(AwsFrame.class), "f\u00e9tch-tbl",
117 new Attributes().with(
118 "pk",
119 AttributeValue.builder().s("f\u00e9tch-pk").build()
120 ),
121 new Array<>("pk")
122 ).get(attr),
123 Matchers.equalTo(
124 AttributeValue.builder().s("r\u00e9sult").build()
125 )
126 );
127 }
128
129 @Test
130 void checksExistenceViaDynamo() throws IOException {
131 final Credentials creds = Mockito.mock(Credentials.class);
132 final DynamoDbClient aws = Mockito.mock(DynamoDbClient.class);
133 Mockito.doReturn(aws).when(creds).aws();
134 final String attr = "ch\u00e9ck";
135 Mockito.doReturn(
136 GetItemResponse.builder()
137 .item(
138 Collections.singletonMap(
139 attr,
140 AttributeValue.builder().s("pr\u00e9sent").build()
141 )
142 )
143 .consumedCapacity(
144 ConsumedCapacity.builder().capacityUnits(1.0).build()
145 )
146 .build()
147 ).when(aws).getItem(Mockito.any(GetItemRequest.class));
148 MatcherAssert.assertThat(
149 "did not detect attribute existence via DynamoDB",
150 new AwsItem(
151 creds, Mockito.mock(AwsFrame.class), "h\u00e4s-tbl",
152 new Attributes().with(
153 "pk",
154 AttributeValue.builder().s("h\u00e4s-pk").build()
155 ),
156 new Array<>("pk")
157 ).has(attr),
158 Matchers.is(true)
159 );
160 }
161
162 @Test
163 void updatesAttribute() throws IOException {
164 final Credentials creds = Mockito.mock(Credentials.class);
165 final DynamoDbClient aws = Mockito.mock(DynamoDbClient.class);
166 Mockito.doReturn(aws).when(creds).aws();
167 final String attr = "\u00fcpd";
168 Mockito.doReturn(
169 UpdateItemResponse.builder()
170 .attributes(
171 Collections.singletonMap(
172 attr,
173 AttributeValue.builder().s("n\u00e9w").build()
174 )
175 )
176 .consumedCapacity(
177 ConsumedCapacity.builder().capacityUnits(1.0).build()
178 )
179 .build()
180 ).when(aws).updateItem(Mockito.any(UpdateItemRequest.class));
181 MatcherAssert.assertThat(
182 "did not return updated attributes",
183 new AwsItem(
184 creds, Mockito.mock(AwsFrame.class), "\u00fcpd-tbl",
185 new Attributes().with(
186 "pk",
187 AttributeValue.builder().s("\u00fcpd-pk").build()
188 ),
189 new Array<>("pk")
190 ).put(
191 attr,
192 AttributeValueUpdate.builder()
193 .value(
194 AttributeValue.builder().s("n\u00e9w").build()
195 )
196 .action(AttributeAction.PUT)
197 .build()
198 ),
199 Matchers.hasEntry(
200 Matchers.equalTo(attr),
201 Matchers.equalTo(
202 AttributeValue.builder().s("n\u00e9w").build()
203 )
204 )
205 );
206 }
207
208 @Test
209 void throwsOnAbsentAttribute() throws IOException {
210 final DynamoDbClient aws = Mockito.mock(DynamoDbClient.class);
211 Mockito.doReturn(AwsItemTest.empty())
212 .when(aws).getItem(Mockito.any(GetItemRequest.class));
213 final Item item = new AwsItem(
214 AwsItemTest.mocked(aws),
215 Mockito.mock(AwsFrame.class), "abs\u00e9nt-tbl",
216 new Attributes().with(
217 "pk",
218 AttributeValue.builder().s("abs\u00e9nt-pk").build()
219 ),
220 new Array<>("pk")
221 );
222 Assertions.assertThrows(
223 NoSuchElementException.class,
224 () -> item.get("m\u00efssing")
225 );
226 }
227
228 @Test
229 void wrapsExceptionOnGet() {
230 final DynamoDbClient aws = Mockito.mock(DynamoDbClient.class);
231 Mockito.doThrow(SdkClientException.create("b\u00f6om"))
232 .when(aws).getItem(Mockito.any(GetItemRequest.class));
233 final Item item = new AwsItem(
234 AwsItemTest.mocked(aws),
235 Mockito.mock(AwsFrame.class), "g\u00e9t-err",
236 new Attributes().with(
237 "pk",
238 AttributeValue.builder().s("g\u00e9t-pk").build()
239 ),
240 new Array<>("pk")
241 );
242 Assertions.assertThrows(
243 IOException.class,
244 () -> item.get("f\u00e4il")
245 );
246 }
247
248 @Test
249 void wrapsExceptionOnHas() {
250 final DynamoDbClient aws = Mockito.mock(DynamoDbClient.class);
251 Mockito.doThrow(SdkClientException.create("b\u00f6om"))
252 .when(aws).getItem(Mockito.any(GetItemRequest.class));
253 final Item item = new AwsItem(
254 AwsItemTest.mocked(aws),
255 Mockito.mock(AwsFrame.class), "h\u00e4s-err",
256 new Attributes().with(
257 "pk",
258 AttributeValue.builder().s("h\u00e4s-pk").build()
259 ),
260 new Array<>("pk")
261 );
262 Assertions.assertThrows(
263 IOException.class,
264 () -> item.has("f\u00e4il")
265 );
266 }
267
268 @Test
269 void wrapsExceptionOnPut() {
270 final DynamoDbClient aws = Mockito.mock(DynamoDbClient.class);
271 Mockito.doThrow(SdkClientException.create("b\u00f6om"))
272 .when(aws).updateItem(Mockito.any(UpdateItemRequest.class));
273 final Item item = new AwsItem(
274 AwsItemTest.mocked(aws),
275 Mockito.mock(AwsFrame.class), "p\u00fct-err",
276 new Attributes().with(
277 "pk",
278 AttributeValue.builder().s("p\u00fct-pk").build()
279 ),
280 new Array<>("pk")
281 );
282 Assertions.assertThrows(
283 IOException.class,
284 () -> item.put(
285 new AttributeUpdates().with(
286 "f\u00e4il",
287 AttributeValueUpdate.builder()
288 .value(
289 AttributeValue.builder().s("v\u00e1l").build()
290 )
291 .action(AttributeAction.PUT)
292 .build()
293 )
294 )
295 );
296 }
297
298 @Test
299 void distinguishesDifferentItems() {
300 final Credentials creds = new Credentials.Simple(
301 "k\u00e9y1", "s\u00e9cret1"
302 );
303 final AwsTable first = new AwsTable(
304 creds, new Region.Simple(creds), "t\u00e4ble-one"
305 );
306 final AwsTable second = new AwsTable(
307 creds, new Region.Simple(creds), "t\u00e4ble-two"
308 );
309 MatcherAssert.assertThat(
310 "items with different tables should not be equal",
311 new AwsItem(
312 creds,
313 new AwsFrame(creds, first, first.name()),
314 first.name(),
315 new Attributes(),
316 new Array<>()
317 ),
318 Matchers.not(
319 Matchers.equalTo(
320 new AwsItem(
321 creds,
322 new AwsFrame(creds, second, second.name()),
323 second.name(),
324 new Attributes(),
325 new Array<>()
326 )
327 )
328 )
329 );
330 }
331
332 @Test
333 void returnsFrame() {
334 MatcherAssert.assertThat(
335 "did not return frame instance",
336 new AwsItem(
337 Mockito.mock(Credentials.class),
338 Mockito.mock(AwsFrame.class),
339 "fr\u00e4me-tbl",
340 new Attributes(),
341 new Array<>()
342 ).frame(),
343 Matchers.instanceOf(Frame.class)
344 );
345 }
346
347
348
349
350
351
352 private static Credentials mocked(final DynamoDbClient aws) {
353 final Credentials creds = Mockito.mock(Credentials.class);
354 Mockito.doReturn(aws).when(creds).aws();
355 return creds;
356 }
357
358
359
360
361
362 private static GetItemResponse empty() {
363 return GetItemResponse.builder()
364 .item(Collections.emptyMap())
365 .consumedCapacity(
366 ConsumedCapacity.builder().capacityUnits(1.0).build()
367 )
368 .build();
369 }
370
371 }