Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(310)

Side by Side Diff: utils/tests/pub/curl_client_test.dart

Issue 12090104: Stop using cURL in Pub. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « utils/pub/resource/certs/pkcs11.txt ('k') | utils/tests/pub/pub.status » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library curl_client_test;
6
7 import 'dart:io';
8 import 'dart:isolate';
9 import 'dart:json' as json;
10 import 'dart:uri';
11
12 import '../../../pkg/unittest/lib/unittest.dart';
13 import '../../../pkg/http/lib/http.dart' as http;
14 import '../../pub/curl_client.dart';
15 import '../../pub/io.dart';
16 import '../../pub/utils.dart';
17
18 // TODO(rnystrom): All of the code from here to the first "---..." line was
19 // copied from pkg/http/test/utils.dart and pkg/http/lib/src/utils.dart. It's
20 // copied here because http/test/utils.dart is now using "package:" imports and
21 // this is not. You cannot mix those because you end up with duplicate copies of
22 // the same library in memory. Since curl_client is going away soon anyway, I'm
23 // just copying the code here. Delete all of this when curl client is removed.
24
25 /// Returns the [Encoding] that corresponds to [charset]. Throws a
26 /// [FormatException] if no [Encoding] was found that corresponds to [charset].
27 /// [charset] may not be null.
28 Encoding requiredEncodingForCharset(String charset) {
29 var encoding = _encodingForCharset(charset);
30 if (encoding != null) return encoding;
31 throw new FormatException('Unsupported encoding "$charset".');
32 }
33
34 /// Returns the [Encoding] that corresponds to [charset]. Returns null if no
35 /// [Encoding] was found that corresponds to [charset]. [charset] may not be
36 /// null.
37 Encoding _encodingForCharset(String charset) {
38 charset = charset.toLowerCase();
39 if (charset == 'ascii' || charset == 'us-ascii') return Encoding.ASCII;
40 if (charset == 'utf-8') return Encoding.UTF_8;
41 if (charset == 'iso-8859-1') return Encoding.ISO_8859_1;
42 return null;
43 }
44
45 /// Converts [bytes] into a [String] according to [encoding].
46 String decodeString(List<int> bytes, Encoding encoding) {
47 // TODO(nweiz): implement this once issue 6284 is fixed.
48 return new String.fromCharCodes(bytes);
49 }
50
51 /// The current server instance.
52 HttpServer _server;
53
54 /// The URL for the current server instance.
55 Uri get serverUrl => Uri.parse('http://localhost:${_server.port}');
56
57 /// A dummy URL for constructing requests that won't be sent.
58 Uri get dummyUrl => Uri.parse('http://dartlang.org/');
59
60 /// Starts a new HTTP server.
61 void startServer() {
62 _server = new HttpServer();
63
64 _server.addRequestHandler((request) => request.path == '/error',
65 (request, response) {
66 response.statusCode = 400;
67 response.contentLength = 0;
68 response.outputStream.close();
69 });
70
71 _server.addRequestHandler((request) => request.path == '/loop',
72 (request, response) {
73 var n = int.parse(Uri.parse(request.uri).query);
74 response.statusCode = 302;
75 response.headers.set('location',
76 serverUrl.resolve('/loop?${n + 1}').toString());
77 response.contentLength = 0;
78 response.outputStream.close();
79 });
80
81 _server.addRequestHandler((request) => request.path == '/redirect',
82 (request, response) {
83 response.statusCode = 302;
84 response.headers.set('location', serverUrl.resolve('/').toString());
85 response.contentLength = 0;
86 response.outputStream.close();
87 });
88
89 _server.defaultRequestHandler = (request, response) {
90 consumeInputStream(request.inputStream).then((requestBodyBytes) {
91 response.statusCode = 200;
92 response.headers.contentType = new ContentType("application", "json");
93
94 var requestBody;
95 if (requestBodyBytes.isEmpty) {
96 requestBody = null;
97 } else if (request.headers.contentType.charset != null) {
98 var encoding = requiredEncodingForCharset(
99 request.headers.contentType.charset);
100 requestBody = decodeString(requestBodyBytes, encoding);
101 } else {
102 requestBody = requestBodyBytes;
103 }
104
105 var content = {
106 'method': request.method,
107 'path': request.path,
108 'headers': {}
109 };
110 if (requestBody != null) content['body'] = requestBody;
111 request.headers.forEach((name, values) {
112 // These headers are automatically generated by dart:io, so we don't
113 // want to test them here.
114 if (name == 'cookie' || name == 'host') return;
115
116 content['headers'][name] = values;
117 });
118
119 var outputEncoding;
120 var encodingName = request.queryParameters['response-encoding'];
121 if (encodingName != null) {
122 outputEncoding = requiredEncodingForCharset(encodingName);
123 } else {
124 outputEncoding = Encoding.ASCII;
125 }
126
127 var body = json.stringify(content);
128 response.contentLength = body.length;
129 response.outputStream.writeString(body, outputEncoding);
130 response.outputStream.close();
131 });
132 };
133
134 _server.listen("127.0.0.1", 0);
135 }
136
137 /// Stops the current HTTP server.
138 void stopServer() {
139 _server.close();
140 _server = null;
141 }
142
143 /// A matcher that matches JSON that parses to a value that matches the inner
144 /// matcher.
145 Matcher parse(matcher) => new _Parse(matcher);
146
147 class _Parse extends BaseMatcher {
148 final Matcher _matcher;
149
150 _Parse(this._matcher);
151
152 bool matches(item, MatchState matchState) {
153 if (item is! String) return false;
154
155 var parsed;
156 try {
157 parsed = json.parse(item);
158 } catch (e) {
159 return false;
160 }
161
162 return _matcher.matches(parsed, matchState);
163 }
164
165 Description describe(Description description) {
166 return description.add('parses to a value that ')
167 .addDescriptionOf(_matcher);
168 }
169 }
170
171 /// A matcher for HttpExceptions.
172 const isHttpException = const _HttpException();
173
174 /// A matcher for functions that throw HttpException.
175 const Matcher throwsHttpException =
176 const Throws(isHttpException);
177
178 class _HttpException extends TypeMatcher {
179 const _HttpException() : super("HttpException");
180 bool matches(item, MatchState matchState) => item is HttpException;
181 }
182
183 /// A matcher for RedirectLimitExceededExceptions.
184 const isRedirectLimitExceededException =
185 const _RedirectLimitExceededException();
186
187 /// A matcher for functions that throw RedirectLimitExceededException.
188 const Matcher throwsRedirectLimitExceededException =
189 const Throws(isRedirectLimitExceededException);
190
191 class _RedirectLimitExceededException extends TypeMatcher {
192 const _RedirectLimitExceededException() :
193 super("RedirectLimitExceededException");
194
195 bool matches(item, MatchState matchState) =>
196 item is RedirectLimitExceededException;
197 }
198
199 // ----------------------------------------------------------------------------
200
201 void main() {
202 setUp(startServer);
203 tearDown(stopServer);
204
205 test('head', () {
206 expect(new CurlClient().head(serverUrl).then((response) {
207 expect(response.statusCode, equals(200));
208 expect(response.body, equals(''));
209 }), completes);
210 });
211
212 test('get', () {
213 expect(new CurlClient().get(serverUrl, headers: {
214 'X-Random-Header': 'Value',
215 'X-Other-Header': 'Other Value'
216 }).then((response) {
217 expect(response.statusCode, equals(200));
218 expect(response.body, parse(equals({
219 'method': 'GET',
220 'path': '/',
221 'headers': {
222 'x-random-header': ['Value'],
223 'x-other-header': ['Other Value']
224 },
225 })));
226 }), completes);
227 });
228
229 test('post', () {
230 expect(new CurlClient().post(serverUrl, headers: {
231 'X-Random-Header': 'Value',
232 'X-Other-Header': 'Other Value'
233 }, fields: {
234 'some-field': 'value',
235 'other-field': 'other value'
236 }).then((response) {
237 expect(response.statusCode, equals(200));
238 expect(response.body, parse(equals({
239 'method': 'POST',
240 'path': '/',
241 'headers': {
242 'content-type': [
243 'application/x-www-form-urlencoded; charset=UTF-8'
244 ],
245 'content-length': ['40'],
246 'x-random-header': ['Value'],
247 'x-other-header': ['Other Value']
248 },
249 'body': 'some-field=value&other-field=other+value'
250 })));
251 }), completes);
252 });
253
254 test('post without fields', () {
255 expect(new CurlClient().post(serverUrl, headers: {
256 'X-Random-Header': 'Value',
257 'X-Other-Header': 'Other Value',
258 'Content-Type': 'text/plain'
259 }).then((response) {
260 expect(response.statusCode, equals(200));
261 expect(response.body, parse(equals({
262 'method': 'POST',
263 'path': '/',
264 'headers': {
265 'content-type': ['text/plain'],
266 'x-random-header': ['Value'],
267 'x-other-header': ['Other Value']
268 }
269 })));
270 }), completes);
271 });
272
273 test('put', () {
274 expect(new CurlClient().put(serverUrl, headers: {
275 'X-Random-Header': 'Value',
276 'X-Other-Header': 'Other Value'
277 }, fields: {
278 'some-field': 'value',
279 'other-field': 'other value'
280 }).then((response) {
281 expect(response.statusCode, equals(200));
282 expect(response.body, parse(equals({
283 'method': 'PUT',
284 'path': '/',
285 'headers': {
286 'content-type': [
287 'application/x-www-form-urlencoded; charset=UTF-8'
288 ],
289 'content-length': ['40'],
290 'x-random-header': ['Value'],
291 'x-other-header': ['Other Value']
292 },
293 'body': 'some-field=value&other-field=other+value'
294 })));
295 }), completes);
296 });
297
298 test('put without fields', () {
299 expect(new CurlClient().put(serverUrl, headers: {
300 'X-Random-Header': 'Value',
301 'X-Other-Header': 'Other Value',
302 'Content-Type': 'text/plain'
303 }).then((response) {
304 expect(response.statusCode, equals(200));
305 expect(response.body, parse(equals({
306 'method': 'PUT',
307 'path': '/',
308 'headers': {
309 'content-type': ['text/plain'],
310 'x-random-header': ['Value'],
311 'x-other-header': ['Other Value']
312 }
313 })));
314 }), completes);
315 });
316
317 test('delete', () {
318 expect(new CurlClient().delete(serverUrl, headers: {
319 'X-Random-Header': 'Value',
320 'X-Other-Header': 'Other Value'
321 }).then((response) {
322 expect(response.statusCode, equals(200));
323 expect(response.body, parse(equals({
324 'method': 'DELETE',
325 'path': '/',
326 'headers': {
327 'x-random-header': ['Value'],
328 'x-other-header': ['Other Value']
329 }
330 })));
331 }), completes);
332 });
333
334 test('read', () {
335 expect(new CurlClient().read(serverUrl, headers: {
336 'X-Random-Header': 'Value',
337 'X-Other-Header': 'Other Value'
338 }), completion(parse(equals({
339 'method': 'GET',
340 'path': '/',
341 'headers': {
342 'x-random-header': ['Value'],
343 'x-other-header': ['Other Value']
344 },
345 }))));
346 });
347
348 test('read throws an error for a 4** status code', () {
349 expect(new CurlClient().read(serverUrl.resolve('/error')),
350 throwsHttpException);
351 });
352
353 test('readBytes', () {
354 var future = new CurlClient().readBytes(serverUrl, headers: {
355 'X-Random-Header': 'Value',
356 'X-Other-Header': 'Other Value'
357 }).then((bytes) => new String.fromCharCodes(bytes));
358
359 expect(future, completion(parse(equals({
360 'method': 'GET',
361 'path': '/',
362 'headers': {
363 'x-random-header': ['Value'],
364 'x-other-header': ['Other Value']
365 },
366 }))));
367 });
368
369 test('readBytes throws an error for a 4** status code', () {
370 expect(new CurlClient().readBytes(serverUrl.resolve('/error')),
371 throwsHttpException);
372 });
373
374 test('#send a StreamedRequest', () {
375 var client = new CurlClient();
376 var request = new http.StreamedRequest("POST", serverUrl);
377 request.headers[HttpHeaders.CONTENT_TYPE] =
378 'application/json; charset=utf-8';
379
380 var future = client.send(request).then((response) {
381 expect(response.statusCode, equals(200));
382 return response.stream.bytesToString();
383 }).whenComplete(client.close);
384
385 expect(future, completion(parse(equals({
386 'method': 'POST',
387 'path': '/',
388 'headers': {
389 'content-type': ['application/json; charset=utf-8'],
390 'transfer-encoding': ['chunked']
391 },
392 'body': '{"hello": "world"}'
393 }))));
394
395 request.sink.add('{"hello": "world"}'.charCodes);
396 request.sink.close();
397 });
398
399 test('with one redirect', () {
400 var url = serverUrl.resolve('/redirect');
401 expect(new CurlClient().get(url).then((response) {
402 expect(response.statusCode, equals(200));
403 expect(response.body, parse(equals({
404 'method': 'GET',
405 'path': '/',
406 'headers': {}
407 })));
408 }), completes);
409 });
410
411 test('with too many redirects', () {
412 expect(new CurlClient().get(serverUrl.resolve('/loop?1')),
413 throwsRedirectLimitExceededException);
414 });
415
416 test('with a generic failure', () {
417 expect(new CurlClient().get('url fail'),
418 throwsHttpException);
419 });
420
421 test('with one redirect via HEAD', () {
422 var url = serverUrl.resolve('/redirect');
423 expect(new CurlClient().head(url).then((response) {
424 expect(response.statusCode, equals(200));
425 }), completes);
426 });
427
428 test('with too many redirects via HEAD', () {
429 expect(new CurlClient().head(serverUrl.resolve('/loop?1')),
430 throwsRedirectLimitExceededException);
431 });
432
433 test('with a generic failure via HEAD', () {
434 expect(new CurlClient().head('url fail'),
435 throwsHttpException);
436 });
437
438 test('without following redirects', () {
439 var request = new http.Request('GET', serverUrl.resolve('/redirect'));
440 request.followRedirects = false;
441 expect(new CurlClient().send(request).then(http.Response.fromStream)
442 .then((response) {
443 expect(response.statusCode, equals(302));
444 expect(response.isRedirect, true);
445 }), completes);
446 });
447 }
OLDNEW
« no previous file with comments | « utils/pub/resource/certs/pkcs11.txt ('k') | utils/tests/pub/pub.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698