OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 import 'dart:async'; |
| 6 import 'dart:io'; |
| 7 import 'dart:convert'; |
| 8 |
| 9 import 'package:unittest/unittest.dart'; |
| 10 |
| 11 import 'package:appengine/api/remote_api.dart'; |
| 12 import 'package:appengine/api/errors.dart'; |
| 13 import 'package:appengine/src/protobuf_api/rpc/rpc_service.dart'; |
| 14 import 'package:appengine/src/appengine_context.dart'; |
| 15 import 'package:appengine/src/api_impl/remote_api_impl.dart'; |
| 16 import 'package:appengine/src/protobuf_api/internal/remote_api.pb.dart' as pb; |
| 17 |
| 18 import 'utils/error_matchers.dart'; |
| 19 |
| 20 class MockRPCService extends RPCService { |
| 21 final pb.Request _expectedPbRequest; |
| 22 final List<int> _responseBytes; |
| 23 final String _expectedTicket; |
| 24 |
| 25 MockRPCService( |
| 26 this._expectedPbRequest, this._responseBytes, this._expectedTicket); |
| 27 |
| 28 Future<List<int>> call(String apiPackage, |
| 29 String method, |
| 30 List<int> requestProtocolBuffer, |
| 31 {String ticket}) { |
| 32 expect(apiPackage, equals(_expectedPbRequest.serviceName)); |
| 33 expect(method, equals(_expectedPbRequest.method)); |
| 34 expect(requestProtocolBuffer, equals(_expectedPbRequest.request)); |
| 35 expect(ticket, equals(_expectedTicket)); |
| 36 return new Future.value(_responseBytes); |
| 37 } |
| 38 } |
| 39 |
| 40 class ErrorMockRPCService extends RPCService { |
| 41 static const RPC_ERROR_CODE = 42; |
| 42 static const RPC_ERROR_MESSAGE = "rpc error from mock"; |
| 43 |
| 44 final bool throwNetworkError; |
| 45 final bool throwProtocolError; |
| 46 final bool throwRpcError; |
| 47 |
| 48 ErrorMockRPCService({this.throwNetworkError: false, |
| 49 this.throwProtocolError: false, |
| 50 this.throwRpcError: false}); |
| 51 |
| 52 Future<List<int>> call(String apiPackage, |
| 53 String method, |
| 54 List<int> requestProtocolBuffer, |
| 55 {String ticket}) { |
| 56 return new Future.sync(() { |
| 57 if (throwNetworkError) { |
| 58 throw new NetworkError("network error from mock"); |
| 59 } else if (throwProtocolError) { |
| 60 throw new ProtocolError("protocol error from mock"); |
| 61 } else if (throwRpcError) { |
| 62 throw new RpcApplicationError(RPC_ERROR_CODE, RPC_ERROR_MESSAGE); |
| 63 } |
| 64 throw "Unknown error from mock"; |
| 65 }); |
| 66 } |
| 67 } |
| 68 |
| 69 Future<List<Future>> testRemoteApi(RemoteApi remoteApi, Function client) { |
| 70 return HttpServer.bind('127.0.0.1', 0).then((HttpServer server) { |
| 71 var serverFuture = server.first.then((HttpRequest request) { |
| 72 return remoteApi.handleRemoteApiRequest(request); |
| 73 }).whenComplete(() => server.close(force: true)); |
| 74 var clientFuture = client(server.address.address, server.port); |
| 75 return [serverFuture, clientFuture]; |
| 76 }); |
| 77 } |
| 78 |
| 79 void runTests() { |
| 80 var INVALID_PROTOBUF = [1, 2, 3, 4, 5]; |
| 81 var serverResponseBytes = [4, 5, 6]; |
| 82 |
| 83 pb.Request pbRequest = new pb.Request(); |
| 84 pbRequest.requestId = 'test-id'; |
| 85 pbRequest.serviceName = 'test-service'; |
| 86 pbRequest.method = 'test-method'; |
| 87 pbRequest.request = [1, 2, 3]; |
| 88 |
| 89 runClient(String address, int port, |
| 90 List<int> requestData, Function validate, |
| 91 {String path: '/foobar', method: 'POST'}) { |
| 92 var client = new HttpClient(); |
| 93 return client.open(method, address, port, path).then((request) { |
| 94 request.add(requestData); |
| 95 return request.close().then((HttpClientResponse response) { |
| 96 return response |
| 97 .fold([], (buffer, data) => buffer..addAll(data)) |
| 98 .then(validate); |
| 99 }); |
| 100 }).whenComplete(client.close); |
| 101 } |
| 102 |
| 103 runClientAndCheckRtokResponse(String address, int port) { |
| 104 var rtok = 'RR'; |
| 105 validate(List<int> bytes) { |
| 106 var json = JSON.decode(UTF8.decode(bytes)); |
| 107 expect(json, isMap); |
| 108 expect(json['app_id'], equals('dev~application')); |
| 109 expect(json['rtok'], equals(rtok)); |
| 110 } |
| 111 |
| 112 return runClient( |
| 113 address, port, [], validate, path: '/foobar?rtok=$rtok', method: 'GET'); |
| 114 } |
| 115 |
| 116 runClientAndCheckApiCallResponse(String address, int port) { |
| 117 validate(List<int> bytes) { |
| 118 pb.Response response = new pb.Response.fromBuffer(bytes); |
| 119 expect(response.response, equals(serverResponseBytes)); |
| 120 } |
| 121 return runClient(address, port, pbRequest.writeToBuffer(), validate); |
| 122 } |
| 123 |
| 124 runClientWithInvalidMethod(String address, int port) { |
| 125 return runClient( |
| 126 address, port, [], (_) {}, path: '/foobar?rtok=foo', method: 'HEAD'); |
| 127 } |
| 128 |
| 129 runClientWithInvalidProtobuf(String address, int port) { |
| 130 return runClient(address, port, INVALID_PROTOBUF, (_) {}, |
| 131 path: '/foobar?rtok=foo'); |
| 132 } |
| 133 |
| 134 runClientAndCheckRpcError(String address, int port) { |
| 135 validate(List<int> bytes) { |
| 136 pb.Response pbResponse = new pb.Response.fromBuffer(bytes); |
| 137 expect(pbResponse.applicationError.code, |
| 138 equals(ErrorMockRPCService.RPC_ERROR_CODE)); |
| 139 expect(pbResponse.applicationError.detail, |
| 140 equals(ErrorMockRPCService.RPC_ERROR_MESSAGE)); |
| 141 } |
| 142 |
| 143 return runClient(address, port, pbRequest.writeToBuffer(), validate); |
| 144 } |
| 145 |
| 146 runClientWithoutValidation(String address, int port) { |
| 147 return runClient(address, port, pbRequest.writeToBuffer(), (){}); |
| 148 } |
| 149 |
| 150 group('remote_api', () { |
| 151 var invalidTicket = 'invalid-ticket'; |
| 152 var context = new AppengineContext( |
| 153 'dev', 'application', 'version', null, null, null); |
| 154 |
| 155 test('get_rtok', () { |
| 156 var remoteApi = new RemoteApiImpl(null, context, invalidTicket); |
| 157 |
| 158 return testRemoteApi(remoteApi, runClientAndCheckRtokResponse) |
| 159 .then((futures) => Future.wait(futures)); |
| 160 }); |
| 161 |
| 162 test('make_request', () { |
| 163 var rpcMock = |
| 164 new MockRPCService(pbRequest, serverResponseBytes, invalidTicket); |
| 165 var remoteApi = new RemoteApiImpl(rpcMock, context, invalidTicket); |
| 166 |
| 167 return testRemoteApi(remoteApi, runClientAndCheckApiCallResponse) |
| 168 .then((futures) => Future.wait(futures)); |
| 169 }); |
| 170 |
| 171 test('invalid_method', () { |
| 172 var remoteApi = new RemoteApiImpl(null, context, invalidTicket); |
| 173 |
| 174 return testRemoteApi(remoteApi, runClientWithInvalidMethod) |
| 175 .then((futures) { |
| 176 expect(futures[0], throwsA(isAppEngineApplicationError)); |
| 177 return futures[1].catchError((_) {}); |
| 178 }); |
| 179 }); |
| 180 |
| 181 test('invalid_protobuf_request', () { |
| 182 var remoteApi = new RemoteApiImpl(null, context, invalidTicket); |
| 183 |
| 184 return testRemoteApi(remoteApi, runClientWithInvalidProtobuf) |
| 185 .then((futures) { |
| 186 expect(futures[0], throws); |
| 187 return futures[1].catchError((_) {}); |
| 188 }); |
| 189 }); |
| 190 |
| 191 test('rpc_error', () { |
| 192 var rpcMock = new ErrorMockRPCService(throwRpcError: true); |
| 193 var remoteApi = new RemoteApiImpl(rpcMock, context, invalidTicket); |
| 194 |
| 195 return testRemoteApi(remoteApi, runClientAndCheckRpcError) |
| 196 .then((futures) => Future.wait(futures)); |
| 197 }); |
| 198 |
| 199 test('network_error', () { |
| 200 var rpcMock = new ErrorMockRPCService(throwNetworkError: true); |
| 201 var remoteApi = new RemoteApiImpl(rpcMock, context, invalidTicket); |
| 202 |
| 203 return testRemoteApi(remoteApi, runClientWithoutValidation) |
| 204 .then((futures) { |
| 205 expect(futures[0], throwsA(isNetworkError)); |
| 206 return futures[1].catchError((e) {}); |
| 207 }); |
| 208 }); |
| 209 |
| 210 test('protocol_error', () { |
| 211 var rpcMock = new ErrorMockRPCService(throwProtocolError: true); |
| 212 var remoteApi = new RemoteApiImpl(rpcMock, context, invalidTicket); |
| 213 |
| 214 return testRemoteApi(remoteApi, runClientWithoutValidation) |
| 215 .then((futures) { |
| 216 expect(futures[0], throwsA(isProtocolError)); |
| 217 return futures[1].catchError((e) {}); |
| 218 }); |
| 219 }); |
| 220 |
| 221 test('unknown_error', () { |
| 222 var rpcMock = new ErrorMockRPCService(); |
| 223 var remoteApi = new RemoteApiImpl(rpcMock, context, invalidTicket); |
| 224 |
| 225 return testRemoteApi(remoteApi, runClientWithoutValidation) |
| 226 .then((futures) { |
| 227 expect(futures[0], throws); |
| 228 return futures[1].catchError((e) {}); |
| 229 }); |
| 230 }); |
| 231 }); |
| 232 } |
| 233 |
| 234 main() { |
| 235 runTests(); |
| 236 } |
OLD | NEW |