blob: 80c16ca20020cf591444c110df9416cf9288e09b [file] [log] [blame]
// Copyright (c) 2013, 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.
library utils;
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import "package:unittest/unittest.dart";
import 'package:http_server/http_server.dart';
import 'http_mock.dart';
/**
* Used to flag a given test case as being a mock or not.
*/
final _isMockTestExpando = new Expando<bool>('isMockTest');
void testVirtualDir(String name, Future func(Directory dir)) {
_testVirtualDir(name, false, func);
_testVirtualDir(name, true, func);
}
void _testVirtualDir(String name, bool useMocks, Future func(Directory dir)) {
if(useMocks) {
name = '$name, with mocks';
}
test(name, () {
// see subsequent access to this expando below
_isMockTestExpando[currentTestCase] = useMocks;
var dir = Directory.systemTemp.createTempSync('http_server_virtual_');
return func(dir)
.whenComplete(() {
return dir.delete(recursive: true);
});
});
}
Future<int> getStatusCodeForVirtDir(VirtualDirectory virtualDir,
String path,
{String host,
bool secure: false,
DateTime ifModifiedSince,
bool rawPath: false,
bool followRedirects: true,
int from,
int to}) {
// if this is a mock test, then run the mock code path
if(_isMockTestExpando[currentTestCase]) {
var uri = _getUri(0, path, secure: secure, rawPath: rawPath);
var request = new MockHttpRequest(uri, followRedirects: followRedirects,
ifModifiedSince: ifModifiedSince);
_addRangeHeader(request, from, to);
return _withMockRequest(virtualDir, request)
.then((response) {
return response.statusCode;
});
};
assert(_isMockTestExpando[currentTestCase] == false);
return _withServer(virtualDir, (port) {
return getStatusCode(port, path, host: host, secure: secure,
ifModifiedSince: ifModifiedSince, rawPath: rawPath,
followRedirects: followRedirects, from: from, to: to);
});
}
Future<int> getStatusCode(int port,
String path,
{String host,
bool secure: false,
DateTime ifModifiedSince,
bool rawPath: false,
bool followRedirects: true,
int from,
int to}) {
var uri = _getUri(port, path, secure: secure, rawPath: rawPath);
var client = new HttpClient();
return client.getUrl(uri)
.then((request) {
if (!followRedirects) request.followRedirects = false;
if (host != null) request.headers.host = host;
if (ifModifiedSince != null) {
request.headers.ifModifiedSince = ifModifiedSince;
}
_addRangeHeader(request, from, to);
return request.close();
})
.then((response) => response.drain()
.then((_) => response.statusCode))
.whenComplete(() => client.close());
}
Future<HttpHeaders> getHeaders(
VirtualDirectory virDir, String path, {int from, int to}) {
// if this is a mock test, then run the mock code path
if(_isMockTestExpando[currentTestCase]) {
var uri = _getUri(0, path);
var request = new MockHttpRequest(uri);
_addRangeHeader(request, from, to);
return _withMockRequest(virDir, request)
.then((response) {
return response.headers;
});
}
assert(_isMockTestExpando[currentTestCase] == false);
return _withServer(virDir, (port) {
return _getHeaders(port, path, from, to);
});
}
Future<String> getAsString(VirtualDirectory virtualDir, String path) {
// if this is a mock test, then run the mock code path
if(_isMockTestExpando[currentTestCase]) {
var uri = _getUri(0, path);
var request = new MockHttpRequest(uri);
return _withMockRequest(virtualDir, request)
.then((response) {
return response.mockContent;
});
};
assert(_isMockTestExpando[currentTestCase] == false);
return _withServer(virtualDir, (int port) {
return _getAsString(port, path);
});
}
Future<List<int>> getAsBytes(
VirtualDirectory virtualDir, String path, {int from, int to}) {
// if this is a mock test, then run the mock code path
if (_isMockTestExpando[currentTestCase]) {
var uri = _getUri(0, path);
var request = new MockHttpRequest(uri);
_addRangeHeader(request, from, to);
return _withMockRequest(virtualDir, request)
.then((response) {
return response.mockContentBinary;
});
};
assert(_isMockTestExpando[currentTestCase] == false);
return _withServer(virtualDir, (int port) {
return _getAsBytes(port, path, from, to);
});
}
Future<List> getContentAndResponse(
VirtualDirectory virtualDir, String path, {int from, int to}) {
// if this is a mock test, then run the mock code path
if (_isMockTestExpando[currentTestCase]) {
var uri = _getUri(0, path);
var request = new MockHttpRequest(uri);
_addRangeHeader(request, from, to);
return _withMockRequest(virtualDir, request)
.then((response) {
return [response.mockContentBinary,
response];
});
};
assert(_isMockTestExpando[currentTestCase] == false);
return _withServer(virtualDir, (int port) {
return _getContentAndResponse(port, path, from, to);
});
}
Future<MockHttpResponse> _withMockRequest(VirtualDirectory virDir,
MockHttpRequest request) {
return virDir.serveRequest(request).then((value) {
expect(value, isNull);
expect(request.response.mockDone, isTrue);
return request.response;
})
.then((HttpResponse response) {
if(response.statusCode == HttpStatus.MOVED_PERMANENTLY ||
response.statusCode == HttpStatus.MOVED_TEMPORARILY) {
if(request.followRedirects == true) {
var uri = Uri.parse(response.headers.value(HttpHeaders.LOCATION));
var newMock = new MockHttpRequest(uri, followRedirects: true);
return _withMockRequest(virDir, newMock);
}
}
return response;
});
}
Future _withServer(VirtualDirectory virDir, Future func(int port)) {
HttpServer server;
return HttpServer.bind('localhost', 0)
.then((value) {
server = value;
virDir.serve(server);
return func(server.port);
})
.whenComplete(() => server.close());
}
Future<HttpHeaders> _getHeaders(int port, String path, int from, int to) {
var client = new HttpClient();
return client.get('localhost', port, path)
.then((request) {
_addRangeHeader(request, from, to);
return request.close();
})
.then((response) => response.drain()
.then((_) => response.headers))
.whenComplete(() => client.close());
}
Future<String> _getAsString(int port, String path) {
var client = new HttpClient();
return client.get('localhost', port, path)
.then((request) => request.close())
.then((response) => UTF8.decodeStream(response))
.whenComplete(() => client.close());
}
Future<List<int>> _getAsBytes(int port, String path, int from, int to) {
var client = new HttpClient();
return client.get('localhost', port, path)
.then((request) {
_addRangeHeader(request, from, to);
return request.close();
})
.then((response) => response.fold([], (p, e) => p..addAll(e)))
.whenComplete(() => client.close());
}
Future<List> _getContentAndResponse(int port, String path, int from, int to) {
var client = new HttpClient();
return client.get('localhost', port, path)
.then((request) {
_addRangeHeader(request, from, to);
return request.close();
})
.then((response) => response.fold([], (p, e) => p..addAll(e))
.then((bytes) => [bytes, response]))
.whenComplete(() => client.close());
}
Uri _getUri(int port,
String path,
{bool secure: false,
bool rawPath: false}) {
if (rawPath) {
return new Uri(scheme: secure ? 'https' : 'http',
host: 'localhost',
port: port,
path: path);
} else {
return (secure ?
new Uri.https('localhost:$port', path) :
new Uri.http('localhost:$port', path));
}
}
void _addRangeHeader(request, int from, int to) {
var fromStr = from != null ? '$from' : '';
var toStr = to != null ? '$to' : '';
if (fromStr.isNotEmpty || toStr.isNotEmpty) {
request.headers.set(HttpHeaders.RANGE, 'bytes=$fromStr-$toStr');
}
}
const CERTIFICATE = "localhost_cert";
void setupSecure() {
String certificateDatabase = Platform.script.resolve('pkcert').toFilePath();
SecureSocket.initialize(database: certificateDatabase,
password: 'dartdart');
}