blob: 36a8cb91d8481d273bbc28763be572c444155038 [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.
import "dart:async";
import "dart:io";
import "dart:isolate";
import "package:sync_http/sync_http.dart";
import "package:test/test.dart";
typedef void ServerCallback(int? port);
class TestServerMain {
TestServerMain() : _statusPort = new ReceivePort();
ReceivePort _statusPort; // Port for receiving messages from the server.
late SendPort _serverPort; // Port for sending messages to the server.
late ServerCallback _startedCallback;
void setServerStartedHandler(ServerCallback startedCallback) {
_startedCallback = startedCallback;
}
void start() {
ReceivePort receivePort = new ReceivePort();
Isolate.spawn(startTestServer, receivePort.sendPort);
receivePort.first.then((port) {
_serverPort = port!;
// Send server start message to the server.
var command = new TestServerCommand.start();
port.send([command, _statusPort.sendPort]);
});
// Handle status messages from the server.
_statusPort.listen((var status) {
if (status.isStarted) {
_startedCallback(status.port);
}
});
}
void close() {
// Send server stop message to the server.
_serverPort.send([new TestServerCommand.stop(), _statusPort.sendPort]);
_statusPort.close();
}
}
enum TestServerCommandState {
start,
stop,
}
class TestServerCommand {
TestServerCommand.start() : _command = TestServerCommandState.start;
TestServerCommand.stop() : _command = TestServerCommandState.stop;
bool get isStart => (_command == TestServerCommandState.start);
bool get isStop => (_command == TestServerCommandState.stop);
TestServerCommandState _command;
}
enum TestServerStatusState {
started,
stopped,
error,
}
class TestServerStatus {
TestServerStatus.started(this._port) : _state = TestServerStatusState.started;
TestServerStatus.stopped() : _state = TestServerStatusState.stopped;
TestServerStatus.error() : _state = TestServerStatusState.error;
bool get isStarted => (_state == TestServerStatusState.started);
bool get isStopped => (_state == TestServerStatusState.stopped);
bool get isError => (_state == TestServerStatusState.error);
int? get port => _port;
TestServerStatusState _state;
int? _port;
}
void startTestServer(SendPort replyTo) {
var server = new TestServer();
server.init();
replyTo.send(server.dispatchSendPort);
}
class TestServer {
// Echo the request content back to the response.
void _echoHandler(HttpRequest request) {
var response = request.response;
if (request.method != "POST") {
response.close();
return;
}
response.contentLength = request.contentLength;
request.listen((List<int> data) {
var string = new String.fromCharCodes(data);
response.write(string);
response.close();
});
}
// Echo the request content back to the response.
void _zeroToTenHandler(HttpRequest request) {
var response = request.response;
String msg = "01234567890";
if (request.method != "GET") {
response.close();
return;
}
response.contentLength = msg.length;
response.write(msg);
response.close();
}
// Return a 404.
void _notFoundHandler(HttpRequest request) {
var response = request.response;
response.statusCode = HttpStatus.notFound;
String msg = "Page not found";
response.contentLength = msg.length;
response.headers.set("Content-Type", "text/html; charset=UTF-8");
response.write(msg);
response.close();
}
// Return a 301 with a custom reason phrase.
void _reasonForMovingHandler(HttpRequest request) {
var response = request.response;
response.statusCode = HttpStatus.movedPermanently;
response.reasonPhrase = "Don't come looking here any more";
response.close();
}
// Check the "Host" header.
void _hostHandler(HttpRequest request) {
var response = request.response;
expect(1, equals(request.headers["Host"]!.length));
expect("dart.dev:1234", equals(request.headers["Host"]![0]));
expect("dart.dev", equals(request.headers.host));
expect(1234, equals(request.headers.port));
response.statusCode = HttpStatus.ok;
response.close();
}
void _hugeHandler(HttpRequest request) {
var response = request.response;
List<int> expected =
new List<int>.generate((1 << 20), (i) => (i + 1) % 256);
String msg = expected.toString();
response.contentLength = msg.length;
response.statusCode = HttpStatus.ok;
response.write(msg);
response.close();
}
void init() {
// Setup request handlers.
_requestHandlers = new Map();
_requestHandlers["/echo"] = _echoHandler;
_requestHandlers["/0123456789"] = _zeroToTenHandler;
_requestHandlers["/reasonformoving"] = _reasonForMovingHandler;
_requestHandlers["/host"] = _hostHandler;
_requestHandlers["/huge"] = _hugeHandler;
_dispatchPort = new ReceivePort();
_dispatchPort.listen(dispatch);
}
SendPort get dispatchSendPort => _dispatchPort.sendPort;
dispatch(var message) async {
TestServerCommand command = message[0];
SendPort replyTo = message[1]!;
if (command.isStart) {
try {
var addr = (await InternetAddress.lookup("localhost"))[0];
HttpServer.bind(addr, 0).then((server) {
_server = server;
_server.listen(_requestReceivedHandler);
replyTo.send(new TestServerStatus.started(_server.port));
});
} catch (e) {
replyTo.send(new TestServerStatus.error());
}
} else if (command.isStop) {
_server.close();
_dispatchPort.close();
replyTo.send(new TestServerStatus.stopped());
}
}
void _requestReceivedHandler(HttpRequest request) {
var requestHandler = _requestHandlers[request.uri.path];
if (requestHandler != null) {
requestHandler(request);
} else {
_notFoundHandler(request);
}
}
late HttpServer _server; // HTTP server instance.
late ReceivePort _dispatchPort;
late Map _requestHandlers;
}
Future testStartStop() async {
Completer completer = new Completer();
TestServerMain testServerMain = new TestServerMain();
testServerMain.setServerStartedHandler((int? port) {
testServerMain.close();
completer.complete();
});
testServerMain.start();
return completer.future;
}
Future testGET() async {
Completer completer = new Completer();
TestServerMain testServerMain = new TestServerMain();
testServerMain.setServerStartedHandler((int? port) {
var request =
SyncHttpClient.getUrl(new Uri.http("localhost:$port", "/0123456789"));
var response = request.close();
expect(HttpStatus.ok, equals(response.statusCode));
expect(11, equals(response.contentLength));
expect("01234567890", equals(response.body));
testServerMain.close();
completer.complete();
});
testServerMain.start();
return completer.future;
}
Future testPOST() async {
Completer completer = new Completer();
String data = "ABCDEFGHIJKLMONPQRSTUVWXYZ";
final int kMessageCount = 10;
TestServerMain testServerMain = new TestServerMain();
void runTest(int? port) {
int count = 0;
void sendRequest() {
var request =
SyncHttpClient.postUrl(new Uri.http("localhost:$port", "/echo"));
request.write(data);
var response = request.close();
expect(HttpStatus.ok, equals(response.statusCode));
expect(data, equals(response.body));
count++;
if (count < kMessageCount) {
sendRequest();
} else {
testServerMain.close();
completer.complete();
}
}
sendRequest();
}
testServerMain.setServerStartedHandler(runTest);
testServerMain.start();
return completer.future;
}
Future test404() async {
Completer completer = new Completer();
TestServerMain testServerMain = new TestServerMain();
testServerMain.setServerStartedHandler((int? port) {
var request = SyncHttpClient.getUrl(
new Uri.http("localhost:$port", "/thisisnotfound"));
var response = request.close();
expect(HttpStatus.notFound, equals(response.statusCode));
expect("Page not found", equals(response.body));
testServerMain.close();
completer.complete();
});
testServerMain.start();
return completer.future;
}
Future testReasonPhrase() async {
Completer completer = new Completer();
TestServerMain testServerMain = new TestServerMain();
testServerMain.setServerStartedHandler((int? port) {
var request = SyncHttpClient.getUrl(
new Uri.http("localhost:$port", "/reasonformoving"));
var response = request.close();
expect(HttpStatus.movedPermanently, equals(response.statusCode));
expect(
"Don't come looking here any more\r\n", equals(response.reasonPhrase));
testServerMain.close();
completer.complete();
});
testServerMain.start();
return completer.future;
}
Future testHuge() async {
Completer completer = new Completer();
TestServerMain testServerMain = new TestServerMain();
testServerMain.setServerStartedHandler((int? port) {
var request =
SyncHttpClient.getUrl(new Uri.http("localhost:$port", "/huge"));
var response = request.close();
String expected =
new List<int>.generate((1 << 20), (i) => (i + 1) % 256).toString();
expect(HttpStatus.ok, equals(response.statusCode));
expect(expected.length, equals(response.contentLength));
expect(expected.toString(), equals(response.body));
testServerMain.close();
completer.complete();
});
testServerMain.start();
return completer.future;
}
void main() {
test("Simple server test", () async {
await testStartStop();
});
test("Sync HTTP GET test", () async {
await testGET();
});
test("Sync HTTP POST test", () async {
await testPOST();
});
test("Sync HTTP 404 test", () async {
await test404();
});
test("Sync HTTP moved test", () async {
await testReasonPhrase();
});
test("Sync HTTP huge test", () async {
await testHuge();
});
}