mirror of https://github.com/grpc/grpc-dart.git
281 lines
8.8 KiB
Dart
281 lines
8.8 KiB
Dart
// Copyright (c) 2017, the gRPC project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
import 'dart:async';
|
|
|
|
import 'package:grpc/grpc.dart';
|
|
import 'package:http2/transport.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
import 'src/server_utils.dart';
|
|
|
|
void main() {
|
|
const dummyValue = 17;
|
|
|
|
ServerHarness harness;
|
|
|
|
setUp(() {
|
|
harness = new ServerHarness()..setUp();
|
|
});
|
|
|
|
tearDown(() {
|
|
harness.tearDown();
|
|
});
|
|
|
|
test('Unary calls work on the server', () async {
|
|
const expectedRequest = 5;
|
|
const expectedResponse = 7;
|
|
Future<int> methodHandler(ServiceCall call, Future<int> request) async {
|
|
expect(await request, expectedRequest);
|
|
return expectedResponse;
|
|
}
|
|
|
|
harness
|
|
..service.unaryHandler = methodHandler
|
|
..runTest('/Test/Unary', [expectedRequest], [expectedResponse]);
|
|
await harness.fromServer.done;
|
|
});
|
|
|
|
test('Client-streaming calls work on the server', () async {
|
|
const expectedRequests = const [5, 3, 17];
|
|
const expectedResponse = 12;
|
|
Future<int> methodHandler(ServiceCall call, Stream<int> request) async {
|
|
expect(await request.toList(), expectedRequests);
|
|
return expectedResponse;
|
|
}
|
|
|
|
harness
|
|
..service.clientStreamingHandler = methodHandler
|
|
..runTest('/Test/ClientStreaming', expectedRequests, [expectedResponse]);
|
|
await harness.fromServer.done;
|
|
});
|
|
|
|
test('Server-streaming calls work on the server', () async {
|
|
const expectedRequest = 5;
|
|
const expectedResponses = const [7, 9, 1];
|
|
|
|
Stream<int> methodHandler(ServiceCall call, Future<int> request) async* {
|
|
expect(await request, expectedRequest);
|
|
for (final value in expectedResponses) {
|
|
yield value;
|
|
}
|
|
}
|
|
|
|
harness
|
|
..service.serverStreamingHandler = methodHandler
|
|
..runTest('/Test/ServerStreaming', [expectedRequest], expectedResponses);
|
|
await harness.fromServer.done;
|
|
});
|
|
|
|
test('Bidirectional calls work on the server', () async {
|
|
const expectedRequests = const [3, 1, 7];
|
|
final expectedResponses = expectedRequests.map((v) => v + 5).toList();
|
|
|
|
Stream<int> methodHandler(ServiceCall call, Stream<int> request) async* {
|
|
yield* request.map((value) => value + 5);
|
|
}
|
|
|
|
harness
|
|
..service.bidirectionalHandler = methodHandler
|
|
..runTest('/Test/Bidirectional', expectedRequests, expectedResponses);
|
|
await harness.fromServer.done;
|
|
});
|
|
|
|
test('Server returns error on missing call header', () async {
|
|
harness
|
|
..expectErrorResponse(StatusCode.unimplemented, 'Expected header frame')
|
|
..sendData(dummyValue);
|
|
await harness.fromServer.done;
|
|
});
|
|
|
|
test('Server returns error on invalid path', () async {
|
|
harness
|
|
..expectErrorResponse(StatusCode.unimplemented, 'Invalid path')
|
|
..sendRequestHeader('InvalidPath');
|
|
await harness.fromServer.done;
|
|
});
|
|
|
|
test('Server returns error on unimplemented path', () async {
|
|
harness
|
|
..expectErrorResponse(
|
|
StatusCode.unimplemented, 'Path /Test/NotFound not found')
|
|
..sendRequestHeader('/Test/NotFound');
|
|
await harness.fromServer.done;
|
|
});
|
|
|
|
/// Returns a service method handler that verifies that awaiting the request
|
|
/// throws a specific error.
|
|
Future<int> Function(ServiceCall call, Future<int> request) expectError(
|
|
expectedError) {
|
|
return expectAsync2((ServiceCall call, Future<int> request) async {
|
|
try {
|
|
final result = await request;
|
|
registerException('Did not throw');
|
|
return result;
|
|
} catch (caughtError) {
|
|
try {
|
|
expect(caughtError, expectedError);
|
|
} catch (failure, stack) {
|
|
registerException(failure, stack);
|
|
}
|
|
rethrow;
|
|
}
|
|
}, count: 1);
|
|
}
|
|
|
|
/// Returns a service method handler that verifies that awaiting the request
|
|
/// stream throws a specific error.
|
|
Stream<int> Function(ServiceCall call, Stream<int> request)
|
|
expectErrorStreaming(expectedError) {
|
|
return (ServiceCall call, Stream<int> request) async* {
|
|
try {
|
|
await for (var entry in request) {
|
|
yield entry;
|
|
}
|
|
registerException('Did not throw');
|
|
} catch (caughtError) {
|
|
try {
|
|
expect(caughtError, expectedError);
|
|
} catch (failure, stack) {
|
|
registerException(failure, stack);
|
|
}
|
|
rethrow;
|
|
}
|
|
};
|
|
}
|
|
|
|
test('Server returns error on missing request for unary call', () async {
|
|
harness
|
|
..service.unaryHandler =
|
|
expectError(new GrpcError.unimplemented('No request received'))
|
|
..expectErrorResponse(StatusCode.unimplemented, 'No request received')
|
|
..sendRequestHeader('/Test/Unary')
|
|
..toServer.close();
|
|
await harness.fromServer.done;
|
|
});
|
|
|
|
test('Server returns error if multiple headers are received for unary call',
|
|
() async {
|
|
harness
|
|
..service.unaryHandler =
|
|
expectError(new GrpcError.unimplemented('Expected request'))
|
|
..expectErrorResponse(StatusCode.unimplemented, 'Expected request')
|
|
..sendRequestHeader('/Test/Unary')
|
|
..toServer.add(new HeadersStreamMessage([]))
|
|
..toServer.close();
|
|
await harness.fromServer.done;
|
|
});
|
|
|
|
test('Server returns error on too many requests for unary call', () async {
|
|
harness
|
|
..service.unaryHandler =
|
|
expectError(new GrpcError.unimplemented('Too many requests'))
|
|
..expectErrorResponse(StatusCode.unimplemented, 'Too many requests')
|
|
..sendRequestHeader('/Test/Unary')
|
|
..sendData(dummyValue)
|
|
..sendData(dummyValue)
|
|
..toServer.close();
|
|
await harness.fromServer.done;
|
|
});
|
|
|
|
test('Server returns request deserialization errors', () async {
|
|
harness
|
|
..service.bidirectionalHandler = expectErrorStreaming(
|
|
new GrpcError.internal('Error deserializing request: Failed'))
|
|
..expectErrorResponse(
|
|
StatusCode.internal, 'Error deserializing request: Failed')
|
|
..sendRequestHeader('/Test/RequestError')
|
|
..sendData(dummyValue)
|
|
..toServer.close();
|
|
await harness.fromServer.done;
|
|
});
|
|
|
|
test('Server returns response serialization errors', () async {
|
|
harness
|
|
..service.bidirectionalHandler = expectErrorStreaming(
|
|
new GrpcError.internal('Error sending response: Failed'))
|
|
..expectErrorResponse(
|
|
StatusCode.internal, 'Error sending response: Failed')
|
|
..sendRequestHeader('/Test/ResponseError')
|
|
..sendData(dummyValue)
|
|
..sendData(dummyValue)
|
|
..toServer.close();
|
|
await harness.fromServer.done;
|
|
});
|
|
|
|
test('Header can only be sent once', () async {
|
|
Future<int> methodHandler(ServiceCall call, Future<int> request) async {
|
|
call.sendHeaders();
|
|
call.sendHeaders();
|
|
return await request;
|
|
}
|
|
|
|
harness
|
|
..service.unaryHandler = methodHandler
|
|
..expectTrailingErrorResponse(StatusCode.internal, 'Headers already sent')
|
|
..sendRequestHeader('/Test/Unary');
|
|
await harness.fromServer.done;
|
|
});
|
|
|
|
test('Server receives cancel', () async {
|
|
final success = new Completer<bool>();
|
|
|
|
Future<int> methodHandler(ServiceCall call, Future<int> request) async {
|
|
try {
|
|
final result = await request;
|
|
registerException('Did not throw');
|
|
return result;
|
|
} catch (caughtError) {
|
|
try {
|
|
expect(caughtError, new GrpcError.cancelled('Cancelled'));
|
|
expect(call.isCanceled, isTrue);
|
|
success.complete(true);
|
|
} catch (failure, stack) {
|
|
registerException(failure, stack);
|
|
}
|
|
} finally {
|
|
if (!success.isCompleted) {
|
|
success.complete(false);
|
|
}
|
|
}
|
|
return dummyValue;
|
|
}
|
|
|
|
harness
|
|
..service.unaryHandler = methodHandler
|
|
..fromServer.stream.listen(expectAsync1((_) {}, count: 0),
|
|
onError: expectAsync1((error) {
|
|
expect(error, 'TERMINATED');
|
|
}, count: 1),
|
|
onDone: expectAsync0(() {}, count: 1))
|
|
..sendRequestHeader('/Test/Unary')
|
|
..toServer.addError('CANCEL');
|
|
|
|
expect(await success.future, isTrue);
|
|
await harness.toServer.close();
|
|
await harness.fromServer.done;
|
|
});
|
|
|
|
test(
|
|
'Server returns error if request stream is closed before sending anything',
|
|
() async {
|
|
harness
|
|
..expectErrorResponse(
|
|
StatusCode.unavailable, 'Request stream closed unexpectedly')
|
|
..toServer.close();
|
|
await harness.fromServer.done;
|
|
});
|
|
}
|