2017-06-30 13:49:45 +00:00
|
|
|
import 'dart:async';
|
2018-08-20 20:43:38 +00:00
|
|
|
import 'dart:convert';
|
2017-06-30 13:49:45 +00:00
|
|
|
import 'dart:io';
|
2018-08-20 20:43:38 +00:00
|
|
|
|
2021-05-14 10:34:09 +00:00
|
|
|
import 'package:angel3_container/mirrors.dart';
|
|
|
|
import 'package:angel3_framework/angel3_framework.dart';
|
|
|
|
import 'package:angel3_framework/http.dart';
|
|
|
|
import 'package:angel3_mock_request/angel3_mock_request.dart';
|
2020-02-05 23:02:46 +00:00
|
|
|
|
2017-06-30 13:49:45 +00:00
|
|
|
import 'package:test/test.dart';
|
|
|
|
|
|
|
|
final Uri $foo = Uri.parse('http://localhost:3000/foo');
|
|
|
|
|
|
|
|
/// Additional tests to improve coverage of server.dart
|
2021-05-14 10:34:09 +00:00
|
|
|
void main() {
|
2017-06-30 13:49:45 +00:00
|
|
|
group('scoping', () {
|
2019-05-02 22:48:31 +00:00
|
|
|
var parent = Angel(reflector: MirrorsReflector())..configuration['two'] = 2;
|
|
|
|
var child = Angel(reflector: MirrorsReflector());
|
2018-08-21 01:05:05 +00:00
|
|
|
parent.mount('/child', child);
|
2017-06-30 13:49:45 +00:00
|
|
|
|
|
|
|
test('sets children', () {
|
|
|
|
expect(parent.children, contains(child));
|
|
|
|
});
|
|
|
|
|
|
|
|
test('sets parent', () {
|
|
|
|
expect(child.parent, parent);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('properties can climb up hierarchy', () {
|
|
|
|
expect(child.findProperty('two'), 2);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
test('custom server generator', () {
|
2019-05-02 22:48:31 +00:00
|
|
|
var app = Angel(reflector: MirrorsReflector());
|
|
|
|
var http = AngelHttp.custom(app, HttpServer.bind);
|
2018-02-07 04:34:08 +00:00
|
|
|
expect(http.serverGenerator, HttpServer.bind);
|
2017-06-30 13:49:45 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
test('default error handler', () async {
|
2019-05-02 22:48:31 +00:00
|
|
|
var app = Angel(reflector: MirrorsReflector());
|
|
|
|
var http = AngelHttp(app);
|
|
|
|
var rq = MockHttpRequest('GET', $foo);
|
2021-06-26 13:13:43 +00:00
|
|
|
await (rq.close());
|
2017-06-30 13:49:45 +00:00
|
|
|
var rs = rq.response;
|
2018-11-11 01:07:09 +00:00
|
|
|
var req = await http.createRequestContext(rq, rs);
|
|
|
|
var res = await http.createResponseContext(rq, rs);
|
2022-02-13 16:48:37 +00:00
|
|
|
var e = AngelHttpException(
|
2017-06-30 13:49:45 +00:00
|
|
|
statusCode: 321, message: 'Hello', errors: ['foo', 'bar']);
|
|
|
|
await app.errorHandler(e, req, res);
|
2018-11-11 01:07:09 +00:00
|
|
|
await http.sendResponse(rq, rs, req, res);
|
2018-02-07 04:34:08 +00:00
|
|
|
expect(
|
2021-03-20 08:11:18 +00:00
|
|
|
ContentType.parse(rs.headers.value('content-type')!).mimeType,
|
2018-06-23 03:29:38 +00:00
|
|
|
'text/html',
|
2018-02-07 04:34:08 +00:00
|
|
|
);
|
2017-06-30 13:49:45 +00:00
|
|
|
expect(rs.statusCode, e.statusCode);
|
2018-06-08 07:06:26 +00:00
|
|
|
var body = await rs.transform(utf8.decoder).join();
|
2017-06-30 13:49:45 +00:00
|
|
|
expect(body, contains('<title>${e.message}</title>'));
|
|
|
|
expect(body, contains('<li>foo</li>'));
|
|
|
|
expect(body, contains('<li>bar</li>'));
|
|
|
|
});
|
|
|
|
|
|
|
|
test('plug-ins run on startup', () async {
|
2019-05-02 22:48:31 +00:00
|
|
|
var app = Angel(reflector: MirrorsReflector());
|
2018-06-08 07:06:26 +00:00
|
|
|
app.startupHooks.add((app) => app.configuration['two'] = 2);
|
2018-02-07 05:36:24 +00:00
|
|
|
|
2019-05-02 22:48:31 +00:00
|
|
|
var http = AngelHttp(app);
|
2018-02-07 05:36:24 +00:00
|
|
|
await http.startServer();
|
2017-09-24 19:43:14 +00:00
|
|
|
expect(app.configuration['two'], 2);
|
2017-06-30 13:49:45 +00:00
|
|
|
await app.close();
|
2018-02-07 05:36:24 +00:00
|
|
|
await http.close();
|
2017-06-30 13:49:45 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
test('warning when adding routes to flattened router', () {
|
2019-05-02 22:48:31 +00:00
|
|
|
var app = Angel(reflector: MirrorsReflector())
|
2018-08-20 20:43:38 +00:00
|
|
|
..optimizeForProduction(force: true);
|
2017-06-30 13:49:45 +00:00
|
|
|
app.dumpTree();
|
2018-08-20 20:43:38 +00:00
|
|
|
app.get('/', (req, res) => 2);
|
2019-05-02 22:48:31 +00:00
|
|
|
app.mount('/foo', Router()..get('/', (req, res) => 3));
|
2017-06-30 13:49:45 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
test('services close on close call', () async {
|
2019-05-02 22:48:31 +00:00
|
|
|
var app = Angel(reflector: MirrorsReflector());
|
|
|
|
var svc = CustomCloseService();
|
2017-06-30 13:49:45 +00:00
|
|
|
expect(svc.value, 2);
|
|
|
|
app.use('/', svc);
|
|
|
|
await app.close();
|
|
|
|
expect(svc.value, 3);
|
|
|
|
});
|
|
|
|
|
2017-09-22 04:48:22 +00:00
|
|
|
test('global injection added to injection map', () async {
|
2019-05-02 22:48:31 +00:00
|
|
|
var app = Angel(reflector: MirrorsReflector())..configuration['a'] = 'b';
|
|
|
|
var http = AngelHttp(app);
|
2018-08-20 20:43:38 +00:00
|
|
|
app.get('/', ioc((String a) => a));
|
2019-05-02 22:48:31 +00:00
|
|
|
var rq = MockHttpRequest('GET', Uri.parse('/'));
|
2021-06-26 13:13:43 +00:00
|
|
|
await (rq.close());
|
2018-02-07 04:34:08 +00:00
|
|
|
await http.handleRequest(rq);
|
2018-06-08 07:06:26 +00:00
|
|
|
var body = await rq.response.transform(utf8.decoder).join();
|
|
|
|
expect(body, json.encode('b'));
|
2017-06-30 13:49:45 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
test('global injected serializer', () async {
|
2019-05-02 22:48:31 +00:00
|
|
|
var app = Angel(reflector: MirrorsReflector())..serializer = (_) => 'x';
|
|
|
|
var http = AngelHttp(app);
|
2017-06-30 13:49:45 +00:00
|
|
|
app.get($foo.path, (req, ResponseContext res) => res.serialize(null));
|
2019-05-02 22:48:31 +00:00
|
|
|
var rq = MockHttpRequest('GET', $foo);
|
2021-06-26 13:13:43 +00:00
|
|
|
await (rq.close());
|
2018-02-07 04:34:08 +00:00
|
|
|
await http.handleRequest(rq);
|
2018-06-08 07:06:26 +00:00
|
|
|
var body = await rq.response.transform(utf8.decoder).join();
|
2017-06-30 13:49:45 +00:00
|
|
|
expect(body, 'x');
|
|
|
|
});
|
|
|
|
|
|
|
|
group('handler results', () {
|
2019-05-02 22:48:31 +00:00
|
|
|
var app = Angel(reflector: MirrorsReflector());
|
|
|
|
var http = AngelHttp(app);
|
2017-06-30 21:23:31 +00:00
|
|
|
app.responseFinalizers
|
2019-05-02 22:48:31 +00:00
|
|
|
.add((req, res) => throw AngelHttpException.forbidden());
|
2021-03-20 08:11:18 +00:00
|
|
|
late RequestContext req;
|
|
|
|
late ResponseContext res;
|
2017-06-30 13:49:45 +00:00
|
|
|
|
|
|
|
setUp(() async {
|
2019-05-02 22:48:31 +00:00
|
|
|
var rq = MockHttpRequest('GET', $foo);
|
2021-06-26 13:13:43 +00:00
|
|
|
await (rq.close());
|
2018-11-11 01:07:09 +00:00
|
|
|
req = await http.createRequestContext(rq, rq.response);
|
|
|
|
res = await http.createResponseContext(rq, rq.response);
|
2017-06-30 13:49:45 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
group('getHandlerResult', () {
|
|
|
|
test('return request handler', () async {
|
2022-08-17 03:05:48 +00:00
|
|
|
handler(req, res) => (req, res) async {
|
2017-06-30 13:49:45 +00:00
|
|
|
return 2;
|
|
|
|
};
|
|
|
|
var r = await app.getHandlerResult(handler, req, res);
|
|
|
|
expect(r, 2);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('return future', () async {
|
2019-05-02 22:48:31 +00:00
|
|
|
var handler = Future.value(2);
|
2017-06-30 13:49:45 +00:00
|
|
|
expect(await app.getHandlerResult(handler, req, res), 2);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
group('executeHandler', () {
|
|
|
|
test('return Stream', () async {
|
2022-08-17 03:05:48 +00:00
|
|
|
handler(req, res) => Stream.fromIterable([2, 3]);
|
2017-06-30 13:49:45 +00:00
|
|
|
expect(await app.executeHandler(handler, req, res), isFalse);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('end response', () async {
|
2022-08-17 03:05:48 +00:00
|
|
|
handler(req, ResponseContext res) => res.close();
|
2017-06-30 13:49:45 +00:00
|
|
|
expect(await app.executeHandler(handler, req, res), isFalse);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
group('handleAngelHttpException', () {
|
2021-03-20 08:11:18 +00:00
|
|
|
late Angel app;
|
|
|
|
late AngelHttp http;
|
2017-06-30 13:49:45 +00:00
|
|
|
|
|
|
|
setUp(() async {
|
2019-05-02 22:48:31 +00:00
|
|
|
app = Angel(reflector: MirrorsReflector());
|
|
|
|
app.get('/wtf', (req, res) => throw AngelHttpException.forbidden());
|
|
|
|
app.get('/wtf2', (req, res) => throw AngelHttpException.forbidden());
|
|
|
|
http = AngelHttp(app);
|
2018-06-08 07:06:26 +00:00
|
|
|
await http.startServer('127.0.0.1', 0);
|
2017-09-22 14:03:23 +00:00
|
|
|
|
|
|
|
var oldHandler = app.errorHandler;
|
|
|
|
app.errorHandler = (e, req, res) {
|
|
|
|
print('FATAL: ${e.error ?? e}');
|
|
|
|
print(e.stackTrace);
|
|
|
|
return oldHandler(e, req, res);
|
|
|
|
};
|
2017-06-30 13:49:45 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
tearDown(() => app.close());
|
|
|
|
|
|
|
|
test('can send json', () async {
|
2019-05-02 22:48:31 +00:00
|
|
|
var rq = MockHttpRequest('GET', Uri(path: 'wtf'))
|
2018-06-23 03:29:38 +00:00
|
|
|
..headers.set('accept', 'application/json');
|
2021-06-26 16:18:46 +00:00
|
|
|
await rq.close();
|
2021-06-26 15:15:48 +00:00
|
|
|
http.handleRequest(rq);
|
2018-05-16 03:14:29 +00:00
|
|
|
await rq.response.toList();
|
2018-06-23 03:29:38 +00:00
|
|
|
expect(rq.response.statusCode, 403);
|
2021-03-20 08:11:18 +00:00
|
|
|
expect(rq.response.headers.contentType!.mimeType, 'application/json');
|
2017-06-30 13:49:45 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
test('can throw in finalizer', () async {
|
2019-05-02 22:48:31 +00:00
|
|
|
var rq = MockHttpRequest('GET', Uri(path: 'wtf'))
|
2018-06-23 03:29:38 +00:00
|
|
|
..headers.set('accept', 'application/json');
|
2021-06-26 16:18:46 +00:00
|
|
|
await rq.close();
|
2021-06-26 15:15:48 +00:00
|
|
|
http.handleRequest(rq);
|
2018-05-16 03:14:29 +00:00
|
|
|
await rq.response.toList();
|
2018-06-23 03:29:38 +00:00
|
|
|
expect(rq.response.statusCode, 403);
|
2021-03-20 08:11:18 +00:00
|
|
|
expect(rq.response.headers.contentType!.mimeType, 'application/json');
|
2017-06-30 13:49:45 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
test('can send html', () async {
|
2019-05-02 22:48:31 +00:00
|
|
|
var rq = MockHttpRequest('GET', Uri(path: 'wtf2'));
|
2021-06-26 15:15:48 +00:00
|
|
|
//rq.headers.set('accept', 'text/html');
|
2021-06-26 16:18:46 +00:00
|
|
|
await rq.close();
|
2021-06-26 15:15:48 +00:00
|
|
|
http.handleRequest(rq);
|
2018-05-16 03:14:29 +00:00
|
|
|
await rq.response.toList();
|
2018-06-23 03:29:38 +00:00
|
|
|
expect(rq.response.statusCode, 403);
|
2018-06-23 03:59:41 +00:00
|
|
|
expect(rq.response.headers.contentType?.mimeType, 'text/html');
|
2017-06-30 13:49:45 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
class CustomCloseService extends Service {
|
|
|
|
int value = 2;
|
|
|
|
|
|
|
|
@override
|
2018-06-08 07:06:26 +00:00
|
|
|
void close() {
|
2017-06-30 13:49:45 +00:00
|
|
|
value = 3;
|
2018-06-08 07:06:26 +00:00
|
|
|
super.close();
|
2017-06-30 13:49:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Expose('/foo')
|
|
|
|
class FooController extends Controller {
|
|
|
|
@Expose('/bar')
|
2021-09-12 14:12:18 +00:00
|
|
|
Future<String> bar() async => 'baz';
|
2017-06-30 13:49:45 +00:00
|
|
|
}
|