import 'dart:async'; import 'dart:convert'; import 'dart:math'; import 'package:flutter_test/flutter_test.dart'; import 'package:veilid/veilid.dart'; Future 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 testAppMessageLoopback(Stream updateStream) async { final appMessageQueue = StreamController(); 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 testAppCallLoopback(Stream updateStream) async { final appCallQueue = StreamController(); 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 testAppMessageLoopbackBigPackets( Stream updateStream) async { final appMessageQueue = StreamController(); final appMessageSubscription = updateStream.listen((update) { if (update is VeilidAppMessage) { appMessageQueue.sink.add(update); } }); final sentMessages = {}; 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 testAppCallLoopbackBigPackets( Stream updateStream) async { final appCallQueue = StreamController(); 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 = {}; 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; }