View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2012-2026 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
4    */
5   package com.jcabi.dynamo;
6   
7   import java.io.IOException;
8   import java.util.ArrayList;
9   import java.util.Arrays;
10  import java.util.Collection;
11  import java.util.Collections;
12  import java.util.Iterator;
13  import java.util.Map;
14  import java.util.NoSuchElementException;
15  import java.util.UUID;
16  import org.hamcrest.MatcherAssert;
17  import org.hamcrest.Matchers;
18  import org.junit.jupiter.api.Assertions;
19  import org.junit.jupiter.api.Test;
20  import org.mockito.Mockito;
21  import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
22  import software.amazon.awssdk.services.dynamodb.model.DeleteItemRequest;
23  
24  /**
25   * Test case for {@link AwsIterator}.
26   * @since 0.1
27   */
28  @SuppressWarnings("unchecked")
29  final class AwsIteratorTest {
30  
31      @Test
32      void hasNextOnFreshIterator() throws IOException {
33          final Credentials credentials = Mockito.mock(Credentials.class);
34          final Dosage first = Mockito.mock(Dosage.class);
35          Mockito.doReturn(
36              Collections.singletonList(
37                  new Attributes().with("attribute-1", "value-1")
38              )
39          ).when(first).items();
40          Mockito.doReturn(true).when(first).hasNext();
41          final Valve valve = Mockito.mock(Valve.class);
42          Mockito.doReturn(first)
43              .when(valve)
44              .fetch(
45                  Mockito.eq(credentials), Mockito.anyString(),
46                  Mockito.any(Map.class), Mockito.any(Collection.class)
47              );
48          final String table = "table-1";
49          MatcherAssert.assertThat(
50              "should has next",
51              new AwsIterator(
52                  credentials,
53                  new AwsFrame(
54                      credentials,
55                      new AwsTable(
56                          credentials,
57                          Mockito.mock(Region.class),
58                          table
59                      ),
60                      table
61                  ),
62                  table, new Conditions(),
63                  new ArrayList<>(0), valve
64              ).hasNext(),
65              Matchers.is(true)
66          );
67      }
68  
69      @Test
70      void returnsFirstItemValue() throws IOException {
71          final Credentials credentials = Mockito.mock(Credentials.class);
72          final String attr = "attribute-1";
73          final String value = "value-1";
74          final Dosage first = Mockito.mock(Dosage.class);
75          Mockito.doReturn(
76              Collections.singletonList(new Attributes().with(attr, value))
77          ).when(first).items();
78          Mockito.doReturn(true).when(first).hasNext();
79          final Valve valve = Mockito.mock(Valve.class);
80          Mockito.doReturn(first)
81              .when(valve)
82              .fetch(
83                  Mockito.eq(credentials), Mockito.anyString(),
84                  Mockito.any(Map.class), Mockito.any(Collection.class)
85              );
86          final String table = "table-1";
87          MatcherAssert.assertThat(
88              "should equal to 'value-1'",
89              new AwsIterator(
90                  credentials,
91                  new AwsFrame(
92                      credentials,
93                      new AwsTable(
94                          credentials,
95                          Mockito.mock(Region.class),
96                          table
97                      ),
98                      table
99                  ),
100                 table, new Conditions(),
101                 new ArrayList<>(0), valve
102             ).next().get(attr).s(),
103             Matchers.equalTo(value)
104         );
105     }
106 
107     @Test
108     void hasNextAfterFirstDosageConsumed() throws IOException {
109         final Credentials credentials = Mockito.mock(Credentials.class);
110         final String attr = "attribute-1";
111         final String value = "value-1";
112         final Dosage first = Mockito.mock(Dosage.class);
113         Mockito.doReturn(
114             Collections.singletonList(new Attributes().with(attr, value))
115         ).when(first).items();
116         Mockito.doReturn(true).when(first).hasNext();
117         final Dosage second = Mockito.mock(Dosage.class);
118         Mockito.doReturn(second).when(first).next();
119         Mockito.doReturn(
120             Collections.singletonList(new Attributes().with(attr, value))
121         ).when(second).items();
122         Mockito.doReturn(false).when(second).hasNext();
123         final Valve valve = Mockito.mock(Valve.class);
124         Mockito.doReturn(first)
125             .when(valve)
126             .fetch(
127                 Mockito.eq(credentials), Mockito.anyString(),
128                 Mockito.any(Map.class), Mockito.any(Collection.class)
129             );
130         final String table = "table-1";
131         final Iterator<Item> iterator = new AwsIterator(
132             credentials,
133             new AwsFrame(
134                 credentials,
135                 new AwsTable(
136                     credentials,
137                     Mockito.mock(Region.class),
138                     table
139                 ),
140                 table
141             ),
142             table, new Conditions(),
143             new ArrayList<>(0), valve
144         );
145         iterator.next();
146         MatcherAssert.assertThat(
147             "should has next",
148             iterator.hasNext(),
149             Matchers.is(true)
150         );
151     }
152 
153     @Test
154     void hasNoNextAfterAllConsumed() throws IOException {
155         final Credentials credentials = Mockito.mock(Credentials.class);
156         final String attr = "attribute-1";
157         final String value = "value-1";
158         final Dosage first = Mockito.mock(Dosage.class);
159         Mockito.doReturn(
160             Collections.singletonList(new Attributes().with(attr, value))
161         ).when(first).items();
162         Mockito.doReturn(true).when(first).hasNext();
163         final Dosage second = Mockito.mock(Dosage.class);
164         Mockito.doReturn(second).when(first).next();
165         Mockito.doReturn(
166             Collections.singletonList(new Attributes().with(attr, value))
167         ).when(second).items();
168         Mockito.doReturn(true).when(second).hasNext();
169         final Dosage last = Mockito.mock(Dosage.class);
170         Mockito.doReturn(last).when(second).next();
171         Mockito.doReturn(new ArrayList<Attributes>(0)).when(last).items();
172         final Valve valve = Mockito.mock(Valve.class);
173         Mockito.doReturn(first)
174             .when(valve)
175             .fetch(
176                 Mockito.eq(credentials), Mockito.anyString(),
177                 Mockito.any(Map.class), Mockito.any(Collection.class)
178             );
179         final String table = "table-1";
180         final Iterator<Item> iterator = new AwsIterator(
181             credentials,
182             new AwsFrame(
183                 credentials,
184                 new AwsTable(
185                     credentials,
186                     Mockito.mock(Region.class),
187                     table
188                 ),
189                 table
190             ),
191             table, new Conditions(),
192             new ArrayList<>(0), valve
193         );
194         iterator.next();
195         iterator.next();
196         MatcherAssert.assertThat(
197             "should not has next",
198             iterator.hasNext(),
199             Matchers.is(false)
200         );
201     }
202 
203     @Test
204     void throwsOnEmptyIterator() throws Exception {
205         final Credentials creds = Mockito.mock(Credentials.class);
206         final Dosage dosage = Mockito.mock(Dosage.class);
207         Mockito.doReturn(Collections.emptyList()).when(dosage).items();
208         final Valve vlv = Mockito.mock(Valve.class);
209         Mockito.doReturn(dosage)
210             .when(vlv)
211             .fetch(
212                 Mockito.eq(creds), Mockito.anyString(),
213                 Mockito.any(Map.class), Mockito.any(Collection.class)
214             );
215         final String table = "table-2";
216         Assertions.assertThrows(
217             NoSuchElementException.class,
218             new AwsIterator(
219                 creds,
220                 new AwsFrame(
221                     creds,
222                     new AwsTable(
223                         creds,
224                         Mockito.mock(Region.class),
225                         table
226                     ),
227                     table
228                 ),
229                 table, new Conditions(),
230                 new ArrayList<>(0), vlv
231             )::next
232         );
233     }
234 
235     @Test
236     void iteratesMultipleItemsInSingleDosage() throws IOException {
237         final Credentials creds = Mockito.mock(Credentials.class);
238         final String attr = UUID.randomUUID().toString();
239         final Dosage dosage = Mockito.mock(Dosage.class);
240         Mockito.doReturn(
241             Arrays.asList(
242                 new Attributes().with(attr, "première"),
243                 new Attributes().with(attr, "deuxième")
244             )
245         ).when(dosage).items();
246         Mockito.doReturn(false).when(dosage).hasNext();
247         final Valve valve = Mockito.mock(Valve.class);
248         Mockito.doReturn(dosage)
249             .when(valve)
250             .fetch(
251                 Mockito.eq(creds), Mockito.anyString(),
252                 Mockito.any(Map.class), Mockito.any(Collection.class)
253             );
254         final String table = UUID.randomUUID().toString();
255         final Iterator<Item> iter = new AwsIterator(
256             creds,
257             new AwsFrame(
258                 creds,
259                 new AwsTable(
260                     creds,
261                     Mockito.mock(Region.class),
262                     table
263                 ),
264                 table
265             ),
266             table, new Conditions(),
267             new ArrayList<>(0), valve
268         );
269         iter.next();
270         MatcherAssert.assertThat(
271             "did not find second item in single dosage",
272             iter.hasNext(),
273             Matchers.is(true)
274         );
275     }
276 
277     @Test
278     void throwsOnRemoveBeforeIteration() {
279         final String table = UUID.randomUUID().toString();
280         final Credentials creds = Mockito.mock(Credentials.class);
281         Assertions.assertThrows(
282             IllegalStateException.class,
283             new AwsIterator(
284                 creds,
285                 new AwsFrame(
286                     creds,
287                     new AwsTable(
288                         creds,
289                         Mockito.mock(Region.class),
290                         table
291                     ),
292                     table
293                 ),
294                 table, new Conditions(),
295                 new ArrayList<>(0), Mockito.mock(Valve.class)
296             )::remove
297         );
298     }
299 
300     @Test
301     void removesCurrentItem() throws IOException {
302         final DynamoDbClient aws = Mockito.mock(DynamoDbClient.class);
303         final Credentials creds = Mockito.mock(Credentials.class);
304         Mockito.doReturn(aws).when(creds).aws();
305         final String attr = UUID.randomUUID().toString();
306         final Dosage dosage = Mockito.mock(Dosage.class);
307         Mockito.doReturn(
308             Collections.singletonList(
309                 new Attributes().with(attr, "ünïcödé")
310             )
311         ).when(dosage).items();
312         Mockito.doReturn(false).when(dosage).hasNext();
313         final Valve valve = Mockito.mock(Valve.class);
314         Mockito.doReturn(dosage)
315             .when(valve)
316             .fetch(
317                 Mockito.eq(creds), Mockito.anyString(),
318                 Mockito.any(Map.class), Mockito.any(Collection.class)
319             );
320         final String table = UUID.randomUUID().toString();
321         final Iterator<Item> iter = new AwsIterator(
322             creds,
323             new AwsFrame(
324                 creds,
325                 new AwsTable(
326                     creds,
327                     Mockito.mock(Region.class),
328                     table
329                 ),
330                 table
331             ),
332             table, new Conditions(),
333             Collections.singletonList(attr), valve
334         );
335         iter.next();
336         iter.remove();
337         Mockito.verify(aws).deleteItem(
338             Mockito.any(DeleteItemRequest.class)
339         );
340     }
341 
342 }