tigerbeetle-node 0.17.3 → 0.17.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/test.ts CHANGED
@@ -17,9 +17,22 @@ import {
17
17
  RequestError,
18
18
  } from '.'
19
19
 
20
+ async function sleep_ms(ms: number): Promise<void> {
21
+ await new Promise(resolve => setTimeout(resolve, ms))
22
+ }
23
+
24
+ function range(n: number): number[] {
25
+ return Array.from({ length: n }, (_, i) => i);
26
+ }
27
+
28
+ function random_index(array: Array<any>): number {
29
+ return Math.floor(Math.random() * array.length);
30
+ }
31
+
32
+ const REPLICA_ADDRESSES = [process.env.TB_ADDRESS || '3000'];
20
33
  const client = createClient({
21
34
  cluster_id: 0n,
22
- replica_addresses: [process.env.TB_ADDRESS || '3000']
35
+ replica_addresses: REPLICA_ADDRESSES
23
36
  })
24
37
 
25
38
  // Test data
@@ -69,7 +82,7 @@ test('id() monotonically increasing', async (): Promise<void> => {
69
82
  for (let i = 0; i < 10_000_000; i++) {
70
83
  // Ensure ID is monotonic between milliseconds if the loop executes too fast.
71
84
  if (i % 10_000 == 0) {
72
- await new Promise(resolve => setTimeout(resolve, 1))
85
+ await sleep_ms(1)
73
86
  }
74
87
 
75
88
  const idB = id();
@@ -115,8 +128,8 @@ test('error if timestamp is not set to 0n on account', async (): Promise<void> =
115
128
 
116
129
  test('batch max size', async (): Promise<void> => {
117
130
  const BATCH_SIZE = 10_000;
118
- var transfers: Transfer[] = [];
119
- for (var i=0; i<BATCH_SIZE;i++) {
131
+ const transfers: Transfer[] = [];
132
+ for (let i=0; i<BATCH_SIZE;i++) {
120
133
  transfers.push({
121
134
  id: 0n,
122
135
  debit_account_id: 0n,
@@ -140,6 +153,17 @@ test('batch max size', async (): Promise<void> => {
140
153
  })
141
154
  })
142
155
 
156
+ test('batch invalid size', async (): Promise<void> => {
157
+ const transfers: Transfer[] = [];
158
+ transfers.length = 0xffffffff;
159
+
160
+ assert.rejects(async() => await client.createTransfers(transfers), (err) => {
161
+ assert.ok(err instanceof RequestError)
162
+ assert.strictEqual(err.code, ErrorCodes.ERR_TOO_MUCH_DATA)
163
+ return true
164
+ })
165
+ })
166
+
143
167
  test('can lookup accounts', async (): Promise<void> => {
144
168
  const accounts = await client.lookupAccounts([accountA.id, accountB.id])
145
169
 
@@ -431,7 +455,7 @@ test('cannot void an expired transfer', async (): Promise<void> => {
431
455
  assert.ok(transfers_results[0].timestamp > 0)
432
456
  assert.deepStrictEqual(transfers_results[0].status, CreateTransferStatus.created)
433
457
 
434
- var accounts = await client.lookupAccounts([accountA.id, accountB.id])
458
+ let accounts = await client.lookupAccounts([accountA.id, accountB.id])
435
459
  assert.strictEqual(accounts.length, 2)
436
460
  assert.strictEqual(accounts[0].credits_posted, 150n)
437
461
  assert.strictEqual(accounts[0].credits_pending, 50n)
@@ -446,9 +470,8 @@ test('cannot void an expired transfer', async (): Promise<void> => {
446
470
  // We need to wait 1s for the server to expire the transfer, however the
447
471
  // server can pulse the expiry operation anytime after the timeout,
448
472
  // so adding an extra delay to avoid flaky tests.
449
- // TODO: Use `await setTimeout(1000)` when upgrade to Node.js > 15.
450
473
  const extra_wait_time = 500;
451
- await new Promise(_ => setTimeout(_, (transfer.timeout * 1000) + extra_wait_time));
474
+ await sleep_ms((transfer.timeout * 1000) + extra_wait_time);
452
475
 
453
476
  // Looking up the accounts again for the updated balance.
454
477
  accounts = await client.lookupAccounts([accountA.id, accountB.id])
@@ -566,9 +589,9 @@ test('can get account transfers', async (): Promise<void> => {
566
589
  assert.ok(account_results[0].timestamp > 0)
567
590
  assert.deepStrictEqual(account_results[0].status, CreateAccountStatus.created)
568
591
 
569
- var transfers_created : Transfer[] = [];
592
+ const transfers_created : Transfer[] = [];
570
593
  // Create transfers where the new account is either the debit or credit account:
571
- for (var i=0; i<10;i++) {
594
+ for (let i=0; i<10;i++) {
572
595
  transfers_created.push({
573
596
  id: BigInt(i + 10000),
574
597
  debit_account_id: i % 2 == 0 ? accountC.id : accountA.id,
@@ -594,7 +617,7 @@ test('can get account transfers', async (): Promise<void> => {
594
617
  }
595
618
 
596
619
  // Query all transfers for accountC:
597
- var filter: AccountFilter = {
620
+ let filter: AccountFilter = {
598
621
  account_id: accountC.id,
599
622
  user_data_128: 0n,
600
623
  user_data_64: 0n,
@@ -605,14 +628,14 @@ test('can get account transfers', async (): Promise<void> => {
605
628
  limit: BATCH_MAX,
606
629
  flags: AccountFilterFlags.credits | AccountFilterFlags.debits,
607
630
  }
608
- var transfers = await client.getAccountTransfers(filter)
609
- var account_balances = await client.getAccountBalances(filter)
631
+ let transfers = await client.getAccountTransfers(filter)
632
+ let account_balances = await client.getAccountBalances(filter)
610
633
  assert.strictEqual(transfers.length, transfers_created.length)
611
634
  assert.strictEqual(account_balances.length, transfers.length)
612
635
 
613
- var timestamp = 0n;
614
- var i = 0;
615
- for (var transfer of transfers) {
636
+ let timestamp = 0n;
637
+ let i = 0;
638
+ for (const transfer of transfers) {
616
639
  assert.ok(timestamp < transfer.timestamp);
617
640
  timestamp = transfer.timestamp;
618
641
 
@@ -640,7 +663,7 @@ test('can get account transfers', async (): Promise<void> => {
640
663
 
641
664
  timestamp = 1n << 64n;
642
665
  i = 0;
643
- for (var transfer of transfers) {
666
+ for (const transfer of transfers) {
644
667
  assert.ok(transfer.timestamp < timestamp);
645
668
  timestamp = transfer.timestamp;
646
669
 
@@ -668,7 +691,7 @@ test('can get account transfers', async (): Promise<void> => {
668
691
 
669
692
  timestamp = 1n << 64n;
670
693
  i = 0;
671
- for (var transfer of transfers) {
694
+ for (const transfer of transfers) {
672
695
  assert.ok(transfer.timestamp < timestamp);
673
696
  timestamp = transfer.timestamp;
674
697
 
@@ -696,7 +719,7 @@ test('can get account transfers', async (): Promise<void> => {
696
719
 
697
720
  timestamp = 0n;
698
721
  i = 0;
699
- for (var transfer of transfers) {
722
+ for (const transfer of transfers) {
700
723
  assert.ok(timestamp < transfer.timestamp);
701
724
  timestamp = transfer.timestamp;
702
725
 
@@ -723,7 +746,7 @@ test('can get account transfers', async (): Promise<void> => {
723
746
  assert.strictEqual(account_balances.length, transfers.length)
724
747
 
725
748
  i = 0;
726
- for (var transfer of transfers) {
749
+ for (const transfer of transfers) {
727
750
  assert.ok(timestamp < transfer.timestamp);
728
751
  timestamp = transfer.timestamp;
729
752
 
@@ -769,7 +792,7 @@ test('can get account transfers', async (): Promise<void> => {
769
792
 
770
793
  timestamp = 1n << 64n;
771
794
  i = 0;
772
- for (var transfer of transfers) {
795
+ for (const transfer of transfers) {
773
796
  assert.ok(timestamp > transfer.timestamp);
774
797
  timestamp = transfer.timestamp;
775
798
 
@@ -796,7 +819,7 @@ test('can get account transfers', async (): Promise<void> => {
796
819
  assert.strictEqual(account_balances.length, transfers.length)
797
820
 
798
821
  i = 0;
799
- for (var transfer of transfers) {
822
+ for (const transfer of transfers) {
800
823
  assert.ok(timestamp > transfer.timestamp);
801
824
  timestamp = transfer.timestamp;
802
825
 
@@ -954,9 +977,9 @@ test('can get account transfers', async (): Promise<void> => {
954
977
 
955
978
  test('can query accounts', async (): Promise<void> => {
956
979
  {
957
- var accounts : Account[] = [];
980
+ const accounts : Account[] = [];
958
981
  // Create transfers:
959
- for (var i=0; i<10;i++) {
982
+ for (let i=0; i<10;i++) {
960
983
  accounts.push({
961
984
  id: id(),
962
985
  debits_pending: 0n,
@@ -986,7 +1009,7 @@ test('can query accounts', async (): Promise<void> => {
986
1009
  // Querying accounts where:
987
1010
  // `user_data_128=1000 AND user_data_64=100 AND user_data_32=10
988
1011
  // AND code=999 AND ledger=1 ORDER BY timestamp ASC`.
989
- var filter: QueryFilter = {
1012
+ const filter: QueryFilter = {
990
1013
  user_data_128: 1000n,
991
1014
  user_data_64: 100n,
992
1015
  user_data_32: 10,
@@ -997,11 +1020,11 @@ test('can query accounts', async (): Promise<void> => {
997
1020
  limit: BATCH_MAX,
998
1021
  flags: QueryFilterFlags.none,
999
1022
  }
1000
- var query: Account[] = await client.queryAccounts(filter)
1023
+ const query: Account[] = await client.queryAccounts(filter)
1001
1024
  assert.strictEqual(query.length, 5)
1002
1025
 
1003
- var timestamp = 0n;
1004
- for (var account of query) {
1026
+ let timestamp = 0n;
1027
+ for (const account of query) {
1005
1028
  assert.ok(timestamp < account.timestamp);
1006
1029
  timestamp = account.timestamp;
1007
1030
 
@@ -1017,7 +1040,7 @@ test('can query accounts', async (): Promise<void> => {
1017
1040
  // Querying accounts where:
1018
1041
  // `user_data_128=2000 AND user_data_64=200 AND user_data_32=20
1019
1042
  // AND code=999 AND ledger=1 ORDER BY timestamp DESC`.
1020
- var filter: QueryFilter = {
1043
+ const filter: QueryFilter = {
1021
1044
  user_data_128: 2000n,
1022
1045
  user_data_64: 200n,
1023
1046
  user_data_32: 20,
@@ -1028,11 +1051,11 @@ test('can query accounts', async (): Promise<void> => {
1028
1051
  limit: BATCH_MAX,
1029
1052
  flags: QueryFilterFlags.reversed,
1030
1053
  }
1031
- var query: Account[] = await client.queryAccounts(filter)
1054
+ const query: Account[] = await client.queryAccounts(filter)
1032
1055
  assert.strictEqual(query.length, 5)
1033
1056
 
1034
- var timestamp = 1n << 64n;
1035
- for (var account of query) {
1057
+ let timestamp = 1n << 64n;
1058
+ for (const account of query) {
1036
1059
  assert.ok(timestamp > account.timestamp);
1037
1060
  timestamp = account.timestamp;
1038
1061
 
@@ -1047,7 +1070,7 @@ test('can query accounts', async (): Promise<void> => {
1047
1070
  {
1048
1071
  // Querying accounts where:
1049
1072
  // `code=999 ORDER BY timestamp ASC`
1050
- var filter: QueryFilter = {
1073
+ const filter: QueryFilter = {
1051
1074
  user_data_128: 0n,
1052
1075
  user_data_64: 0n,
1053
1076
  user_data_32: 0,
@@ -1058,11 +1081,11 @@ test('can query accounts', async (): Promise<void> => {
1058
1081
  limit: BATCH_MAX,
1059
1082
  flags: QueryFilterFlags.none,
1060
1083
  }
1061
- var query: Account[] = await client.queryAccounts(filter)
1084
+ const query: Account[] = await client.queryAccounts(filter)
1062
1085
  assert.strictEqual(query.length, 10)
1063
1086
 
1064
- var timestamp = 0n;
1065
- for (var account of query) {
1087
+ let timestamp = 0n;
1088
+ for (const account of query) {
1066
1089
  assert.ok(timestamp < account.timestamp);
1067
1090
  timestamp = account.timestamp;
1068
1091
 
@@ -1073,7 +1096,7 @@ test('can query accounts', async (): Promise<void> => {
1073
1096
  {
1074
1097
  // Querying accounts where:
1075
1098
  // `code=999 ORDER BY timestamp DESC LIMIT 5`.
1076
- var filter: QueryFilter = {
1099
+ const filter: QueryFilter = {
1077
1100
  user_data_128: 0n,
1078
1101
  user_data_64: 0n,
1079
1102
  user_data_32: 0,
@@ -1086,11 +1109,11 @@ test('can query accounts', async (): Promise<void> => {
1086
1109
  }
1087
1110
 
1088
1111
  // First 5 items:
1089
- var query: Account[] = await client.queryAccounts(filter)
1112
+ let query: Account[] = await client.queryAccounts(filter)
1090
1113
  assert.strictEqual(query.length, 5)
1091
1114
 
1092
- var timestamp = 1n << 64n;
1093
- for (var account of query) {
1115
+ let timestamp = 1n << 64n;
1116
+ for (const account of query) {
1094
1117
  assert.ok(timestamp > account.timestamp);
1095
1118
  timestamp = account.timestamp;
1096
1119
 
@@ -1102,7 +1125,7 @@ test('can query accounts', async (): Promise<void> => {
1102
1125
  query = await client.queryAccounts(filter)
1103
1126
  assert.strictEqual(query.length, 5)
1104
1127
 
1105
- for (var account of query) {
1128
+ for (const account of query) {
1106
1129
  assert.ok(timestamp > account.timestamp);
1107
1130
  timestamp = account.timestamp;
1108
1131
 
@@ -1117,7 +1140,7 @@ test('can query accounts', async (): Promise<void> => {
1117
1140
 
1118
1141
  {
1119
1142
  // Not found:
1120
- var filter: QueryFilter = {
1143
+ const filter: QueryFilter = {
1121
1144
  user_data_128: 0n,
1122
1145
  user_data_64: 200n,
1123
1146
  user_data_32: 10,
@@ -1128,7 +1151,7 @@ test('can query accounts', async (): Promise<void> => {
1128
1151
  limit: BATCH_MAX,
1129
1152
  flags: QueryFilterFlags.none,
1130
1153
  }
1131
- var query: Account[] = await client.queryAccounts(filter)
1154
+ const query: Account[] = await client.queryAccounts(filter)
1132
1155
  assert.strictEqual(query.length, 0)
1133
1156
  }
1134
1157
  })
@@ -1155,9 +1178,9 @@ test('can query transfers', async (): Promise<void> => {
1155
1178
  assert.ok(account_results[0].timestamp > 0)
1156
1179
  assert.deepStrictEqual(account_results[0].status, CreateAccountStatus.created)
1157
1180
 
1158
- var transfers_created : Transfer[] = [];
1181
+ const transfers_created : Transfer[] = [];
1159
1182
  // Create transfers:
1160
- for (var i=0; i<10;i++) {
1183
+ for (let i=0; i<10;i++) {
1161
1184
  transfers_created.push({
1162
1185
  id: id(),
1163
1186
  debit_account_id: i % 2 == 0 ? account.id : accountA.id,
@@ -1187,7 +1210,7 @@ test('can query transfers', async (): Promise<void> => {
1187
1210
  // Querying transfers where:
1188
1211
  // `user_data_128=1000 AND user_data_64=100 AND user_data_32=10
1189
1212
  // AND code=999 AND ledger=1 ORDER BY timestamp ASC`.
1190
- var filter: QueryFilter = {
1213
+ const filter: QueryFilter = {
1191
1214
  user_data_128: 1000n,
1192
1215
  user_data_64: 100n,
1193
1216
  user_data_32: 10,
@@ -1198,11 +1221,11 @@ test('can query transfers', async (): Promise<void> => {
1198
1221
  limit: BATCH_MAX,
1199
1222
  flags: QueryFilterFlags.none,
1200
1223
  }
1201
- var query: Transfer[] = await client.queryTransfers(filter)
1224
+ const query: Transfer[] = await client.queryTransfers(filter)
1202
1225
  assert.strictEqual(query.length, 5)
1203
1226
 
1204
- var timestamp = 0n;
1205
- for (var transfer of query) {
1227
+ let timestamp = 0n;
1228
+ for (const transfer of query) {
1206
1229
  assert.ok(timestamp < transfer.timestamp);
1207
1230
  timestamp = transfer.timestamp;
1208
1231
 
@@ -1218,7 +1241,7 @@ test('can query transfers', async (): Promise<void> => {
1218
1241
  // Querying transfers where:
1219
1242
  // `user_data_128=2000 AND user_data_64=200 AND user_data_32=20
1220
1243
  // AND code=999 AND ledger=1 ORDER BY timestamp DESC`.
1221
- var filter: QueryFilter = {
1244
+ const filter: QueryFilter = {
1222
1245
  user_data_128: 2000n,
1223
1246
  user_data_64: 200n,
1224
1247
  user_data_32: 20,
@@ -1229,11 +1252,11 @@ test('can query transfers', async (): Promise<void> => {
1229
1252
  limit: BATCH_MAX,
1230
1253
  flags: QueryFilterFlags.reversed,
1231
1254
  }
1232
- var query: Transfer[] = await client.queryTransfers(filter)
1255
+ const query: Transfer[] = await client.queryTransfers(filter)
1233
1256
  assert.strictEqual(query.length, 5)
1234
1257
 
1235
- var timestamp = 1n << 64n;
1236
- for (var transfer of query) {
1258
+ let timestamp = 1n << 64n;
1259
+ for (const transfer of query) {
1237
1260
  assert.ok(timestamp > transfer.timestamp);
1238
1261
  timestamp = transfer.timestamp;
1239
1262
 
@@ -1248,7 +1271,7 @@ test('can query transfers', async (): Promise<void> => {
1248
1271
  {
1249
1272
  // Querying transfers where:
1250
1273
  // `code=999 ORDER BY timestamp ASC`
1251
- var filter: QueryFilter = {
1274
+ const filter: QueryFilter = {
1252
1275
  user_data_128: 0n,
1253
1276
  user_data_64: 0n,
1254
1277
  user_data_32: 0,
@@ -1259,11 +1282,11 @@ test('can query transfers', async (): Promise<void> => {
1259
1282
  limit: BATCH_MAX,
1260
1283
  flags: QueryFilterFlags.none,
1261
1284
  }
1262
- var query: Transfer[] = await client.queryTransfers(filter)
1285
+ const query: Transfer[] = await client.queryTransfers(filter)
1263
1286
  assert.strictEqual(query.length, 10)
1264
1287
 
1265
- var timestamp = 0n;
1266
- for (var transfer of query) {
1288
+ let timestamp = 0n;
1289
+ for (const transfer of query) {
1267
1290
  assert.ok(timestamp < transfer.timestamp);
1268
1291
  timestamp = transfer.timestamp;
1269
1292
 
@@ -1274,7 +1297,7 @@ test('can query transfers', async (): Promise<void> => {
1274
1297
  {
1275
1298
  // Querying transfers where:
1276
1299
  // `code=999 ORDER BY timestamp DESC LIMIT 5`.
1277
- var filter: QueryFilter = {
1300
+ const filter: QueryFilter = {
1278
1301
  user_data_128: 0n,
1279
1302
  user_data_64: 0n,
1280
1303
  user_data_32: 0,
@@ -1287,11 +1310,11 @@ test('can query transfers', async (): Promise<void> => {
1287
1310
  }
1288
1311
 
1289
1312
  // First 5 items:
1290
- var query: Transfer[] = await client.queryTransfers(filter)
1313
+ let query: Transfer[] = await client.queryTransfers(filter)
1291
1314
  assert.strictEqual(query.length, 5)
1292
1315
 
1293
- var timestamp = 1n << 64n;
1294
- for (var transfer of query) {
1316
+ let timestamp = 1n << 64n;
1317
+ for (const transfer of query) {
1295
1318
  assert.ok(timestamp > transfer.timestamp);
1296
1319
  timestamp = transfer.timestamp;
1297
1320
 
@@ -1303,7 +1326,7 @@ test('can query transfers', async (): Promise<void> => {
1303
1326
  query = await client.queryTransfers(filter)
1304
1327
  assert.strictEqual(query.length, 5)
1305
1328
 
1306
- for (var transfer of query) {
1329
+ for (const transfer of query) {
1307
1330
  assert.ok(timestamp > transfer.timestamp);
1308
1331
  timestamp = transfer.timestamp;
1309
1332
 
@@ -1318,7 +1341,7 @@ test('can query transfers', async (): Promise<void> => {
1318
1341
 
1319
1342
  {
1320
1343
  // Not found:
1321
- var filter: QueryFilter = {
1344
+ const filter: QueryFilter = {
1322
1345
  user_data_128: 0n,
1323
1346
  user_data_64: 200n,
1324
1347
  user_data_32: 10,
@@ -1329,7 +1352,7 @@ test('can query transfers', async (): Promise<void> => {
1329
1352
  limit: BATCH_MAX,
1330
1353
  flags: QueryFilterFlags.none,
1331
1354
  }
1332
- var query: Transfer[] = await client.queryTransfers(filter)
1355
+ const query: Transfer[] = await client.queryTransfers(filter)
1333
1356
  assert.strictEqual(query.length, 0)
1334
1357
  }
1335
1358
  })
@@ -1461,7 +1484,7 @@ test('can import accounts and transfers', async (): Promise<void> => {
1461
1484
 
1462
1485
  // Wait 10 ms so we can use the account's timestamp as the reference for past time
1463
1486
  // after the last object inserted.
1464
- await new Promise(_ => setTimeout(_, 10));
1487
+ await sleep_ms(10);
1465
1488
 
1466
1489
  const accountA: Account = {
1467
1490
  id: id(),
@@ -1552,14 +1575,48 @@ test('accept zero-length lookup_transfers', async (): Promise<void> => {
1552
1575
  })
1553
1576
 
1554
1577
  test("destroy client in-flight", async (): Promise<void> => {
1555
- // Non-existing cluster.
1556
- const client = createClient({ cluster_id: 92n, replica_addresses: ["99"] });
1557
- setTimeout(() => client.destroy(), 30);
1558
- assert.rejects(async () => await client.lookupAccounts([0n]), (err) => {
1559
- assert.ok(err instanceof RequestError)
1560
- assert.strictEqual(err.code, ErrorCodes.ERR_CLIENT_CLOSED)
1561
- return true
1562
- })
1578
+ const client_count = 5;
1579
+ const action_count = 50;
1580
+
1581
+ const clients = range(client_count).map(() =>
1582
+ createClient({
1583
+ cluster_id: 0n,
1584
+ replica_addresses: REPLICA_ADDRESSES,
1585
+ })
1586
+ );
1587
+
1588
+ const ids: Array<bigint> = [];
1589
+ const actions = range(action_count).map(() => async () => {
1590
+ await sleep_ms(Math.random() < 0.2 ? 0 : Math.random());
1591
+ const client = clients[random_index(clients)];
1592
+ if (Math.random() < 0.1) {
1593
+ client.destroy();
1594
+ return;
1595
+ }
1596
+ if (Math.random() < 0.7) {
1597
+ const id_new = id();
1598
+ ids.push(id_new);
1599
+ try {
1600
+ await client.createAccounts([{ ...accountA, id: id_new }]);
1601
+ } catch (err) {
1602
+ assert.ok(err instanceof RequestError);
1603
+ assert.strictEqual(err.code, ErrorCodes.ERR_CLIENT_CLOSED);
1604
+ }
1605
+ return;
1606
+ }
1607
+ try {
1608
+ const id_lookup = (Math.random() < 0.2 || ids.length == 0)
1609
+ ? BigInt(Math.floor(Math.random() * 10000))
1610
+ : ids[random_index(ids)];
1611
+ await client.lookupAccounts([id_lookup]);
1612
+ } catch (err) {
1613
+ assert.ok(err instanceof RequestError);
1614
+ assert.strictEqual(err.code, ErrorCodes.ERR_CLIENT_CLOSED);
1615
+ }
1616
+ });
1617
+
1618
+ await Promise.all(actions.map((f) => f()));
1619
+ for (const client of clients) client.destroy();
1563
1620
  });
1564
1621
 
1565
1622
  async function main () {