16
16
17
17
package org .dataloader ;
18
18
19
+ import org .awaitility .Duration ;
19
20
import org .dataloader .fixtures .CustomCacheMap ;
20
21
import org .dataloader .fixtures .JsonObject ;
21
22
import org .dataloader .fixtures .TestKit ;
22
23
import org .dataloader .fixtures .User ;
23
24
import org .dataloader .fixtures .UserManager ;
24
25
import org .dataloader .impl .CompletableFutureKit ;
26
+ import org .dataloader .impl .DataLoaderAssertionException ;
25
27
import org .junit .jupiter .api .Named ;
26
28
import org .junit .jupiter .api .Test ;
27
29
import org .junit .jupiter .params .ParameterizedTest ;
35
37
import java .util .List ;
36
38
import java .util .Map ;
37
39
import java .util .Optional ;
40
+ import java .util .Set ;
38
41
import java .util .concurrent .CompletableFuture ;
39
42
import java .util .concurrent .CompletionStage ;
40
43
import java .util .concurrent .ExecutionException ;
47
50
import static java .util .Arrays .asList ;
48
51
import static java .util .Collections .emptyList ;
49
52
import static java .util .Collections .singletonList ;
53
+ import static java .util .concurrent .CompletableFuture .*;
50
54
import static org .awaitility .Awaitility .await ;
51
55
import static org .dataloader .DataLoaderFactory .newDataLoader ;
52
56
import static org .dataloader .DataLoaderFactory .newMappedDataLoader ;
@@ -104,7 +108,7 @@ public void basic_map_batch_loading() {
104
108
mapOfResults .put (k , k );
105
109
}
106
110
});
107
- return CompletableFuture . completedFuture (mapOfResults );
111
+ return completedFuture (mapOfResults );
108
112
};
109
113
DataLoader <String , String > loader = DataLoaderFactory .newMappedDataLoader (evensOnlyMappedBatchLoader );
110
114
@@ -424,7 +428,7 @@ public void should_Allow_priming_the_cache_with_a_future(TestDataLoaderFactory f
424
428
List <Collection <String >> loadCalls = new ArrayList <>();
425
429
DataLoader <String , String > identityLoader = factory .idLoader (new DataLoaderOptions (), loadCalls );
426
430
427
- DataLoader <String , String > dlFluency = identityLoader .prime ("A" , CompletableFuture . completedFuture ("A" ));
431
+ DataLoader <String , String > dlFluency = identityLoader .prime ("A" , completedFuture ("A" ));
428
432
assertThat (dlFluency , equalTo (identityLoader ));
429
433
430
434
CompletableFuture <String > future1 = identityLoader .load ("A" );
@@ -992,7 +996,7 @@ public void batches_multiple_requests_with_max_batch_size(TestDataLoaderFactory
992
996
993
997
identityLoader .dispatch ();
994
998
995
- CompletableFuture . allOf (f1 , f2 , f3 ).join ();
999
+ allOf (f1 , f2 , f3 ).join ();
996
1000
997
1001
assertThat (f1 .join (), equalTo (1 ));
998
1002
assertThat (f2 .join (), equalTo (2 ));
@@ -1035,13 +1039,13 @@ public void should_Batch_loads_occurring_within_futures(TestDataLoaderFactory fa
1035
1039
1036
1040
AtomicBoolean v4Called = new AtomicBoolean ();
1037
1041
1038
- CompletableFuture . supplyAsync (nullValue ).thenAccept (v1 -> {
1042
+ supplyAsync (nullValue ).thenAccept (v1 -> {
1039
1043
identityLoader .load ("a" );
1040
- CompletableFuture . supplyAsync (nullValue ).thenAccept (v2 -> {
1044
+ supplyAsync (nullValue ).thenAccept (v2 -> {
1041
1045
identityLoader .load ("b" );
1042
- CompletableFuture . supplyAsync (nullValue ).thenAccept (v3 -> {
1046
+ supplyAsync (nullValue ).thenAccept (v3 -> {
1043
1047
identityLoader .load ("c" );
1044
- CompletableFuture . supplyAsync (nullValue ).thenAccept (
1048
+ supplyAsync (nullValue ).thenAccept (
1045
1049
v4 -> {
1046
1050
identityLoader .load ("d" );
1047
1051
v4Called .set (true );
@@ -1058,12 +1062,68 @@ public void should_Batch_loads_occurring_within_futures(TestDataLoaderFactory fa
1058
1062
singletonList (asList ("a" , "b" , "c" , "d" ))));
1059
1063
}
1060
1064
1065
+ @ ParameterizedTest
1066
+ @ MethodSource ("dataLoaderFactories" )
1067
+ public void should_blowup_after_N_keys (TestDataLoaderFactory factory ) {
1068
+ if (!(factory instanceof TestReactiveDataLoaderFactory )) {
1069
+ return ;
1070
+ }
1071
+ //
1072
+ // if we blow up after emitting N keys, the N keys should work but the rest of the keys
1073
+ // should be exceptional
1074
+ DataLoader <Integer , Integer > identityLoader = ((TestReactiveDataLoaderFactory ) factory ).idLoaderBlowsUpsAfterN (3 , new DataLoaderOptions (), new ArrayList <>());
1075
+ CompletableFuture <Integer > cf1 = identityLoader .load (1 );
1076
+ CompletableFuture <Integer > cf2 = identityLoader .load (2 );
1077
+ CompletableFuture <Integer > cf3 = identityLoader .load (3 );
1078
+ CompletableFuture <Integer > cf4 = identityLoader .load (4 );
1079
+ CompletableFuture <Integer > cf5 = identityLoader .load (5 );
1080
+ identityLoader .dispatch ();
1081
+ await ().until (cf5 ::isDone );
1082
+
1083
+ assertThat (cf1 .join (), equalTo (1 ));
1084
+ assertThat (cf2 .join (), equalTo (2 ));
1085
+ assertThat (cf3 .join (), equalTo (3 ));
1086
+ assertThat (cf4 .isCompletedExceptionally (), is (true ));
1087
+ assertThat (cf5 .isCompletedExceptionally (), is (true ));
1088
+
1089
+ }
1090
+
1091
+ @ ParameterizedTest
1092
+ @ MethodSource ("dataLoaderFactories" )
1093
+ public void should_assert_values_size_equals_key_size (TestDataLoaderFactory factory ) {
1094
+ //
1095
+ // what happens if we want 4 values but are only given 2 back say
1096
+ //
1097
+ DataLoader <String , String > identityLoader = factory .onlyReturnsNValues (2 , new DataLoaderOptions (), new ArrayList <>());
1098
+ CompletableFuture <String > cf1 = identityLoader .load ("A" );
1099
+ CompletableFuture <String > cf2 = identityLoader .load ("B" );
1100
+ CompletableFuture <String > cf3 = identityLoader .load ("C" );
1101
+ CompletableFuture <String > cf4 = identityLoader .load ("D" );
1102
+ identityLoader .dispatch ();
1103
+
1104
+ await ().atMost (Duration .FIVE_HUNDRED_MILLISECONDS ).until (() -> cf1 .isDone () && cf2 .isDone () && cf3 .isDone () && cf4 .isDone ());
1105
+
1106
+ if (factory instanceof ListDataLoaderFactory | factory instanceof PublisherDataLoaderFactory ) {
1107
+ assertThat (cause (cf1 ), instanceOf (DataLoaderAssertionException .class ));
1108
+ assertThat (cause (cf2 ), instanceOf (DataLoaderAssertionException .class ));
1109
+ assertThat (cause (cf3 ), instanceOf (DataLoaderAssertionException .class ));
1110
+ assertThat (cause (cf4 ), instanceOf (DataLoaderAssertionException .class ));
1111
+ } else {
1112
+ // with the maps it's ok to have fewer results
1113
+ assertThat (cf1 .join (), equalTo ("A" ));
1114
+ assertThat (cf2 .join (), equalTo ("B" ));
1115
+ assertThat (cf3 .join (), equalTo (null ));
1116
+ assertThat (cf4 .join (), equalTo (null ));
1117
+ }
1118
+
1119
+ }
1120
+
1061
1121
@ Test
1062
1122
public void can_call_a_loader_from_a_loader () throws Exception {
1063
1123
List <Collection <String >> deepLoadCalls = new ArrayList <>();
1064
1124
DataLoader <String , String > deepLoader = newDataLoader (keys -> {
1065
1125
deepLoadCalls .add (keys );
1066
- return CompletableFuture . completedFuture (keys );
1126
+ return completedFuture (keys );
1067
1127
});
1068
1128
1069
1129
List <Collection <String >> aLoadCalls = new ArrayList <>();
@@ -1083,7 +1143,7 @@ public void can_call_a_loader_from_a_loader() throws Exception {
1083
1143
CompletableFuture <String > b1 = bLoader .load ("B1" );
1084
1144
CompletableFuture <String > b2 = bLoader .load ("B2" );
1085
1145
1086
- CompletableFuture . allOf (
1146
+ allOf (
1087
1147
aLoader .dispatch (),
1088
1148
deepLoader .dispatch (),
1089
1149
bLoader .dispatch (),
@@ -1109,11 +1169,10 @@ public void can_call_a_loader_from_a_loader() throws Exception {
1109
1169
public void should_allow_composition_of_data_loader_calls () {
1110
1170
UserManager userManager = new UserManager ();
1111
1171
1112
- BatchLoader <Long , User > userBatchLoader = userIds -> CompletableFuture
1113
- .supplyAsync (() -> userIds
1114
- .stream ()
1115
- .map (userManager ::loadUserById )
1116
- .collect (Collectors .toList ()));
1172
+ BatchLoader <Long , User > userBatchLoader = userIds -> supplyAsync (() -> userIds
1173
+ .stream ()
1174
+ .map (userManager ::loadUserById )
1175
+ .collect (Collectors .toList ()));
1117
1176
DataLoader <Long , User > userLoader = newDataLoader (userBatchLoader );
1118
1177
1119
1178
AtomicBoolean gandalfCalled = new AtomicBoolean (false );
@@ -1160,17 +1219,26 @@ private static Stream<Arguments> dataLoaderFactories() {
1160
1219
1161
1220
public interface TestDataLoaderFactory {
1162
1221
<K > DataLoader <K , K > idLoader (DataLoaderOptions options , List <Collection <K >> loadCalls );
1222
+
1163
1223
<K > DataLoader <K , K > idLoaderBlowsUps (DataLoaderOptions options , List <Collection <K >> loadCalls );
1224
+
1164
1225
<K > DataLoader <K , Object > idLoaderAllExceptions (DataLoaderOptions options , List <Collection <K >> loadCalls );
1226
+
1165
1227
DataLoader <Integer , Object > idLoaderOddEvenExceptions (DataLoaderOptions options , List <Collection <Integer >> loadCalls );
1228
+
1229
+ DataLoader <String , String > onlyReturnsNValues (int N , DataLoaderOptions options , ArrayList <Object > loadCalls );
1230
+ }
1231
+
1232
+ public interface TestReactiveDataLoaderFactory {
1233
+ <K > DataLoader <K , K > idLoaderBlowsUpsAfterN (int N , DataLoaderOptions options , List <Collection <K >> loadCalls );
1166
1234
}
1167
1235
1168
1236
private static class ListDataLoaderFactory implements TestDataLoaderFactory {
1169
1237
@ Override
1170
1238
public <K > DataLoader <K , K > idLoader (DataLoaderOptions options , List <Collection <K >> loadCalls ) {
1171
1239
return newDataLoader (keys -> {
1172
1240
loadCalls .add (new ArrayList <>(keys ));
1173
- return CompletableFuture . completedFuture (keys );
1241
+ return completedFuture (keys );
1174
1242
}, options );
1175
1243
}
1176
1244
@@ -1189,7 +1257,7 @@ public <K> DataLoader<K, Object> idLoaderAllExceptions(DataLoaderOptions options
1189
1257
loadCalls .add (new ArrayList <>(keys ));
1190
1258
1191
1259
List <Object > errors = keys .stream ().map (k -> new IllegalStateException ("Error" )).collect (Collectors .toList ());
1192
- return CompletableFuture . completedFuture (errors );
1260
+ return completedFuture (errors );
1193
1261
}, options );
1194
1262
}
1195
1263
@@ -1206,7 +1274,15 @@ public DataLoader<Integer, Object> idLoaderOddEvenExceptions(DataLoaderOptions o
1206
1274
errors .add (new IllegalStateException ("Error" ));
1207
1275
}
1208
1276
}
1209
- return CompletableFuture .completedFuture (errors );
1277
+ return completedFuture (errors );
1278
+ }, options );
1279
+ }
1280
+
1281
+ @ Override
1282
+ public DataLoader <String , String > onlyReturnsNValues (int N , DataLoaderOptions options , ArrayList <Object > loadCalls ) {
1283
+ return newDataLoader (keys -> {
1284
+ loadCalls .add (new ArrayList <>(keys ));
1285
+ return completedFuture (keys .subList (0 , N ));
1210
1286
}, options );
1211
1287
}
1212
1288
}
@@ -1220,7 +1296,7 @@ public <K> DataLoader<K, K> idLoader(
1220
1296
loadCalls .add (new ArrayList <>(keys ));
1221
1297
Map <K , K > map = new HashMap <>();
1222
1298
keys .forEach (k -> map .put (k , k ));
1223
- return CompletableFuture . completedFuture (map );
1299
+ return completedFuture (map );
1224
1300
}, options );
1225
1301
}
1226
1302
@@ -1239,7 +1315,7 @@ public <K> DataLoader<K, Object> idLoaderAllExceptions(
1239
1315
loadCalls .add (new ArrayList <>(keys ));
1240
1316
Map <K , Object > errorByKey = new HashMap <>();
1241
1317
keys .forEach (k -> errorByKey .put (k , new IllegalStateException ("Error" )));
1242
- return CompletableFuture . completedFuture (errorByKey );
1318
+ return completedFuture (errorByKey );
1243
1319
}, options );
1244
1320
}
1245
1321
@@ -1257,16 +1333,28 @@ public DataLoader<Integer, Object> idLoaderOddEvenExceptions(
1257
1333
errorByKey .put (key , new IllegalStateException ("Error" ));
1258
1334
}
1259
1335
}
1260
- return CompletableFuture .completedFuture (errorByKey );
1336
+ return completedFuture (errorByKey );
1337
+ }, options );
1338
+ }
1339
+
1340
+ @ Override
1341
+ public DataLoader <String , String > onlyReturnsNValues (int N , DataLoaderOptions options , ArrayList <Object > loadCalls ) {
1342
+ return newMappedDataLoader (keys -> {
1343
+ loadCalls .add (new ArrayList <>(keys ));
1344
+
1345
+ Map <String , String > collect = List .copyOf (keys ).subList (0 , N ).stream ().collect (Collectors .toMap (
1346
+ k -> k , v -> v
1347
+ ));
1348
+ return completedFuture (collect );
1261
1349
}, options );
1262
1350
}
1263
1351
}
1264
1352
1265
- private static class PublisherDataLoaderFactory implements TestDataLoaderFactory {
1353
+ private static class PublisherDataLoaderFactory implements TestDataLoaderFactory , TestReactiveDataLoaderFactory {
1266
1354
1267
1355
@ Override
1268
1356
public <K > DataLoader <K , K > idLoader (
1269
- DataLoaderOptions options , List <Collection <K >> loadCalls ) {
1357
+ DataLoaderOptions options , List <Collection <K >> loadCalls ) {
1270
1358
return newPublisherDataLoader ((keys , subscriber ) -> {
1271
1359
loadCalls .add (new ArrayList <>(keys ));
1272
1360
Flux .fromIterable (keys ).subscribe (subscriber );
@@ -1283,7 +1371,7 @@ public <K> DataLoader<K, K> idLoaderBlowsUps(DataLoaderOptions options, List<Col
1283
1371
1284
1372
@ Override
1285
1373
public <K > DataLoader <K , Object > idLoaderAllExceptions (
1286
- DataLoaderOptions options , List <Collection <K >> loadCalls ) {
1374
+ DataLoaderOptions options , List <Collection <K >> loadCalls ) {
1287
1375
return newPublisherDataLoaderWithTry ((keys , subscriber ) -> {
1288
1376
loadCalls .add (new ArrayList <>(keys ));
1289
1377
Stream <Try <Object >> failures = keys .stream ().map (k -> Try .failed (new IllegalStateException ("Error" )));
@@ -1293,7 +1381,7 @@ public <K> DataLoader<K, Object> idLoaderAllExceptions(
1293
1381
1294
1382
@ Override
1295
1383
public DataLoader <Integer , Object > idLoaderOddEvenExceptions (
1296
- DataLoaderOptions options , List <Collection <Integer >> loadCalls ) {
1384
+ DataLoaderOptions options , List <Collection <Integer >> loadCalls ) {
1297
1385
return newPublisherDataLoaderWithTry ((keys , subscriber ) -> {
1298
1386
loadCalls .add (new ArrayList <>(keys ));
1299
1387
@@ -1308,13 +1396,36 @@ public DataLoader<Integer, Object> idLoaderOddEvenExceptions(
1308
1396
Flux .fromIterable (errors ).subscribe (subscriber );
1309
1397
}, options );
1310
1398
}
1399
+
1400
+ @ Override
1401
+ public <K > DataLoader <K , K > idLoaderBlowsUpsAfterN (int N , DataLoaderOptions options , List <Collection <K >> loadCalls ) {
1402
+ return newPublisherDataLoader ((keys , subscriber ) -> {
1403
+ loadCalls .add (new ArrayList <>(keys ));
1404
+
1405
+ List <K > nKeys = keys .subList (0 , N );
1406
+ Flux <K > subFlux = Flux .fromIterable (nKeys );
1407
+ subFlux .concatWith (Flux .error (new IllegalStateException ("Error" )))
1408
+ .subscribe (subscriber );
1409
+ }, options );
1410
+ }
1411
+
1412
+ @ Override
1413
+ public DataLoader <String , String > onlyReturnsNValues (int N , DataLoaderOptions options , ArrayList <Object > loadCalls ) {
1414
+ return newPublisherDataLoader ((keys , subscriber ) -> {
1415
+ loadCalls .add (new ArrayList <>(keys ));
1416
+
1417
+ List <String > nKeys = keys .subList (0 , N );
1418
+ Flux .fromIterable (nKeys )
1419
+ .subscribe (subscriber );
1420
+ }, options );
1421
+ }
1311
1422
}
1312
1423
1313
- private static class MappedPublisherDataLoaderFactory implements TestDataLoaderFactory {
1424
+ private static class MappedPublisherDataLoaderFactory implements TestDataLoaderFactory , TestReactiveDataLoaderFactory {
1314
1425
1315
1426
@ Override
1316
1427
public <K > DataLoader <K , K > idLoader (
1317
- DataLoaderOptions options , List <Collection <K >> loadCalls ) {
1428
+ DataLoaderOptions options , List <Collection <K >> loadCalls ) {
1318
1429
return newMappedPublisherDataLoader ((keys , subscriber ) -> {
1319
1430
loadCalls .add (new ArrayList <>(keys ));
1320
1431
Map <K , K > map = new HashMap <>();
@@ -1333,7 +1444,7 @@ public <K> DataLoader<K, K> idLoaderBlowsUps(DataLoaderOptions options, List<Col
1333
1444
1334
1445
@ Override
1335
1446
public <K > DataLoader <K , Object > idLoaderAllExceptions (
1336
- DataLoaderOptions options , List <Collection <K >> loadCalls ) {
1447
+ DataLoaderOptions options , List <Collection <K >> loadCalls ) {
1337
1448
return newMappedPublisherDataLoaderWithTry ((keys , subscriber ) -> {
1338
1449
loadCalls .add (new ArrayList <>(keys ));
1339
1450
Stream <Map .Entry <K , Try <Object >>> failures = keys .stream ().map (k -> Map .entry (k , Try .failed (new IllegalStateException ("Error" ))));
@@ -1343,7 +1454,7 @@ public <K> DataLoader<K, Object> idLoaderAllExceptions(
1343
1454
1344
1455
@ Override
1345
1456
public DataLoader <Integer , Object > idLoaderOddEvenExceptions (
1346
- DataLoaderOptions options , List <Collection <Integer >> loadCalls ) {
1457
+ DataLoaderOptions options , List <Collection <Integer >> loadCalls ) {
1347
1458
return newMappedPublisherDataLoaderWithTry ((keys , subscriber ) -> {
1348
1459
loadCalls .add (new ArrayList <>(keys ));
1349
1460
@@ -1358,6 +1469,29 @@ public DataLoader<Integer, Object> idLoaderOddEvenExceptions(
1358
1469
Flux .fromIterable (errorByKey .entrySet ()).subscribe (subscriber );
1359
1470
}, options );
1360
1471
}
1472
+
1473
+ @ Override
1474
+ public <K > DataLoader <K , K > idLoaderBlowsUpsAfterN (int N , DataLoaderOptions options , List <Collection <K >> loadCalls ) {
1475
+ return newMappedPublisherDataLoader ((keys , subscriber ) -> {
1476
+ loadCalls .add (new ArrayList <>(keys ));
1477
+
1478
+ List <K > nKeys = keys .subList (0 , N );
1479
+ Flux <Map .Entry <K , K >> subFlux = Flux .fromIterable (nKeys ).map (k -> Map .entry (k , k ));
1480
+ subFlux .concatWith (Flux .error (new IllegalStateException ("Error" )))
1481
+ .subscribe (subscriber );
1482
+ }, options );
1483
+ }
1484
+
1485
+ @ Override
1486
+ public DataLoader <String , String > onlyReturnsNValues (int N , DataLoaderOptions options , ArrayList <Object > loadCalls ) {
1487
+ return newMappedPublisherDataLoader ((keys , subscriber ) -> {
1488
+ loadCalls .add (new ArrayList <>(keys ));
1489
+
1490
+ List <String > nKeys = keys .subList (0 , N );
1491
+ Flux .fromIterable (nKeys ).map (k -> Map .entry (k , k ))
1492
+ .subscribe (subscriber );
1493
+ }, options );
1494
+ }
1361
1495
}
1362
1496
1363
1497
private static class ThrowingCacheMap extends CustomCacheMap {
0 commit comments