1
2
3
4
5 package com.jcabi.dynamo;
6
7 import java.io.IOException;
8 import java.util.ArrayList;
9 import java.util.Collections;
10 import java.util.Map;
11 import java.util.Random;
12 import org.hamcrest.MatcherAssert;
13 import org.hamcrest.Matchers;
14 import org.junit.jupiter.api.Assertions;
15 import org.junit.jupiter.api.Test;
16 import org.mockito.Mockito;
17 import software.amazon.awssdk.core.exception.SdkClientException;
18 import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
19 import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
20 import software.amazon.awssdk.services.dynamodb.model.ConsumedCapacity;
21 import software.amazon.awssdk.services.dynamodb.model.ScanRequest;
22 import software.amazon.awssdk.services.dynamodb.model.ScanResponse;
23
24
25
26
27
28 final class ScanValveTest {
29
30 @Test
31 @SuppressWarnings("unchecked")
32 void fetchesDataWithNoNext() throws Exception {
33 final Credentials credentials = Mockito.mock(Credentials.class);
34 final DynamoDbClient aws = Mockito.mock(DynamoDbClient.class);
35 Mockito.doReturn(aws).when(credentials).aws();
36 Mockito.doReturn(
37 ScanResponse.builder()
38 .items(
39 Collections.singletonList(Collections.emptyMap())
40 )
41 .consumedCapacity(
42 ConsumedCapacity.builder().capacityUnits(1d).build()
43 )
44 .build()
45 ).when(aws).scan(Mockito.any(ScanRequest.class));
46 MatcherAssert.assertThat(
47 "should not has next",
48 new ScanValve().fetch(
49 credentials, "table",
50 new Conditions(), new ArrayList<>(0)
51 ).hasNext(),
52 Matchers.is(false)
53 );
54 }
55
56 @Test
57 @SuppressWarnings("unchecked")
58 void fetchesDataWithItems() throws Exception {
59 final Credentials credentials = Mockito.mock(Credentials.class);
60 final Map<String, AttributeValue> item = Collections.emptyMap();
61 final DynamoDbClient aws = Mockito.mock(DynamoDbClient.class);
62 Mockito.doReturn(aws).when(credentials).aws();
63 Mockito.doReturn(
64 ScanResponse.builder()
65 .items(
66 Collections.singletonList(item)
67 )
68 .consumedCapacity(
69 ConsumedCapacity.builder().capacityUnits(1d).build()
70 )
71 .build()
72 ).when(aws).scan(Mockito.any(ScanRequest.class));
73 MatcherAssert.assertThat(
74 "should has items",
75 new ScanValve().fetch(
76 credentials, "table",
77 new Conditions(), new ArrayList<>(0)
78 ).items(),
79 Matchers.hasItem(item)
80 );
81 }
82
83 @Test
84 void countsItemsViaScan() {
85 final Credentials creds = Mockito.mock(Credentials.class);
86 final DynamoDbClient aws = Mockito.mock(DynamoDbClient.class);
87 Mockito.doReturn(aws).when(creds).aws();
88 final int expected = new Random().nextInt(100) + 1;
89 Mockito.doReturn(
90 ScanResponse.builder()
91 .count(expected)
92 .consumedCapacity(
93 ConsumedCapacity.builder()
94 .capacityUnits(1d).build()
95 )
96 .build()
97 ).when(aws).scan(Mockito.any(ScanRequest.class));
98 MatcherAssert.assertThat(
99 "did not return correct count from scan",
100 new ScanValve().count(
101 creds, "c\u00f6unt-tbl", new Conditions()
102 ),
103 Matchers.equalTo(expected)
104 );
105 }
106
107 @Test
108 void wrapsExceptionOnFetch() {
109 Assertions.assertThrows(
110 IOException.class,
111 () -> {
112 final Credentials creds =
113 Mockito.mock(Credentials.class);
114 final DynamoDbClient aws =
115 Mockito.mock(DynamoDbClient.class);
116 Mockito.doReturn(aws).when(creds).aws();
117 Mockito.doThrow(
118 SdkClientException.create("f\u00e4iled")
119 ).when(aws).scan(Mockito.any(ScanRequest.class));
120 new ScanValve().fetch(
121 creds, "f\u00e4il-tbl",
122 new Conditions(), new ArrayList<>(0)
123 );
124 }
125 );
126 }
127
128 @Test
129 @SuppressWarnings("unchecked")
130 void reportsNextWhenMorePages() throws Exception {
131 final Credentials creds = Mockito.mock(Credentials.class);
132 final DynamoDbClient aws = Mockito.mock(DynamoDbClient.class);
133 Mockito.doReturn(aws).when(creds).aws();
134 Mockito.doReturn(
135 ScanResponse.builder()
136 .items(
137 Collections.singletonList(
138 Collections.singletonMap(
139 "h\u00e4sh",
140 AttributeValue.builder()
141 .s("v\u00e4l").build()
142 )
143 )
144 )
145 .lastEvaluatedKey(
146 Collections.singletonMap(
147 "h\u00e4sh",
148 AttributeValue.builder()
149 .s("l\u00e4st").build()
150 )
151 )
152 .consumedCapacity(
153 ConsumedCapacity.builder()
154 .capacityUnits(1d).build()
155 )
156 .build()
157 ).when(aws).scan(Mockito.any(ScanRequest.class));
158 MatcherAssert.assertThat(
159 "did not report next when more pages exist",
160 new ScanValve().fetch(
161 creds, "p\u00e4ge-tbl",
162 new Conditions(), new ArrayList<>(0)
163 ).hasNext(),
164 Matchers.is(true)
165 );
166 }
167
168 @Test
169 @SuppressWarnings("unchecked")
170 void fetchesNextPage() throws Exception {
171 final Credentials creds = Mockito.mock(Credentials.class);
172 final DynamoDbClient aws = Mockito.mock(DynamoDbClient.class);
173 Mockito.doReturn(aws).when(creds).aws();
174 final Map<String, AttributeValue> item =
175 Collections.singletonMap(
176 "s\u00f6rt",
177 AttributeValue.builder().s("v\u00e4l2").build()
178 );
179 Mockito.doReturn(
180 ScanResponse.builder()
181 .items(
182 Collections.singletonList(
183 Collections.singletonMap(
184 "s\u00f6rt",
185 AttributeValue.builder()
186 .s("v\u00e4l1").build()
187 )
188 )
189 )
190 .lastEvaluatedKey(
191 Collections.singletonMap(
192 "s\u00f6rt",
193 AttributeValue.builder()
194 .s("l\u00e4st").build()
195 )
196 )
197 .consumedCapacity(
198 ConsumedCapacity.builder()
199 .capacityUnits(1d).build()
200 )
201 .build()
202 ).doReturn(
203 ScanResponse.builder()
204 .items(Collections.singletonList(item))
205 .consumedCapacity(
206 ConsumedCapacity.builder()
207 .capacityUnits(1d).build()
208 )
209 .build()
210 ).when(aws).scan(Mockito.any(ScanRequest.class));
211 MatcherAssert.assertThat(
212 "did not return correct items on next page",
213 new ScanValve().fetch(
214 creds, "n\u00e9xt-tbl",
215 new Conditions(), new ArrayList<>(0)
216 ).next().items(),
217 Matchers.hasItem(item)
218 );
219 }
220
221 @Test
222 @SuppressWarnings("unchecked")
223 void throwsOnNextWithoutMorePages() {
224 Assertions.assertThrows(
225 IllegalStateException.class,
226 () -> {
227 final Credentials creds =
228 Mockito.mock(Credentials.class);
229 final DynamoDbClient aws =
230 Mockito.mock(DynamoDbClient.class);
231 Mockito.doReturn(aws).when(creds).aws();
232 Mockito.doReturn(
233 ScanResponse.builder()
234 .items(
235 Collections.singletonList(
236 Collections.emptyMap()
237 )
238 )
239 .consumedCapacity(
240 ConsumedCapacity.builder()
241 .capacityUnits(1d).build()
242 )
243 .build()
244 ).when(aws).scan(Mockito.any(ScanRequest.class));
245 new ScanValve().fetch(
246 creds, "n\u00f6-next-tbl",
247 new Conditions(), new ArrayList<>(0)
248 ).next();
249 }
250 );
251 }
252
253 @Test
254 @SuppressWarnings("unchecked")
255 void fetchesWithCustomLimit() throws Exception {
256 final Credentials creds = Mockito.mock(Credentials.class);
257 final DynamoDbClient aws = Mockito.mock(DynamoDbClient.class);
258 Mockito.doReturn(aws).when(creds).aws();
259 Mockito.doReturn(
260 ScanResponse.builder()
261 .items(
262 Collections.singletonList(Collections.emptyMap())
263 )
264 .consumedCapacity(
265 ConsumedCapacity.builder()
266 .capacityUnits(1d).build()
267 )
268 .build()
269 ).when(aws).scan(Mockito.any(ScanRequest.class));
270 MatcherAssert.assertThat(
271 "did not fetch with custom limit",
272 new ScanValve()
273 .withLimit(5)
274 .fetch(
275 creds, "l\u00efmit-tbl",
276 new Conditions(), new ArrayList<>(0)
277 ).items(),
278 Matchers.hasSize(1)
279 );
280 }
281
282 @Test
283 @SuppressWarnings("unchecked")
284 void fetchesWithAttributeToGet() throws Exception {
285 final Credentials creds = Mockito.mock(Credentials.class);
286 final DynamoDbClient aws = Mockito.mock(DynamoDbClient.class);
287 Mockito.doReturn(aws).when(creds).aws();
288 Mockito.doReturn(
289 ScanResponse.builder()
290 .items(
291 Collections.singletonList(Collections.emptyMap())
292 )
293 .consumedCapacity(
294 ConsumedCapacity.builder()
295 .capacityUnits(1d).build()
296 )
297 .build()
298 ).when(aws).scan(Mockito.any(ScanRequest.class));
299 MatcherAssert.assertThat(
300 "did not fetch with attribute to get",
301 new ScanValve()
302 .withAttributeToGet("\u00e4ttr")
303 .fetch(
304 creds, "\u00e4ttr-tbl",
305 new Conditions(), new ArrayList<>(0)
306 ).items(),
307 Matchers.hasSize(1)
308 );
309 }
310
311 }