Skip to content

Commit 2d81ceb

Browse files
chore: sync with main (#884)
* chore: updating maven repository link in release notes (#876) * chore: Fix ResourceSet iterator to allow multiple iterations and reduce code duplication (#883) --------- Co-authored-by: Copilot <[email protected]>
1 parent 6533f63 commit 2d81ceb

File tree

4 files changed

+166
-2
lines changed

4 files changed

+166
-2
lines changed

.github/workflows/test-and-deploy.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ jobs:
6262
with:
6363
distribution: 'zulu'
6464
java-version: '17'
65-
65+
6666
- name: SonarCloud Scan
6767
if: ${{ (github.event_name == 'pull_request' || github.ref_type == 'branch') && matrix.java == 11 && !github.event.pull_request.head.repo.fork }}
6868
env:
@@ -94,7 +94,7 @@ jobs:
9494
- name: Create GitHub Release
9595
uses: sendgrid/dx-automator/actions/release@main
9696
with:
97-
footer: '**[Maven](https://mvnrepository.com/artifact/com.twilio.sdk/twilio/${version})**'
97+
footer: '**[Maven](https://central.sonatype.com/artifact/com.twilio.sdk/twilio/${version})**'
9898
env:
9999
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
100100

src/main/java/com/twilio/base/ResourceSet.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public class ResourceSet<E extends Resource> implements Iterable<E> {
1414

1515
private final Reader<E> reader;
1616
private final TwilioRestClient client;
17+
private final Page<E> firstPage; // Store reference to first page to enable multiple iterations
1718

1819
private boolean autoPaging;
1920
private long pages = 1;
@@ -32,6 +33,7 @@ public class ResourceSet<E extends Resource> implements Iterable<E> {
3233
public ResourceSet(final Reader<E> reader, final TwilioRestClient client, final Page<E> page) {
3334
this.reader = reader;
3435
this.client = client;
36+
this.firstPage = page; // Save first page to allow resetting iterator state
3537
this.page = page;
3638
this.iterator = page.getRecords().iterator();
3739
this.autoPaging = true;
@@ -74,6 +76,12 @@ public long getPageLimit() {
7476

7577
@Override
7678
public Iterator<E> iterator() {
79+
// Reset state to allow multiple iterations
80+
this.processed = 0;
81+
this.pages = 1;
82+
this.page = this.firstPage; // Reset to first page for new iteration
83+
this.iterator = this.firstPage.getRecords().iterator(); // Reset iterator to start of first page
84+
7785
return new ResourceSetIterator<>(this);
7886
}
7987

src/main/java/com/twilio/base/bearertoken/ResourceSet.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public class ResourceSet<E extends Resource> implements Iterable<E> {
1414

1515
private final Reader<E> reader;
1616
private final BearerTokenTwilioRestClient client;
17+
private final Page<E> firstPage; // Store reference to first page to enable multiple iterations
1718

1819
private boolean autoPaging;
1920
private long pages = 1;
@@ -32,6 +33,7 @@ public class ResourceSet<E extends Resource> implements Iterable<E> {
3233
public ResourceSet(final Reader<E> reader, final BearerTokenTwilioRestClient client, final Page<E> page) {
3334
this.reader = reader;
3435
this.client = client;
36+
this.firstPage = page; // Save first page to allow resetting iterator state
3537
this.page = page;
3638
this.iterator = page.getRecords().iterator();
3739
this.autoPaging = true;
@@ -74,6 +76,12 @@ public long getPageLimit() {
7476

7577
@Override
7678
public Iterator<E> iterator() {
79+
// Reset state to allow multiple iterations
80+
this.processed = 0;
81+
this.pages = 1;
82+
this.page = this.firstPage; // Reset to first page for new iteration
83+
this.iterator = this.firstPage.getRecords().iterator(); // Reset iterator to start of first page
84+
7785
return new ResourceSetIterator<>(this);
7886
}
7987

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package com.twilio.base;
2+
3+
import com.twilio.http.TwilioRestClient;
4+
import org.junit.Assert;
5+
import org.junit.Before;
6+
import org.junit.Test;
7+
import org.mockito.Mock;
8+
import org.mockito.MockitoAnnotations;
9+
10+
import java.util.ArrayList;
11+
import java.util.Arrays;
12+
import java.util.Iterator;
13+
import java.util.List;
14+
15+
import static org.mockito.Mockito.when;
16+
17+
// Simple test resource for testing ResourceSet iteration
18+
class TestResource extends Resource {
19+
private final String id;
20+
21+
public TestResource(String id) {
22+
this.id = id;
23+
}
24+
25+
public String getId() {
26+
return id;
27+
}
28+
}
29+
30+
// Simple test reader for testing ResourceSet iteration
31+
class TestReader extends Reader<TestResource> {
32+
@Override
33+
public ResourceSet<TestResource> read(TwilioRestClient client) {
34+
return null; // Not needed for our test
35+
}
36+
37+
@Override
38+
public Page<TestResource> firstPage(TwilioRestClient client) {
39+
return null; // Not needed for our test
40+
}
41+
42+
@Override
43+
public Page<TestResource> previousPage(Page<TestResource> page, TwilioRestClient client) {
44+
return null; // Not needed for our test
45+
}
46+
47+
@Override
48+
public Page<TestResource> nextPage(Page<TestResource> page, TwilioRestClient client) {
49+
return null; // Not needed for our test
50+
}
51+
52+
@Override
53+
public Page<TestResource> getPage(String targetUrl, TwilioRestClient client) {
54+
return null; // Not needed for our test
55+
}
56+
}
57+
58+
public class ResourceSetIterationTest {
59+
60+
@Mock
61+
TwilioRestClient client;
62+
63+
@Mock
64+
Page<TestResource> page;
65+
66+
@Before
67+
public void init() {
68+
MockitoAnnotations.initMocks(this);
69+
}
70+
71+
@Test
72+
public void testResourceSetCanBeIteratedMultipleTimes() {
73+
// Setup mock data with concrete objects
74+
TestResource resource1 = new TestResource("resource1");
75+
TestResource resource2 = new TestResource("resource2");
76+
List<TestResource> resources = Arrays.asList(resource1, resource2);
77+
78+
when(page.getRecords()).thenReturn(resources);
79+
when(page.getPageSize()).thenReturn(2);
80+
when(page.hasNextPage()).thenReturn(false);
81+
82+
Reader<TestResource> reader = new TestReader().limit(2);
83+
ResourceSet<TestResource> resourceSet = new ResourceSet<>(reader, client, page);
84+
85+
// First iteration - should work
86+
List<String> firstIterationResults = new ArrayList<>();
87+
for (TestResource resource : resourceSet) {
88+
firstIterationResults.add(resource.getId());
89+
}
90+
Assert.assertEquals(2, firstIterationResults.size());
91+
Assert.assertEquals("resource1", firstIterationResults.get(0));
92+
Assert.assertEquals("resource2", firstIterationResults.get(1));
93+
94+
// Second iteration - should also work and return the same results
95+
List<String> secondIterationResults = new ArrayList<>();
96+
for (TestResource resource : resourceSet) {
97+
secondIterationResults.add(resource.getId());
98+
}
99+
Assert.assertEquals("Second iteration should return same number of elements", 2, secondIterationResults.size());
100+
Assert.assertEquals("resource1", secondIterationResults.get(0));
101+
Assert.assertEquals("resource2", secondIterationResults.get(1));
102+
103+
// Third iteration using explicit iterator - should also work
104+
List<String> thirdIterationResults = new ArrayList<>();
105+
for (Iterator<TestResource> it = resourceSet.iterator(); it.hasNext(); ) {
106+
TestResource resource = it.next();
107+
thirdIterationResults.add(resource.getId());
108+
}
109+
Assert.assertEquals("Third iteration should return same number of elements", 2, thirdIterationResults.size());
110+
Assert.assertEquals("resource1", thirdIterationResults.get(0));
111+
Assert.assertEquals("resource2", thirdIterationResults.get(1));
112+
}
113+
114+
@Test
115+
public void testResourceSetWithLimitCanBeIteratedMultipleTimes() {
116+
// Setup mock data with more resources than the limit
117+
TestResource resource1 = new TestResource("resource1");
118+
TestResource resource2 = new TestResource("resource2");
119+
TestResource resource3 = new TestResource("resource3");
120+
List<TestResource> resources = Arrays.asList(resource1, resource2, resource3);
121+
122+
when(page.getRecords()).thenReturn(resources);
123+
when(page.getPageSize()).thenReturn(3);
124+
when(page.hasNextPage()).thenReturn(false);
125+
126+
// Set limit to 2, so only first 2 should be returned
127+
Reader<TestResource> reader = new TestReader().limit(2);
128+
ResourceSet<TestResource> resourceSet = new ResourceSet<>(reader, client, page);
129+
130+
// First iteration - should only return 2 elements due to limit
131+
List<String> firstIterationResults = new ArrayList<>();
132+
for (TestResource resource : resourceSet) {
133+
firstIterationResults.add(resource.getId());
134+
}
135+
Assert.assertEquals("First iteration should respect limit", 2, firstIterationResults.size());
136+
Assert.assertEquals("resource1", firstIterationResults.get(0));
137+
Assert.assertEquals("resource2", firstIterationResults.get(1));
138+
139+
// Second iteration - should also respect limit and return same results
140+
List<String> secondIterationResults = new ArrayList<>();
141+
for (TestResource resource : resourceSet) {
142+
secondIterationResults.add(resource.getId());
143+
}
144+
Assert.assertEquals("Second iteration should respect limit", 2, secondIterationResults.size());
145+
Assert.assertEquals("resource1", secondIterationResults.get(0));
146+
Assert.assertEquals("resource2", secondIterationResults.get(1));
147+
}
148+
}

0 commit comments

Comments
 (0)