OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library curl_client_test; | 5 library curl_client_test; |
6 | 6 |
7 import 'dart:io'; | 7 import 'dart:io'; |
8 import 'dart:isolate'; | 8 import 'dart:isolate'; |
| 9 import 'dart:json'; |
9 import 'dart:uri'; | 10 import 'dart:uri'; |
10 | 11 |
11 import '../../../pkg/unittest/lib/unittest.dart'; | 12 import '../../../pkg/unittest/lib/unittest.dart'; |
12 import '../../../pkg/http/lib/http.dart' as http; | 13 import '../../../pkg/http/lib/http.dart' as http; |
13 import '../../../pkg/http/test/utils.dart'; | |
14 import '../../pub/curl_client.dart'; | 14 import '../../pub/curl_client.dart'; |
15 import '../../pub/io.dart'; | 15 import '../../pub/io.dart'; |
16 | 16 |
| 17 // TODO(rnystrom): All of the code from here to the "---..." line was copied |
| 18 // from pkg/http/test/utils.dart and pkg/http/lib/src/utils.dart. It's copied |
| 19 // here because http/test/utils.dart is now using "package:" imports and this |
| 20 // is not. You cannot mix those because you end up with duplicate copies of the |
| 21 // same library in memory. Since curl_client is going away soon anyway, I'm |
| 22 // just copying the code here. Delete all of this when curl client is removed. |
| 23 |
| 24 /// Returns the [Encoding] that corresponds to [charset]. Throws a |
| 25 /// [FormatException] if no [Encoding] was found that corresponds to [charset]. |
| 26 /// [charset] may not be null. |
| 27 Encoding requiredEncodingForCharset(String charset) { |
| 28 var encoding = _encodingForCharset(charset); |
| 29 if (encoding != null) return encoding; |
| 30 throw new FormatException('Unsupported encoding "$charset".'); |
| 31 } |
| 32 |
| 33 /// Returns the [Encoding] that corresponds to [charset]. Returns null if no |
| 34 /// [Encoding] was found that corresponds to [charset]. [charset] may not be |
| 35 /// null. |
| 36 Encoding _encodingForCharset(String charset) { |
| 37 charset = charset.toLowerCase(); |
| 38 if (charset == 'ascii' || charset == 'us-ascii') return Encoding.ASCII; |
| 39 if (charset == 'utf-8') return Encoding.UTF_8; |
| 40 if (charset == 'iso-8859-1') return Encoding.ISO_8859_1; |
| 41 return null; |
| 42 } |
| 43 |
| 44 /// Converts [bytes] into a [String] according to [encoding]. |
| 45 String decodeString(List<int> bytes, Encoding encoding) { |
| 46 // TODO(nweiz): implement this once issue 6284 is fixed. |
| 47 return new String.fromCharCodes(bytes); |
| 48 } |
| 49 |
| 50 /// The current server instance. |
| 51 HttpServer _server; |
| 52 |
| 53 /// The URL for the current server instance. |
| 54 Uri get serverUrl => new Uri.fromString('http://localhost:${_server.port}'); |
| 55 |
| 56 /// A dummy URL for constructing requests that won't be sent. |
| 57 Uri get dummyUrl => new Uri.fromString('http://dartlang.org/'); |
| 58 |
| 59 /// Starts a new HTTP server. |
| 60 void startServer() { |
| 61 _server = new HttpServer(); |
| 62 |
| 63 _server.addRequestHandler((request) => request.path == '/error', |
| 64 (request, response) { |
| 65 response.statusCode = 400; |
| 66 response.contentLength = 0; |
| 67 response.outputStream.close(); |
| 68 }); |
| 69 |
| 70 _server.addRequestHandler((request) => request.path == '/loop', |
| 71 (request, response) { |
| 72 var n = int.parse(new Uri.fromString(request.uri).query); |
| 73 response.statusCode = 302; |
| 74 response.headers.set('location', |
| 75 serverUrl.resolve('/loop?${n + 1}').toString()); |
| 76 response.contentLength = 0; |
| 77 response.outputStream.close(); |
| 78 }); |
| 79 |
| 80 _server.addRequestHandler((request) => request.path == '/redirect', |
| 81 (request, response) { |
| 82 response.statusCode = 302; |
| 83 response.headers.set('location', serverUrl.resolve('/').toString()); |
| 84 response.contentLength = 0; |
| 85 response.outputStream.close(); |
| 86 }); |
| 87 |
| 88 _server.defaultRequestHandler = (request, response) { |
| 89 consumeInputStream(request.inputStream).then((requestBodyBytes) { |
| 90 response.statusCode = 200; |
| 91 response.headers.contentType = new ContentType("application", "json"); |
| 92 |
| 93 var requestBody; |
| 94 if (requestBodyBytes.isEmpty) { |
| 95 requestBody = null; |
| 96 } else if (request.headers.contentType.charset != null) { |
| 97 var encoding = requiredEncodingForCharset( |
| 98 request.headers.contentType.charset); |
| 99 requestBody = decodeString(requestBodyBytes, encoding); |
| 100 } else { |
| 101 requestBody = requestBodyBytes; |
| 102 } |
| 103 |
| 104 var content = { |
| 105 'method': request.method, |
| 106 'path': request.path, |
| 107 'headers': <String>{} |
| 108 }; |
| 109 if (requestBody != null) content['body'] = requestBody; |
| 110 request.headers.forEach((name, values) { |
| 111 // These headers are automatically generated by dart:io, so we don't |
| 112 // want to test them here. |
| 113 if (name == 'cookie' || name == 'host') return; |
| 114 |
| 115 content['headers'][name] = values; |
| 116 }); |
| 117 |
| 118 var outputEncoding; |
| 119 var encodingName = request.queryParameters['response-encoding']; |
| 120 if (encodingName != null) { |
| 121 outputEncoding = requiredEncodingForCharset(encodingName); |
| 122 } else { |
| 123 outputEncoding = Encoding.ASCII; |
| 124 } |
| 125 |
| 126 var body = JSON.stringify(content); |
| 127 response.contentLength = body.length; |
| 128 response.outputStream.writeString(body, outputEncoding); |
| 129 response.outputStream.close(); |
| 130 }); |
| 131 }; |
| 132 |
| 133 _server.listen("127.0.0.1", 0); |
| 134 } |
| 135 |
| 136 /// Stops the current HTTP server. |
| 137 void stopServer() { |
| 138 _server.close(); |
| 139 _server = null; |
| 140 } |
| 141 |
| 142 /// A matcher that matches JSON that parses to a value that matches the inner |
| 143 /// matcher. |
| 144 Matcher parse(matcher) => new _Parse(matcher); |
| 145 |
| 146 class _Parse extends BaseMatcher { |
| 147 final Matcher _matcher; |
| 148 |
| 149 _Parse(this._matcher); |
| 150 |
| 151 bool matches(item, MatchState matchState) { |
| 152 if (item is! String) return false; |
| 153 |
| 154 var parsed; |
| 155 try { |
| 156 parsed = JSON.parse(item); |
| 157 } catch (e) { |
| 158 return false; |
| 159 } |
| 160 |
| 161 return _matcher.matches(parsed, matchState); |
| 162 } |
| 163 |
| 164 Description describe(Description description) { |
| 165 return description.add('parses to a value that ') |
| 166 .addDescriptionOf(_matcher); |
| 167 } |
| 168 } |
| 169 |
| 170 // TODO(nweiz): remove this once it's built in to unittest |
| 171 /// A matcher for StateErrors. |
| 172 const isStateError = const _StateError(); |
| 173 |
| 174 /// A matcher for functions that throw StateError. |
| 175 const Matcher throwsStateError = |
| 176 const Throws(isStateError); |
| 177 |
| 178 class _StateError extends TypeMatcher { |
| 179 const _StateError() : super("StateError"); |
| 180 bool matches(item, MatchState matchState) => item is StateError; |
| 181 } |
| 182 |
| 183 /// A matcher for HttpExceptions. |
| 184 const isHttpException = const _HttpException(); |
| 185 |
| 186 /// A matcher for functions that throw HttpException. |
| 187 const Matcher throwsHttpException = |
| 188 const Throws(isHttpException); |
| 189 |
| 190 class _HttpException extends TypeMatcher { |
| 191 const _HttpException() : super("HttpException"); |
| 192 bool matches(item, MatchState matchState) => item is HttpException; |
| 193 } |
| 194 |
| 195 /// A matcher for RedirectLimitExceededExceptions. |
| 196 const isRedirectLimitExceededException = |
| 197 const _RedirectLimitExceededException(); |
| 198 |
| 199 /// A matcher for functions that throw RedirectLimitExceededException. |
| 200 const Matcher throwsRedirectLimitExceededException = |
| 201 const Throws(isRedirectLimitExceededException); |
| 202 |
| 203 class _RedirectLimitExceededException extends TypeMatcher { |
| 204 const _RedirectLimitExceededException() : |
| 205 super("RedirectLimitExceededException"); |
| 206 |
| 207 bool matches(item, MatchState matchState) => |
| 208 item is RedirectLimitExceededException; |
| 209 } |
| 210 |
| 211 // ---------------------------------------------------------------------------- |
| 212 |
17 void main() { | 213 void main() { |
18 setUp(startServer); | 214 setUp(startServer); |
19 tearDown(stopServer); | 215 tearDown(stopServer); |
20 | 216 |
21 test('head', () { | 217 test('head', () { |
22 expect(new CurlClient().head(serverUrl).transform((response) { | 218 expect(new CurlClient().head(serverUrl).transform((response) { |
23 expect(response.statusCode, equals(200)); | 219 expect(response.statusCode, equals(200)); |
24 expect(response.body, equals('')); | 220 expect(response.body, equals('')); |
25 }), completes); | 221 }), completes); |
26 }); | 222 }); |
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
255 test('without following redirects', () { | 451 test('without following redirects', () { |
256 var request = new http.Request('GET', serverUrl.resolve('/redirect')); | 452 var request = new http.Request('GET', serverUrl.resolve('/redirect')); |
257 request.followRedirects = false; | 453 request.followRedirects = false; |
258 expect(new CurlClient().send(request).chain(http.Response.fromStream) | 454 expect(new CurlClient().send(request).chain(http.Response.fromStream) |
259 .transform((response) { | 455 .transform((response) { |
260 expect(response.statusCode, equals(302)); | 456 expect(response.statusCode, equals(302)); |
261 expect(response.isRedirect, true); | 457 expect(response.isRedirect, true); |
262 }), completes); | 458 }), completes); |
263 }); | 459 }); |
264 } | 460 } |
OLD | NEW |