Skip to content

Commit 893794a

Browse files
committed
Stabilize scrolling by example API tests.
1 parent d5e7e20 commit 893794a

File tree

3 files changed

+437
-360
lines changed

3 files changed

+437
-360
lines changed

src/test/java/org/springframework/data/neo4j/integration/imperative/ScrollingIT.java

Lines changed: 182 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323

2424
import org.assertj.core.data.Index;
2525
import org.junit.jupiter.api.BeforeAll;
26+
import org.junit.jupiter.api.DisplayName;
27+
import org.junit.jupiter.api.Nested;
2628
import org.junit.jupiter.api.Tag;
2729
import org.junit.jupiter.api.Test;
2830
import org.neo4j.driver.Driver;
@@ -46,6 +48,7 @@
4648
import org.springframework.data.neo4j.test.Neo4jImperativeTestConfiguration;
4749
import org.springframework.data.neo4j.test.Neo4jIntegrationTest;
4850
import org.springframework.data.support.WindowIterator;
51+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
4952
import org.springframework.transaction.PlatformTransactionManager;
5053
import org.springframework.transaction.annotation.EnableTransactionManagement;
5154

@@ -57,174 +60,197 @@ class ScrollingIT {
5760

5861
@SuppressWarnings("unused")
5962
private static Neo4jExtension.Neo4jConnectionSupport neo4jConnectionSupport;
60-
61-
@BeforeAll
62-
static void setupTestData(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) {
63-
try (
64-
var session = driver.session(bookmarkCapture.createSessionConfig());
65-
var transaction = session.beginTransaction()
66-
) {
67-
ScrollingEntity.createTestData(transaction);
68-
transaction.commit();
69-
bookmarkCapture.seedWith(session.lastBookmarks());
63+
@Nested
64+
@SpringJUnitConfig(Config.class)
65+
@DisplayName("Scroll with derived finder method")
66+
class ScrollWithDerivedFinderMethod {
67+
68+
@BeforeAll
69+
static void setupTestData(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) {
70+
try (
71+
var session = driver.session(bookmarkCapture.createSessionConfig());
72+
var transaction = session.beginTransaction()
73+
) {
74+
ScrollingEntity.createTestData(transaction);
75+
transaction.commit();
76+
bookmarkCapture.seedWith(session.lastBookmarks());
77+
}
7078
}
71-
}
7279

73-
@Test
74-
void oneColumnSortNoScroll(@Autowired ScrollingRepository repository) {
80+
@Test
81+
void oneColumnSortNoScroll(@Autowired ScrollingRepository repository) {
7582

76-
var topN = repository.findTop4ByOrderByB();
77-
assertThat(topN)
78-
.hasSize(4)
79-
.extracting(ScrollingEntity::getA)
80-
.containsExactly("A0", "B0", "C0", "D0");
81-
}
83+
var topN = repository.findTop4ByOrderByB();
84+
assertThat(topN)
85+
.hasSize(4)
86+
.extracting(ScrollingEntity::getA)
87+
.containsExactly("A0", "B0", "C0", "D0");
88+
}
8289

83-
@Test
84-
void forwardWithDuplicatesManualIteration(@Autowired ScrollingRepository repository) {
85-
86-
var duplicates = repository.findAllByAOrderById("D0");
87-
assertThat(duplicates).hasSize(2);
88-
89-
var window = repository.findTop4By(ScrollingEntity.SORT_BY_B_AND_A, ScrollPosition.keyset());
90-
assertThat(window.hasNext()).isTrue();
91-
assertThat(window)
92-
.hasSize(4)
93-
.extracting(Function.identity())
94-
.satisfies(e -> assertThat(e.getId()).isEqualTo(duplicates.get(0).getId()), Index.atIndex(3))
95-
.extracting(ScrollingEntity::getA)
96-
.containsExactly("A0", "B0", "C0", "D0");
97-
98-
window = repository.findTop4By(ScrollingEntity.SORT_BY_B_AND_A, window.positionAt(window.size() - 1));
99-
assertThat(window.hasNext()).isTrue();
100-
assertThat(window)
101-
.hasSize(4)
102-
.extracting(Function.identity())
103-
.satisfies(e -> assertThat(e.getId()).isEqualTo(duplicates.get(1).getId()), Index.atIndex(0))
104-
.extracting(ScrollingEntity::getA)
105-
.containsExactly("D0", "E0", "F0", "G0");
106-
107-
window = repository.findTop4By(ScrollingEntity.SORT_BY_B_AND_A, window.positionAt(window.size() - 1));
108-
assertThat(window.isLast()).isTrue();
109-
assertThat(window).extracting(ScrollingEntity::getA)
110-
.containsExactly("H0", "I0");
111-
}
90+
@Test
91+
void forwardWithDuplicatesManualIteration(@Autowired ScrollingRepository repository) {
92+
93+
var duplicates = repository.findAllByAOrderById("D0");
94+
assertThat(duplicates).hasSize(2);
95+
96+
var window = repository.findTop4By(ScrollingEntity.SORT_BY_B_AND_A, ScrollPosition.keyset());
97+
assertThat(window.hasNext()).isTrue();
98+
assertThat(window)
99+
.hasSize(4)
100+
.extracting(Function.identity())
101+
.satisfies(e -> assertThat(e.getId()).isEqualTo(duplicates.get(0).getId()), Index.atIndex(3))
102+
.extracting(ScrollingEntity::getA)
103+
.containsExactly("A0", "B0", "C0", "D0");
104+
105+
window = repository.findTop4By(ScrollingEntity.SORT_BY_B_AND_A, window.positionAt(window.size() - 1));
106+
assertThat(window.hasNext()).isTrue();
107+
assertThat(window)
108+
.hasSize(4)
109+
.extracting(Function.identity())
110+
.satisfies(e -> assertThat(e.getId()).isEqualTo(duplicates.get(1).getId()), Index.atIndex(0))
111+
.extracting(ScrollingEntity::getA)
112+
.containsExactly("D0", "E0", "F0", "G0");
113+
114+
window = repository.findTop4By(ScrollingEntity.SORT_BY_B_AND_A, window.positionAt(window.size() - 1));
115+
assertThat(window.isLast()).isTrue();
116+
assertThat(window).extracting(ScrollingEntity::getA)
117+
.containsExactly("H0", "I0");
118+
}
112119

113-
@Test
114-
@Tag("GH-2726")
115-
void forwardWithFluentQueryByExample(@Autowired ScrollingRepository scrollingRepository) {
116-
ScrollingEntity scrollingEntity = new ScrollingEntity();
117-
Example<ScrollingEntity> example = Example.of(scrollingEntity, ExampleMatcher.matchingAll().withIgnoreNullValues());
118-
119-
var window = scrollingRepository.findBy(example, q -> q.sortBy(ScrollingEntity.SORT_BY_C).limit(4).scroll(ScrollPosition.keyset()));
120-
assertThat(window.hasNext()).isTrue();
121-
assertThat(window)
122-
.hasSize(4)
123-
.extracting(ScrollingEntity::getA)
124-
.containsExactly("A0", "B0", "C0", "D0");
125-
126-
ScrollPosition newPosition = ScrollPosition.forward(((KeysetScrollPosition) window.positionAt(window.size() - 1)).getKeys());
127-
window = scrollingRepository.findBy(example, q -> q.sortBy(ScrollingEntity.SORT_BY_C).limit(4).scroll(newPosition));
128-
assertThat(window)
129-
.hasSize(4)
130-
.extracting(ScrollingEntity::getA)
131-
.containsExactly("D0", "E0", "F0", "G0");
132-
133-
window = scrollingRepository.findTop4By(ScrollingEntity.SORT_BY_C, window.positionAt(window.size() - 1));
134-
assertThat(window.isLast()).isTrue();
135-
assertThat(window).extracting(ScrollingEntity::getA)
136-
.containsExactly("H0", "I0");
137-
}
120+
@Test
121+
void forwardWithDuplicatesIteratorIteration(@Autowired ScrollingRepository repository) {
138122

139-
@Test
140-
void forwardWithDuplicatesIteratorIteration(@Autowired ScrollingRepository repository) {
123+
var it = WindowIterator.of(pos -> repository.findTop4By(ScrollingEntity.SORT_BY_B_AND_A, pos))
124+
.startingAt(ScrollPosition.keyset());
125+
var content = new ArrayList<ScrollingEntity>();
126+
while (it.hasNext()) {
127+
var next = it.next();
128+
content.add(next);
129+
}
141130

142-
var it = WindowIterator.of(pos -> repository.findTop4By(ScrollingEntity.SORT_BY_B_AND_A, pos))
143-
.startingAt(ScrollPosition.keyset());
144-
var content = new ArrayList<ScrollingEntity>();
145-
while (it.hasNext()) {
146-
var next = it.next();
147-
content.add(next);
131+
assertThat(content).hasSize(10);
132+
assertThat(content.stream().map(ScrollingEntity::getId)
133+
.distinct().toList()).hasSize(10);
148134
}
149135

150-
assertThat(content).hasSize(10);
151-
assertThat(content.stream().map(ScrollingEntity::getId)
152-
.distinct().toList()).hasSize(10);
136+
@Test
137+
void backwardWithDuplicatesManualIteration(@Autowired ScrollingRepository repository) {
138+
139+
// Recreate the last position
140+
var last = repository.findFirstByA("I0");
141+
var keys = Map.of(
142+
"foobar", Values.value(last.getA()),
143+
"b", Values.value(last.getB()),
144+
Constants.NAME_OF_ADDITIONAL_SORT, Values.value(last.getId().toString())
145+
);
146+
147+
var duplicates = repository.findAllByAOrderById("D0");
148+
assertThat(duplicates).hasSize(2);
149+
150+
var window = repository.findTop4By(ScrollingEntity.SORT_BY_B_AND_A, ScrollPosition.backward(keys));
151+
assertThat(window.hasNext()).isTrue();
152+
assertThat(window)
153+
.hasSize(4)
154+
.extracting(ScrollingEntity::getA)
155+
.containsExactly("F0", "G0", "H0", "I0");
156+
157+
var pos = ((KeysetScrollPosition) window.positionAt(0));
158+
pos = ScrollPosition.backward(pos.getKeys());
159+
window = repository.findTop4By(ScrollingEntity.SORT_BY_B_AND_A, pos);
160+
assertThat(window.hasNext()).isTrue();
161+
assertThat(window)
162+
.hasSize(4)
163+
.extracting(Function.identity())
164+
.extracting(ScrollingEntity::getA)
165+
.containsExactly("C0", "D0", "D0", "E0");
166+
167+
pos = ((KeysetScrollPosition) window.positionAt(0));
168+
pos = ScrollPosition.backward(pos.getKeys());
169+
window = repository.findTop4By(ScrollingEntity.SORT_BY_B_AND_A, pos);
170+
assertThat(window.isLast()).isTrue();
171+
assertThat(window).extracting(ScrollingEntity::getA)
172+
.containsExactly("A0", "B0");
173+
}
153174
}
154175

155-
@Test
156-
void backwardWithDuplicatesManualIteration(@Autowired ScrollingRepository repository) {
157-
158-
// Recreate the last position
159-
var last = repository.findFirstByA("I0");
160-
var keys = Map.of(
161-
"foobar", Values.value(last.getA()),
162-
"b", Values.value(last.getB()),
163-
Constants.NAME_OF_ADDITIONAL_SORT, Values.value(last.getId().toString())
164-
);
165-
166-
var duplicates = repository.findAllByAOrderById("D0");
167-
assertThat(duplicates).hasSize(2);
168-
169-
var window = repository.findTop4By(ScrollingEntity.SORT_BY_B_AND_A, ScrollPosition.backward(keys));
170-
assertThat(window.hasNext()).isTrue();
171-
assertThat(window)
172-
.hasSize(4)
173-
.extracting(ScrollingEntity::getA)
174-
.containsExactly("F0", "G0", "H0", "I0");
175-
176-
var pos = ((KeysetScrollPosition) window.positionAt(0));
177-
pos = ScrollPosition.backward(pos.getKeys());
178-
window = repository.findTop4By(ScrollingEntity.SORT_BY_B_AND_A, pos);
179-
assertThat(window.hasNext()).isTrue();
180-
assertThat(window)
181-
.hasSize(4)
182-
.extracting(Function.identity())
183-
.extracting(ScrollingEntity::getA)
184-
.containsExactly("C0", "D0", "D0", "E0");
185-
186-
pos = ((KeysetScrollPosition) window.positionAt(0));
187-
pos = ScrollPosition.backward(pos.getKeys());
188-
window = repository.findTop4By(ScrollingEntity.SORT_BY_B_AND_A, pos);
189-
assertThat(window.isLast()).isTrue();
190-
assertThat(window).extracting(ScrollingEntity::getA)
191-
.containsExactly("A0", "B0");
192-
}
176+
@Nested
177+
@SpringJUnitConfig(Config.class)
178+
@DisplayName("ScrollWithExampleApi")
179+
class ScrollWithExampleApi {
180+
181+
@BeforeAll
182+
static void setupTestData(@Autowired Driver driver, @Autowired BookmarkCapture bookmarkCapture) {
183+
try (
184+
var session = driver.session(bookmarkCapture.createSessionConfig());
185+
var transaction = session.beginTransaction()
186+
) {
187+
ScrollingEntity.createTestDataWithoutDuplicates(transaction);
188+
transaction.commit();
189+
bookmarkCapture.seedWith(session.lastBookmarks());
190+
}
191+
}
193192

194-
@Test
195-
void backwardWithFluentQueryByExample(@Autowired ScrollingRepository repository) {
196-
197-
ScrollingEntity scrollingEntity = new ScrollingEntity();
198-
Example<ScrollingEntity> example = Example.of(scrollingEntity, ExampleMatcher.matchingAll().withIgnoreNullValues());
199-
200-
var last = repository.findFirstByA("I0");
201-
var keys = Map.of(
202-
"c", last.getC(),
203-
Constants.NAME_OF_ADDITIONAL_SORT, Values.value(last.getId().toString())
204-
);
205-
206-
var window = repository.findBy(example, q -> q.sortBy(ScrollingEntity.SORT_BY_C).limit(4).scroll(ScrollPosition.backward(keys)));
207-
assertThat(window.hasNext()).isTrue();
208-
assertThat(window)
209-
.hasSize(4)
210-
.extracting(ScrollingEntity::getA)
211-
.containsExactly("F0", "G0", "H0", "I0");
212-
213-
var pos = ((KeysetScrollPosition) window.positionAt(0));
214-
var nextPos = ScrollPosition.backward(pos.getKeys());
215-
window = repository.findBy(example, q -> q.sortBy(ScrollingEntity.SORT_BY_C).limit(4).scroll(nextPos));
216-
assertThat(window.hasNext()).isTrue();
217-
assertThat(window)
218-
.hasSize(4)
219-
.extracting(Function.identity())
220-
.extracting(ScrollingEntity::getA)
221-
.containsExactly("C0", "D0", "D0", "E0");
222-
223-
var nextNextPos = ScrollPosition.backward(((KeysetScrollPosition) window.positionAt(0)).getKeys());
224-
window = repository.findBy(example, q -> q.sortBy(ScrollingEntity.SORT_BY_C).limit(4).scroll(nextNextPos));
225-
assertThat(window.isLast()).isTrue();
226-
assertThat(window).extracting(ScrollingEntity::getA)
227-
.containsExactly("A0", "B0");
193+
@Test
194+
@Tag("GH-2726")
195+
void forwardWithFluentQueryByExample(@Autowired ScrollingRepository scrollingRepository) {
196+
ScrollingEntity scrollingEntity = new ScrollingEntity();
197+
Example<ScrollingEntity> example = Example.of(scrollingEntity, ExampleMatcher.matchingAll().withIgnoreNullValues());
198+
199+
var window = scrollingRepository.findBy(example, q -> q.sortBy(ScrollingEntity.SORT_BY_C).limit(4).scroll(ScrollPosition.keyset()));
200+
assertThat(window.hasNext()).isTrue();
201+
assertThat(window)
202+
.hasSize(4)
203+
.extracting(ScrollingEntity::getA)
204+
.containsExactly("A0", "B0", "C0", "D0");
205+
206+
ScrollPosition newPosition = ScrollPosition.forward(((KeysetScrollPosition) window.positionAt(window.size() - 1)).getKeys());
207+
window = scrollingRepository.findBy(example, q -> q.sortBy(ScrollingEntity.SORT_BY_C).limit(4).scroll(newPosition));
208+
assertThat(window)
209+
.hasSize(4)
210+
.extracting(ScrollingEntity::getA)
211+
.containsExactly("E0", "F0", "G0", "H0");
212+
213+
window = scrollingRepository.findTop4By(ScrollingEntity.SORT_BY_C, window.positionAt(window.size() - 1));
214+
assertThat(window.isLast()).isTrue();
215+
assertThat(window).extracting(ScrollingEntity::getA)
216+
.containsExactly("I0");
217+
}
218+
219+
@Test
220+
void backwardWithFluentQueryByExample(@Autowired ScrollingRepository repository) {
221+
222+
ScrollingEntity scrollingEntity = new ScrollingEntity();
223+
Example<ScrollingEntity> example = Example.of(scrollingEntity, ExampleMatcher.matchingAll().withIgnoreNullValues());
224+
225+
var last = repository.findFirstByA("I0");
226+
var keys = Map.of(
227+
"c", last.getC(),
228+
Constants.NAME_OF_ADDITIONAL_SORT, Values.value(last.getId().toString())
229+
);
230+
231+
var window = repository.findBy(example, q -> q.sortBy(ScrollingEntity.SORT_BY_C).limit(4).scroll(ScrollPosition.backward(keys)));
232+
assertThat(window.hasNext()).isTrue();
233+
assertThat(window)
234+
.hasSize(4)
235+
.extracting(ScrollingEntity::getA)
236+
.containsExactly("F0", "G0", "H0", "I0");
237+
238+
var pos = ((KeysetScrollPosition) window.positionAt(0));
239+
var nextPos = ScrollPosition.backward(pos.getKeys());
240+
window = repository.findBy(example, q -> q.sortBy(ScrollingEntity.SORT_BY_C).limit(4).scroll(nextPos));
241+
assertThat(window.hasNext()).isTrue();
242+
assertThat(window)
243+
.hasSize(4)
244+
.extracting(Function.identity())
245+
.extracting(ScrollingEntity::getA)
246+
.containsExactly("B0", "C0", "D0", "E0");
247+
248+
var nextNextPos = ScrollPosition.backward(((KeysetScrollPosition) window.positionAt(0)).getKeys());
249+
window = repository.findBy(example, q -> q.sortBy(ScrollingEntity.SORT_BY_C).limit(4).scroll(nextNextPos));
250+
assertThat(window.isLast()).isTrue();
251+
assertThat(window).extracting(ScrollingEntity::getA)
252+
.containsExactly("A0");
253+
}
228254
}
229255

230256
@Configuration

0 commit comments

Comments
 (0)