blob: fb302e8b206ddd97c3045e07b09b4ab3ed50937b [file] [log] [blame]
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// @dart = 2.9
/// http and web sockets utils
/// @author a.semenov@unipro.ru
library http_utils;
import "dart:io";
import "dart:async";
import "../../Utils/expect.dart";
/**
* Spawns a HttpServer instance
*/
Future<HttpServer> spawnHttpServer(void requestHandler(HttpRequest request)) async {
HttpServer server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
server.listen(requestHandler);
return server;
}
/**
* Spawns a HttpServer instance that is intended to handle web sockets.
*/
Future<HttpServer> spawnWebSocketServer(void wsHandler(WebSocket webSocket)) {
return spawnHttpServer((HttpRequest request) {
WebSocketTransformer.upgrade(request).then(wsHandler);
});
}
/**
* Spawns a HttpServer instance that is intended to handle web sockets.
* Each new connection receives the same [content] and then closed.
*/
Future<HttpServer> spawnStaticContentWebSocketServer(content) {
return spawnWebSocketServer((WebSocket webSocket) {
webSocket.add(content);
webSocket.close();
});
}
/**
* Spawns a HttpServer instance that is intended to handle web sockets.
* Each new connection is listened for first message and send it back,
* then web socket is closed.
*/
Future<HttpServer> spawnEchoWebSocketServer() {
return spawnWebSocketServer((WebSocket webSocket) async {
webSocket.add(await webSocket.first);
webSocket.close();
});
}
List<int> _bigData = null;
List<int> get bigData {
if (_bigData == null) {
_bigData = getList(8187);
}
return _bigData;
}
List<int> getList(int size) {
List<int> l = [];
for (int j = 0; j < size; j++) {
l.add(j);
}
return l;
}
Future<List<int>> sendDatagramOnce(RawDatagramSocket producer,
List<List<int>> data, InternetAddress address, int port,
{Duration period = const Duration(milliseconds: 1)}) {
List<int> sent = [];
Completer<List<int>> completer = new Completer<List<int>>();
Future<List<int>> f = completer.future;
if (data != null) {
int i = 0;
new Timer.periodic(period, (timer) {
if (i < data.length) {
sent.add(producer.send(data[i++], address, port));
} else {
timer.cancel();
completer.complete(sent);
}
});
} else {
completer.complete(sent);
}
return f;
}
Future<bool> sendDatagram(RawDatagramSocket producer, List<List<int>> data,
InternetAddress address, int port,
{Duration period = const Duration(milliseconds: 1), int attempts = 5,
bool closeProducer = true}) async {
for (int attempt = 0; attempt < attempts; attempt++) {
List<int> bytesWritten = await sendDatagramOnce(producer, data, address, port,
period: period);
if (wasSent(bytesWritten)) {
compareSentData(data, bytesWritten);
if (closeProducer) {
producer.close();
}
return true;
}
}
producer.close();
return false;
}
/***
* Check that there is any buffer size > 0
*/
bool wasSent(List<int> bytesWritten) {
for (int i = 0; i < bytesWritten.length; i++) {
if (bytesWritten[i] > 0) {
return true;
}
}
return false;
}
compareSentData(List<List<int>> data, List<int> sentStatus) {
Expect.equals(sentStatus.length, data.length, "Wrong sizes of sent and sentResult");
for (int i = 0; i < data.length; i++) {
if (sentStatus[i] == 0) {
continue;
}
Expect.equals(data[i].length, sentStatus[i]);
}
}
Future<List<List<int>>> receiveDatagram(RawDatagramSocket receiver,
{Duration delay = const Duration(seconds: 2), RawSocketEvent event}) {
List<List<int>> received = [];
Completer<List<List<int>>> completer = new Completer<List<List<int>>>();
Future<List<List<int>>> f = completer.future;
receiver.listen((_event) {
var datagram = receiver.receive();
if (event == null || _event == event) {
received.add(datagram?.data);
}
if (_event == RawSocketEvent.closed) {
if(!completer.isCompleted) {
completer.complete(received);
}
}
});
new Future.delayed(delay, () {
if(!completer.isCompleted) {
receiver.close();
completer.complete(received);
}
});
return f;
}
/**
* If we receive datagram we check if received data can be found among sent ones
*/
compareReceivedData(List<List<int>> sent, List<List<int>> received) {
Expect.isTrue(received.length <= sent.length, "${received.length} <= ${sent.length}");
for (int i = 0; i < received.length; i++) {
if (received[i] == null) {
continue;
}
bool found = false;
for (int j = 0; j < sent.length; j++) {
if (_listEquals(received[i], sent[j])) {
found = true;
break;
}
}
Expect.isTrue(found, "${received[i]} not found among $sent");
}
}
bool _listEquals(List<int> list1, List<int> list2) {
if (list1.length == list2.length) {
for (int i = 0; i < list1.length; i++) {
if (list1[i] != list2[i]) {
return false;
}
}
return true;
}
return false;
}
Future<List<RawSocketEvent>> anyElement(RawDatagramSocket receiver,
RawSocketEvent expectedEvent, bool shouldFind,
{Duration delay = const Duration(seconds: 2)}) {
List<RawSocketEvent> tested = [];
Completer<List<RawSocketEvent>> completer =
new Completer<List<RawSocketEvent>>();
Future<List<RawSocketEvent>> f = completer.future;
bool test(x) {
tested.add(x);
receiver.receive();
if (x == RawSocketEvent.closed) {
if (!completer.isCompleted) {
completer.complete(tested);
}
}
return x == expectedEvent;
}
receiver.any((event) => test(event)).then((value) {
if (shouldFind) {
Expect.equals(true, value);
} else {
Expect.equals(false, value);
}
if (!completer.isCompleted) {
receiver.close();
completer.complete(tested);
}
});
new Future.delayed(delay, () {
if (!completer.isCompleted) {
receiver.close();
}
});
return f;
}
checkTested<T>(List<T> tested, T expected) {
for (int i = tested.length - 2; i >= 0; i--) {
Expect.notEquals(expected, tested[i]);
}
}
checkReceived(check, List<RawSocketEvent> expectedValues, int expectedLen,
{int attempts = 5}) async {
for (int i = 0; i < attempts; i++) {
List list = await check();
int listLen = list.length;
if (listLen == 0) {
continue;
}
if (listLen > 0 && listLen <= expectedLen) {
for (int i = 0; i < list.length; i++) {
Expect.isTrue(
expectedValues.contains(list[i]), "Unexpected value ${list[i]}");
}
break;
}
if (listLen > expectedLen) {
Expect.fail("$listLen elements found instead of $expectedLen.");
}
if (i == attempts - 1) {
print('$listLen elements found. Look like test failed.');
}
}
}