veilid/veilid-flutter/example/integration_test/test_routing_context.dart
2024-05-02 14:15:42 -04:00

270 lines
8.5 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'dart:math';
import 'package:flutter_test/flutter_test.dart';
import 'package:veilid/veilid.dart';
Future<void> testRoutingContexts() async {
{
final rc = await Veilid.instance.routingContext();
rc.close();
}
{
final rc = await Veilid.instance.routingContext();
final rcp = rc.withDefaultSafety();
// ignore: cascade_invocations
rcp.close();
rc.close();
}
{
final rc = await Veilid.instance.routingContext();
final rcp = rc.withSequencing(Sequencing.ensureOrdered);
// ignore: cascade_invocations
rcp.close();
rc.close();
}
{
final rc = await Veilid.instance.routingContext();
final rcp = rc.withSafety(const SafetySelectionSafe(
safetySpec: SafetySpec(
hopCount: 2,
stability: Stability.lowLatency,
sequencing: Sequencing.noPreference)));
// ignore: cascade_invocations
rcp.close();
rc.close();
}
{
final rc = await Veilid.instance.routingContext();
final rcp = rc.withSafety(
const SafetySelectionUnsafe(sequencing: Sequencing.preferOrdered));
// ignore: cascade_invocations
rcp.close();
rc.close();
}
}
Future<void> testAppMessageLoopback(Stream<VeilidUpdate> updateStream) async {
final appMessageQueue = StreamController<VeilidAppMessage>();
final appMessageSubscription = updateStream.listen((update) {
if (update is VeilidAppMessage) {
appMessageQueue.sink.add(update);
}
});
try {
await Veilid.instance.debug('purge routes');
// make a routing context that uses a safety route
final rc = await Veilid.instance.routingContext();
try {
// make a new local private route
final prl = await Veilid.instance.newPrivateRoute();
try {
// import it as a remote route as well so we can send to it
final prr = await Veilid.instance.importRemotePrivateRoute(prl.blob);
try {
// send an app message to our own private route
final message = utf8.encode('abcd1234');
await rc.appMessage(prr, message);
// we should get the same message back
final update = await appMessageQueue.stream.first;
expect(update.message, equals(message));
expect(update.routeId, isNotNull);
} finally {
await Veilid.instance.releasePrivateRoute(prr);
}
} finally {
await Veilid.instance.releasePrivateRoute(prl.routeId);
}
} finally {
rc.close();
}
} finally {
await appMessageSubscription.cancel();
await appMessageQueue.close();
}
}
Future<void> testAppCallLoopback(Stream<VeilidUpdate> updateStream) async {
final appCallQueue = StreamController<VeilidAppCall>();
final appMessageSubscription = updateStream.listen((update) {
if (update is VeilidAppCall) {
appCallQueue.sink.add(update);
}
});
try {
await Veilid.instance.debug('purge routes');
// make a routing context that uses a safety route
final rc = await Veilid.instance.routingContext();
try {
// make a new local private route
final prl = await Veilid.instance.newPrivateRoute();
try {
// import it as a remote route as well so we can send to it
final prr = await Veilid.instance.importRemotePrivateRoute(prl.blob);
try {
// send an app call to our own private route
final message = utf8.encode('abcd1234');
final appCallFuture = rc.appCall(prr, message);
// we should get the same call back
final update = await appCallQueue.stream.first;
final appcallid = update.callId;
expect(update.message, equals(message));
expect(update.routeId, isNotNull);
// now we reply to the request
final reply = utf8.encode('qwer5678');
await Veilid.instance.appCallReply(appcallid, reply);
// now we should get the reply from the call
final result = await appCallFuture;
expect(result, equals(reply));
} finally {
await Veilid.instance.releasePrivateRoute(prr);
}
} finally {
await Veilid.instance.releasePrivateRoute(prl.routeId);
}
} finally {
rc.close();
}
} finally {
await appMessageSubscription.cancel();
await appCallQueue.close();
}
}
Future<void> testAppMessageLoopbackBigPackets(
Stream<VeilidUpdate> updateStream) async {
final appMessageQueue = StreamController<VeilidAppMessage>();
final appMessageSubscription = updateStream.listen((update) {
if (update is VeilidAppMessage) {
appMessageQueue.sink.add(update);
}
});
final sentMessages = <String>{};
final random = Random.secure();
final cs = await Veilid.instance.bestCryptoSystem();
try {
await Veilid.instance.debug('purge routes');
// make a routing context that uses a safety route
final rc = await Veilid.instance.routingContext();
try {
// make a new local private route
final prl = await Veilid.instance.newPrivateRoute();
try {
// import it as a remote route as well so we can send to it
final prr = await Veilid.instance.importRemotePrivateRoute(prl.blob);
final appMessageQueueIterator = StreamIterator(appMessageQueue.stream);
try {
for (var i = 0; i < 5; i++) {
// send an app message to our own private route
final message = await cs.randomBytes(random.nextInt(32768));
await rc.appMessage(prr, message);
sentMessages.add(base64Url.encode(message));
}
// we should get the same messages back
for (var i = 0; i < sentMessages.length; i++) {
if (await appMessageQueueIterator.moveNext()) {
final update = appMessageQueueIterator.current;
expect(sentMessages.contains(base64Url.encode(update.message)),
isTrue);
} else {
fail('not enough messages in the queue');
}
}
} finally {
await appMessageQueueIterator.cancel();
await Veilid.instance.releasePrivateRoute(prr);
}
} finally {
await Veilid.instance.releasePrivateRoute(prl.routeId);
}
} finally {
rc.close();
}
} finally {
await appMessageSubscription.cancel();
await appMessageQueue.close();
}
}
Future<void> testAppCallLoopbackBigPackets(
Stream<VeilidUpdate> updateStream) async {
final appCallQueue = StreamController<VeilidAppCall>();
final appMessageSubscription = updateStream.listen((update) {
if (update is VeilidAppCall) {
appCallQueue.sink.add(update);
}
});
final appCallQueueHandler = () async {
await for (final update in appCallQueue.stream) {
await Veilid.instance.appCallReply(update.callId, update.message);
}
}();
final sentMessages = <String>{};
final random = Random.secure();
final cs = await Veilid.instance.bestCryptoSystem();
try {
await Veilid.instance.debug('purge routes');
// make a routing context that uses a safety route
final rc = await Veilid.instance.routingContext();
try {
// make a new local private route
final prl = await Veilid.instance.newPrivateRoute();
try {
// import it as a remote route as well so we can send to it
final prr = await Veilid.instance.importRemotePrivateRoute(prl.blob);
final appMessageQueueIterator = StreamIterator(appCallQueue.stream);
try {
for (var i = 0; i < 5; i++) {
// send an app message to our own private route
final message = await cs.randomBytes(random.nextInt(32768));
final outmessage = await rc.appCall(prr, message);
expect(message, equals(outmessage));
}
// we should get the same messages back
for (var i = 0; i < sentMessages.length; i++) {
if (await appMessageQueueIterator.moveNext()) {
final update = appMessageQueueIterator.current;
expect(sentMessages.contains(base64Url.encode(update.message)),
isTrue);
} else {
fail('not enough messages in the queue');
}
}
} finally {
await appMessageQueueIterator.cancel();
await Veilid.instance.releasePrivateRoute(prr);
}
} finally {
await Veilid.instance.releasePrivateRoute(prl.routeId);
}
} finally {
rc.close();
}
} finally {
await appMessageSubscription.cancel();
}
await appCallQueue.close();
await appCallQueueHandler;
}