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

Side by Side Diff: generated/googleapis_beta/test/common/common_internal_test.dart

Issue 559053002: Generate 0.1.0 version of googleapis/googleapis_beta (Closed) Base URL: git@github.com:dart-lang/googleapis.git@master
Patch Set: Created 6 years, 3 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
OLDNEW
(Empty)
1 library googleapis_beta.common_internal_test;
2 import 'dart:async';
3 import 'dart:convert';
4
5 import 'package:crypto/crypto.dart' as crypto;
6 import 'package:googleapis_beta/common/common.dart';
7 import 'package:googleapis_beta/src/common_internal.dart';
8 import 'package:http/http.dart' as http;
9 import 'package:unittest/unittest.dart';
10 class HttpServerMock extends http.BaseClient {
11 Function _callback;
12 bool _expectJson;
13
14 void register(Function callback, bool expectJson) {
15 _callback = callback;
16 _expectJson = expectJson;
17 }
18
19 Future<http.StreamedResponse> send(http.BaseRequest request) {
20 if (_expectJson) {
21 return request.finalize()
22 .transform(UTF8.decoder)
23 .join('')
24 .then((String jsonString) {
25 if (jsonString.isEmpty) {
26 return _callback(request, null);
27 } else {
28 return _callback(request, JSON.decode(jsonString));
29 }
30 });
31 } else {
32 var stream = request.finalize();
33 if (stream == null) {
34 return _callback(request, []);
35 } else {
36 return stream.toBytes().then((data) {
37 return _callback(request, data);
38 });
39 }
40 }
41 }
42 }
43
44 http.StreamedResponse stringResponse(int status, Map headers, String body) {
45 var stream = new Stream.fromIterable([UTF8.encode(body)]);
46 return new http.StreamedResponse(stream, status, headers: headers);
47 }
48
49 http.StreamedResponse binaryResponse(int status,
50 Map<String,String> headers,
51 List<int> bytes) {
52 var stream = new Stream.fromIterable([bytes]);
53 return new http.StreamedResponse(stream, status, headers: headers);
54 }
55
56 Stream<List<int>> byteStream(String s) {
57 var bodyController = new StreamController();
58 bodyController.add(UTF8.encode(s));
59 bodyController.close();
60 return bodyController.stream;
61 }
62
63 class _ApiRequestError extends TypeMatcher {
64 const _ApiRequestError() : super("ApiRequestError");
65 bool matches(item, Map matchState) => item is ApiRequestError;
66 }
67
68 class _DetailedApiRequestError extends TypeMatcher {
69 const _DetailedApiRequestError() : super("DetailedApiRequestError");
70 bool matches(item, Map matchState) => item is DetailedApiRequestError;
71 }
72
73 class TestError {}
74
75 class _TestError extends TypeMatcher {
76 const _TestError() : super("TestError");
77 bool matches(item, Map matchState) => item is TestError;
78 }
79
80 const isApiRequestError = const _ApiRequestError();
81 const isDetailedApiRequestError = const _DetailedApiRequestError();
82 const isTestError = const _TestError();
83
84
85 main() {
86 group('common-external', () {
87 test('escaper', () {
88 expect(Escaper.ecapePathComponent('a/b%c '), equals('a%2Fb%25c%20'));
89 expect(Escaper.ecapeVariable('a/b%c '), equals('a%2Fb%25c%20'));
90 expect(Escaper.ecapeVariableReserved('a/b%c+ '), equals('a/b%25c+%20'));
91 expect(Escaper.escapeQueryComponent('a/b%c '), equals('a%2Fb%25c%20'));
92 });
93
94 test('mapMap', () {
95 newTestMap() => {
96 's' : 'string',
97 'i' : 42,
98 };
99
100 var copy = mapMap(newTestMap());
101 expect(copy, hasLength(2));
102 expect(copy['s'], equals('string'));
103 expect(copy['i'], equals(42));
104
105
106 var mod = mapMap(newTestMap(), (x) => '$x foobar');
107 expect(mod, hasLength(2));
108 expect(mod['s'], equals('string foobar'));
109 expect(mod['i'], equals('42 foobar'));
110 });
111
112 test('base64-encoder', () {
113 var base64encoder = new Base64Encoder();
114
115 testString(String msg, String expectedBase64) {
116 var msgBytes = UTF8.encode(msg);
117
118 Stream singleByteStream(List<int> msgBytes) {
119 var controller = new StreamController();
120 for (var byte in msgBytes) {
121 controller.add([byte]);
122 }
123 controller.close();
124 return controller.stream;
125 }
126
127 Stream allByteStream(List<int> msgBytes) {
128 var controller = new StreamController();
129 controller.add(msgBytes);
130 controller.close();
131 return controller.stream;
132 }
133
134 singleByteStream(msgBytes)
135 .transform(base64encoder)
136 .join('')
137 .then(expectAsync((String result) {
138 expect(result, equals(expectedBase64));
139 }));
140
141 allByteStream(msgBytes)
142 .transform(base64encoder)
143 .join('')
144 .then(expectAsync((String result) {
145 expect(result, equals(expectedBase64));
146 }));
147
148 expect(Base64Encoder.lengthOfBase64Stream(msg.length),
149 equals(expectedBase64.length));
150 }
151
152 testString('pleasure.', 'cGxlYXN1cmUu');
153 testString('leasure.', 'bGVhc3VyZS4=');
154 testString('easure.', 'ZWFzdXJlLg==');
155 testString('asure.', 'YXN1cmUu');
156 testString('sure.', 'c3VyZS4=');
157 testString('', '');
158 });
159
160 group('chunk-stack', () {
161 var chunkSize = 9;
162
163 folded(List<List<int>> byteArrays) {
164 return byteArrays.fold([], (buf, e) => buf..addAll(e));
165 }
166
167 test('finalize', () {
168 var chunkStack = new ChunkStack(9);
169 chunkStack.finalize();
170 expect(() => chunkStack.addBytes([1]), throwsA(isStateError));
171 expect(() => chunkStack.finalize(), throwsA(isStateError));
172 });
173
174 test('empty', () {
175 var chunkStack = new ChunkStack(9);
176 expect(chunkStack.length, equals(0));
177 chunkStack.finalize();
178 expect(chunkStack.length, equals(0));
179 });
180
181 test('sub-chunk-size', () {
182 var bytes = [1, 2, 3];
183
184 var chunkStack = new ChunkStack(9);
185 chunkStack.addBytes(bytes);
186 expect(chunkStack.length, equals(0));
187 chunkStack.finalize();
188 expect(chunkStack.length, equals(1));
189 expect(chunkStack.totalByteLength, equals(bytes.length));
190
191 var chunks = chunkStack.removeSublist(0, chunkStack.length);
192 expect(chunkStack.length, equals(0));
193 expect(chunks, hasLength(1));
194
195 expect(folded(chunks.first.byteArrays), equals(bytes));
196 expect(chunks.first.offset, equals(0));
197 expect(chunks.first.length, equals(3));
198 expect(chunks.first.endOfChunk, equals(bytes.length));
199 });
200
201 test('exact-chunk-size', () {
202 var bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9];
203
204 var chunkStack = new ChunkStack(9);
205 chunkStack.addBytes(bytes);
206 expect(chunkStack.length, equals(1));
207 chunkStack.finalize();
208 expect(chunkStack.length, equals(1));
209 expect(chunkStack.totalByteLength, equals(bytes.length));
210
211 var chunks = chunkStack.removeSublist(0, chunkStack.length);
212 expect(chunkStack.length, equals(0));
213 expect(chunks, hasLength(1));
214
215 expect(folded(chunks.first.byteArrays), equals(bytes));
216 expect(chunks.first.offset, equals(0));
217 expect(chunks.first.length, equals(bytes.length));
218 expect(chunks.first.endOfChunk, equals(bytes.length));
219 });
220
221 test('super-chunk-size', () {
222 var bytes0 = [1, 2, 3, 4];
223 var bytes1 = [1, 2, 3, 4];
224 var bytes2 = [5, 6, 7, 8, 9, 10, 11];
225 var bytes = folded([bytes0, bytes1, bytes2]);
226
227 var chunkStack = new ChunkStack(9);
228 chunkStack.addBytes(bytes0);
229 chunkStack.addBytes(bytes1);
230 chunkStack.addBytes(bytes2);
231 expect(chunkStack.length, equals(1));
232 chunkStack.finalize();
233 expect(chunkStack.length, equals(2));
234 expect(chunkStack.totalByteLength, equals(bytes.length));
235
236 var chunks = chunkStack.removeSublist(0, chunkStack.length);
237 expect(chunkStack.length, equals(0));
238 expect(chunks, hasLength(2));
239
240 expect(folded(chunks.first.byteArrays),
241 equals(bytes.sublist(0, chunkSize)));
242 expect(chunks.first.offset, equals(0));
243 expect(chunks.first.length, equals(chunkSize));
244 expect(chunks.first.endOfChunk, equals(chunkSize));
245
246 expect(folded(chunks.last.byteArrays),
247 equals(bytes.sublist(chunkSize)));
248 expect(chunks.last.offset, equals(chunkSize));
249 expect(chunks.last.length, equals(bytes.length - chunkSize));
250 expect(chunks.last.endOfChunk, equals(bytes.length));
251 });
252 });
253
254 test('media', () {
255 // Tests for [MediaRange]
256 var partialRange = new ByteRange(1, 100);
257 expect(partialRange.start, equals(1));
258 expect(partialRange.end, equals(100));
259
260 var fullRange = new ByteRange(0, -1);
261 expect(fullRange.start, equals(0));
262 expect(fullRange.end, equals(-1));
263
264 expect(() => new ByteRange(0, 0), throws);
265 expect(() => new ByteRange(-1, 0), throws);
266 expect(() => new ByteRange(-1, 1), throws);
267
268 // Tests for [DownloadOptions]
269 expect(DownloadOptions.Metadata.isMetadataDownload, isTrue);
270
271 expect(DownloadOptions.FullMedia.isFullDownload, isTrue);
272 expect(DownloadOptions.FullMedia.isMetadataDownload, isFalse);
273
274 // Tests for [Media]
275 var stream = new StreamController().stream;
276 expect(() => new Media(null, 0, contentType: 'foobar'),
277 throwsA(isArgumentError));
278 expect(() => new Media(stream, 0, contentType: null),
279 throwsA(isArgumentError));
280 expect(() => new Media(stream, -1, contentType: 'foobar'),
281 throwsA(isArgumentError));
282
283 var lengthUnknownMedia = new Media(stream, null);
284 expect(lengthUnknownMedia.stream, equals(stream));
285 expect(lengthUnknownMedia.length, equals(null));
286
287 var media = new Media(stream, 10, contentType: 'foobar');
288 expect(media.stream, equals(stream));
289 expect(media.length, equals(10));
290 expect(media.contentType, equals('foobar'));
291
292 // Tests for [ResumableUploadOptions]
293 expect(() => new ResumableUploadOptions(numberOfAttempts: 0),
294 throwsA(isArgumentError));
295 expect(() => new ResumableUploadOptions(chunkSize: 1),
296 throwsA(isArgumentError));
297 });
298
299 group('api-requester', () {
300 var httpMock, rootUrl, basePath;
301 ApiRequester requester;
302
303 var responseHeaders = {
304 'content-type' : 'application/json; charset=utf-8',
305 };
306
307 setUp(() {
308 httpMock = new HttpServerMock();
309 rootUrl = 'http://example.com/';
310 basePath = '/base/';
311 requester = new ApiRequester(httpMock, rootUrl, basePath);
312 });
313
314
315 // Tests for Request, Response
316
317 group('metadata-request-response', () {
318 test('empty-request-empty-response', () {
319 httpMock.register(expectAsync((http.BaseRequest request, json) {
320 expect(request.method, equals('GET'));
321 expect('${request.url}',
322 equals('http://example.com/base/abc?alt=json'));
323 return stringResponse(200, responseHeaders, '');
324 }), true);
325 requester.request('abc', 'GET').then(expectAsync((response) {
326 expect(response, isNull);
327 }));
328 });
329
330 test('json-map-request-json-map-response', () {
331 httpMock.register(expectAsync((http.BaseRequest request, json) {
332 expect(request.method, equals('GET'));
333 expect('${request.url}',
334 equals('http://example.com/base/abc?alt=json'));
335 expect(json is Map, isTrue);
336 expect(json, hasLength(1));
337 expect(json['foo'], equals('bar'));
338 return stringResponse(200, responseHeaders, '{"foo2" : "bar2"}');
339 }), true);
340 requester.request('abc',
341 'GET',
342 body: JSON.encode({'foo' : 'bar'})).then(
343 expectAsync((response) {
344 expect(response is Map, isTrue);
345 expect(response, hasLength(1));
346 expect(response['foo2'], equals('bar2'));
347 }));
348 });
349
350 test('json-list-request-json-list-response', () {
351 httpMock.register(expectAsync((http.BaseRequest request, json) {
352 expect(request.method, equals('GET'));
353 expect('${request.url}',
354 equals('http://example.com/base/abc?alt=json'));
355 expect(json is List, isTrue);
356 expect(json, hasLength(2));
357 expect(json[0], equals('a'));
358 expect(json[1], equals(1));
359 return stringResponse(200, responseHeaders, '["b", 2]');
360 }), true);
361 requester.request('abc',
362 'GET',
363 body: JSON.encode(['a', 1])).then(
364 expectAsync((response) {
365 expect(response is List, isTrue);
366 expect(response[0], equals('b'));
367 expect(response[1], equals(2));
368 }));
369 });
370 });
371
372 group('media-download', () {
373 test('media-download', () {
374 var data256 = new List.generate(256, (i) => i);
375 httpMock.register(expectAsync((http.BaseRequest request, data) {
376 expect(request.method, equals('GET'));
377 expect('${request.url}',
378 equals('http://example.com/base/abc?alt=media'));
379 expect(data, isEmpty);
380 var headers = {
381 'content-length' : '${data256.length}',
382 'content-type' : 'foobar',
383 };
384 return binaryResponse(200, headers, data256);
385 }), false);
386 requester.request('abc',
387 'GET',
388 body: '',
389 downloadOptions: DownloadOptions.FullMedia).then(
390 expectAsync((Media media) {
391 expect(media.contentType, equals('foobar'));
392 expect(media.length, equals(data256.length));
393 media.stream.fold([], (b, d) => b..addAll(d)).then(expectAsync((d) {
394 expect(d, equals(data256));
395 }));
396 }));
397 });
398
399 test('media-download-partial', () {
400 var data256 = new List.generate(256, (i) => i);
401 var data64 = data256.sublist(128, 128 + 64);
402
403 httpMock.register(expectAsync((http.BaseRequest request, data) {
404 expect(request.method, equals('GET'));
405 expect('${request.url}',
406 equals('http://example.com/base/abc?alt=media'));
407 expect(data, isEmpty);
408 expect(request.headers['range'],
409 equals('bytes=128-191'));
410 var headers = {
411 'content-length' : '${data64.length}',
412 'content-type' : 'foobar',
413 'content-range' : 'bytes 128-191/256',
414 };
415 return binaryResponse(200, headers, data64);
416 }), false);
417 var range = new ByteRange(128, 128 + 64 - 1);
418 var options = new PartialDownloadOptions(range);
419 requester.request('abc',
420 'GET',
421 body: '',
422 downloadOptions: options).then(
423 expectAsync((Media media) {
424 expect(media.contentType, equals('foobar'));
425 expect(media.length, equals(data64.length));
426 media.stream.fold([], (b, d) => b..addAll(d)).then(expectAsync((d) {
427 expect(d, equals(data64));
428 }));
429 }));
430 });
431
432 test('json-upload-media-download', () {
433 var data256 = new List.generate(256, (i) => i);
434 httpMock.register(expectAsync((http.BaseRequest request, json) {
435 expect(request.method, equals('GET'));
436 expect('${request.url}',
437 equals('http://example.com/base/abc?alt=media'));
438 expect(json is List, isTrue);
439 expect(json, hasLength(2));
440 expect(json[0], equals('a'));
441 expect(json[1], equals(1));
442
443 var headers = {
444 'content-length' : '${data256.length}',
445 'content-type' : 'foobar',
446 };
447 return binaryResponse(200, headers, data256);
448 }), true);
449 requester.request('abc',
450 'GET',
451 body: JSON.encode(['a', 1]),
452 downloadOptions: DownloadOptions.FullMedia).then(
453 expectAsync((Media media) {
454 expect(media.contentType, equals('foobar'));
455 expect(media.length, equals(data256.length));
456 media.stream.fold([], (b, d) => b..addAll(d)).then(expectAsync((d) {
457 expect(d, equals(data256));
458 }));
459 }));
460 });
461 });
462
463 // Tests for media uploads
464
465 group('media-upload', () {
466 Stream streamFromByteArrays(byteArrays) {
467 var controller = new StreamController();
468 for (var array in byteArrays) {
469 controller.add(array);
470 }
471 controller.close();
472 return controller.stream;
473 }
474 Media mediaFromByteArrays(byteArrays, {bool withLen: true}) {
475 int len = 0;
476 byteArrays.forEach((array) { len += array.length; });
477 if (!withLen) len = null;
478 return new Media(streamFromByteArrays(byteArrays),
479 len,
480 contentType: 'foobar');
481 }
482 validateServerRequest(e, http.BaseRequest request, List<int> data) {
483 return new Future.sync(() {
484 var h = e['headers'];
485 var r = e['response'];
486
487 expect(request.url.toString(), equals(e['url']));
488 expect(request.method, equals(e['method']));
489 h.forEach((k, v) {
490 expect(request.headers[k], equals(v));
491 });
492
493 expect(data, equals(e['data']));
494 return r;
495 });
496 }
497 serverRequestValidator(List expectations) {
498 int i = 0;
499 return (http.BaseRequest request, List<int> data) {
500 return validateServerRequest(expectations[i++], request, data);
501 };
502 }
503
504 test('simple', () {
505 var bytes = new List.generate(10 * 256 * 1024 + 1, (i) => i % 256);
506 var expectations = [
507 {
508 'url' : 'http://example.com/xyz?uploadType=media&alt=json',
509 'method' : 'POST',
510 'data' : bytes,
511 'headers' : {
512 'content-length' : '${bytes.length}',
513 'content-type' : 'foobar',
514 },
515 'response' : stringResponse(200, responseHeaders, '')
516 },
517 ];
518
519 httpMock.register(
520 expectAsync(serverRequestValidator(expectations)), false);
521 var media = mediaFromByteArrays([bytes]);
522 requester.request('/xyz',
523 'POST',
524 uploadMedia: media).then(
525 expectAsync((response) {}));
526 });
527
528 test('multipart-upload', () {
529 var bytes = new List.generate(10 * 256 * 1024 + 1, (i) => i % 256);
530 var contentBytes =
531 '--314159265358979323846\r\n'
532 'Content-Type: $CONTENT_TYPE_JSON_UTF8\r\n\r\n'
533 'BODY'
534 '\r\n--314159265358979323846\r\n'
535 'Content-Type: foobar\r\n'
536 'Content-Transfer-Encoding: base64\r\n\r\n'
537 '${crypto.CryptoUtils.bytesToBase64(bytes)}'
538 '\r\n--314159265358979323846--';
539
540 var expectations = [
541 {
542 'url' : 'http://example.com/xyz?uploadType=multipart&alt=json',
543 'method' : 'POST',
544 'data' : UTF8.encode('$contentBytes'),
545 'headers' : {
546 'content-length' : '${contentBytes.length}',
547 'content-type' :
548 'multipart/related; boundary="314159265358979323846"',
549 },
550 'response' : stringResponse(200, responseHeaders, '')
551 },
552 ];
553
554 httpMock.register(
555 expectAsync(serverRequestValidator(expectations)), false);
556 var media = mediaFromByteArrays([bytes]);
557 requester.request('/xyz',
558 'POST',
559 body: 'BODY',
560 uploadMedia: media).then(
561 expectAsync((response) {}));
562 });
563
564 group('resumable-upload', () {
565 // TODO: respect [stream]
566 buildExpectations(List<int> bytes, int chunkSize, bool stream,
567 {int numberOfServerErrors: 0}) {
568 int totalLength = bytes.length;
569 int numberOfChunks = totalLength ~/ chunkSize;
570 int numberOfBytesInLastChunk = totalLength % chunkSize;
571
572 if (numberOfBytesInLastChunk > 0) {
573 numberOfChunks++;
574 } else {
575 numberOfBytesInLastChunk = chunkSize;
576 }
577
578 var expectations = [];
579
580 // First request is making a POST and gets the upload URL.
581 expectations.add({
582 'url' : 'http://example.com/xyz?uploadType=resumable&alt=json',
583 'method' : 'POST',
584 'data' : [],
585 'headers' : {
586 'content-length' : '0',
587 'content-type' : 'application/json; charset=utf-8',
588 'x-upload-content-type' : 'foobar',
589 }..addAll(stream ? {} : {
590 'x-upload-content-length' : '$totalLength',
591 }),
592 'response' : stringResponse(
593 200, {'location' : 'http://upload.com/'}, '')
594 });
595
596 var lastEnd = 0;
597 for (int i = 0; i < numberOfChunks; i++) {
598 bool isLast = i == (numberOfChunks - 1);
599 var lengthMarker = stream && !isLast ? '*' : '$totalLength';
600
601 int bytesToExpect = chunkSize;
602 if (isLast) {
603 bytesToExpect = numberOfBytesInLastChunk;
604 }
605
606 var start = i * chunkSize;
607 var end = start + bytesToExpect;
608 var sublist = bytes.sublist(start, end);
609
610 var firstContentRange =
611 'bytes $start-${end-1}/$lengthMarker';
612 var firstRange =
613 'bytes=0-${end-1}';
614
615 // We issue [numberOfServerErrors] 503 errors first, and then a
616 // successfull response.
617 for (var j = 0; j < (numberOfServerErrors + 1); j++) {
618 bool successfullResponse = j == numberOfServerErrors;
619
620 var response;
621 if (successfullResponse) {
622 var headers = isLast
623 ? { 'content-type' : 'application/json; charset=utf-8' }
624 : {'range' : firstRange };
625 response = stringResponse(isLast ? 200 : 308, headers, '');
626 } else {
627 var headers = {};
628 response = stringResponse(503, headers, '');
629 }
630
631 expectations.add({
632 'url' : 'http://upload.com/',
633 'method' : 'PUT',
634 'data' : sublist,
635 'headers' : {
636 'content-length' : '${sublist.length}',
637 'content-range' : firstContentRange,
638 'content-type' : 'foobar',
639 },
640 'response' : response,
641 });
642 }
643 }
644 return expectations;
645 }
646
647 List<List<int>> makeParts(List<int> bytes, List<int> splits) {
648 var parts = [];
649 int lastEnd = 0;
650 for (int i = 0; i < splits.length; i++) {
651 parts.add(bytes.sublist(lastEnd, splits[i]));
652 lastEnd = splits[i];
653 }
654 return parts;
655 }
656
657 runTest(int chunkSizeInBlocks, int length, List splits, bool stream,
658 {int numberOfServerErrors: 0, resumableOptions,
659 int expectedErrorStatus, int messagesNrOfFailure}) {
660 int chunkSize = chunkSizeInBlocks * 256 * 1024;
661
662 int i = 0;
663 var bytes = new List.generate(length, (i) => i % 256);
664 var parts = makeParts(bytes, splits);
665
666 // Simulation of our server
667 var expectations = buildExpectations(
668 bytes, chunkSize, false,
669 numberOfServerErrors: numberOfServerErrors);
670 // If the server simulates 50X errors and the client resumes only
671 // a limited amount of time, we'll trunkate the number of requests
672 // the server expects.
673 // [The client will give up and if the server expects more, the test
674 // would timeout.]
675 if (expectedErrorStatus != null) {
676 expectations = expectations.sublist(0, messagesNrOfFailure);
677 }
678 httpMock.register(
679 expectAsync(serverRequestValidator(expectations),
680 count: expectations.length),
681 false);
682
683 // Our client
684 var media = mediaFromByteArrays(parts);
685 if (resumableOptions == null) {
686 resumableOptions =
687 new ResumableUploadOptions(chunkSize: chunkSize);
688 }
689 var result = requester.request('/xyz',
690 'POST',
691 uploadMedia: media,
692 uploadOptions: resumableOptions);
693 if (expectedErrorStatus != null) {
694 result.catchError(expectAsync((error) {
695 expect(error is DetailedApiRequestError, isTrue);
696 expect(error.status, equals(expectedErrorStatus));
697 }));
698 } else {
699 result.then(expectAsync((_) {}));
700 }
701 }
702
703 Function backoffWrapper(int callCount) {
704 return expectAsync((int failedAttempts) {
705 var exp = ResumableUploadOptions.ExponentialBackoff;
706 Duration duration = exp(failedAttempts);
707 expect(duration.inSeconds, equals(1 << (failedAttempts - 1)));
708 return const Duration(milliseconds: 1);
709 }, count: callCount);
710 }
711
712 test('length-small-block', () {
713 runTest(1, 10, [10], false);
714 });
715
716 test('length-small-block-parts', () {
717 runTest(1, 20, [1, 2, 3, 4, 5, 6, 7, 19, 20], false);
718 });
719
720 test('length-big-block', () {
721 runTest(1, 1024 * 1024, [1024*1024], false);
722 });
723
724 test('length-big-block-parts', () {
725 runTest(1, 1024 * 1024,
726 [1,
727 256*1024-1,
728 256*1024,
729 256*1024+1,
730 1024*1024-1,
731 1024*1024], false);
732 });
733
734 test('stream-small-block', () {
735 runTest(1, 10, [10], true);
736 });
737
738 test('stream-small-block-parts', () {
739 runTest(1, 20, [1, 2, 3, 4, 5, 6, 7, 19, 20], true);
740 });
741
742 test('stream-big-block', () {
743 runTest(1, 1024 * 1024, [1024*1024], true);
744 });
745
746 test('stream-big-block-parts', () {
747 runTest(1, 1024 * 1024,
748 [1,
749 256*1024-1,
750 256*1024,
751 256*1024+1,
752 1024*1024-1,
753 1024*1024], true);
754 });
755
756 test('stream-big-block-parts--with-server-error-recovery', () {
757 var numFailedAttempts = 4 * 3;
758 var options = new ResumableUploadOptions(
759 chunkSize: 256 * 1024, numberOfAttempts: 4,
760 backoffFunction: backoffWrapper(numFailedAttempts));
761 runTest(1, 1024 * 1024,
762 [1,
763 256*1024-1,
764 256*1024,
765 256*1024+1,
766 1024*1024-1,
767 1024*1024],
768 true,
769 numberOfServerErrors: 3,
770 resumableOptions: options);
771 });
772
773 test('stream-big-block-parts--server-error', () {
774 var numFailedAttempts = 2;
775 var options = new ResumableUploadOptions(
776 chunkSize: 256 * 1024, numberOfAttempts: 3,
777 backoffFunction: backoffWrapper(numFailedAttempts));
778 runTest(1, 1024 * 1024,
779 [1,
780 256*1024-1,
781 256*1024,
782 256*1024+1,
783 1024*1024-1,
784 1024*1024],
785 true,
786 numberOfServerErrors: 3,
787 resumableOptions: options,
788 expectedErrorStatus: 503,
789 messagesNrOfFailure: 4);
790 });
791 });
792 });
793
794 // Tests for error responses
795 group('request-errors', () {
796 makeTestError() {
797 // All errors from the [http.Client] propagate through.
798 // We use [TestError] to simulate it.
799 httpMock.register(expectAsync((http.BaseRequest request, string) {
800 return new Future.error(new TestError());
801 }), false);
802 }
803
804 makeDetailed400Error() {
805 httpMock.register(expectAsync((http.BaseRequest request, string) {
806 return stringResponse(400,
807 responseHeaders,
808 '{"error" : {"code" : 42, "message": "foo"}}');
809 }), false);
810 }
811
812 makeNormal199Error() {
813 httpMock.register(expectAsync((http.BaseRequest request, string) {
814 return stringResponse(199, {}, '');
815 }), false);
816 }
817
818 makeInvalidContentTypeError() {
819 httpMock.register(expectAsync((http.BaseRequest request, string) {
820 var responseHeaders = { 'content-type' : 'image/png'};
821 return stringResponse(200, responseHeaders, '');
822 }), false);
823 }
824
825
826 test('normal-http-client', () {
827 makeTestError();
828 expect(requester.request('abc', 'GET'), throwsA(isTestError));
829 });
830
831 test('normal-detailed-400', () {
832 makeDetailed400Error();
833 requester.request('abc', 'GET')
834 .catchError(expectAsync((error, stack) {
835 expect(error, isDetailedApiRequestError);
836 DetailedApiRequestError e = error;
837 expect(e.status, equals(42));
838 expect(e.message, equals('foo'));
839 }));
840 });
841
842 test('normal-199', () {
843 makeNormal199Error();
844 expect(requester.request('abc', 'GET'), throwsA(isApiRequestError));
845 });
846
847 test('normal-invalid-content-type', () {
848 makeInvalidContentTypeError();
849 expect(requester.request('abc', 'GET'), throwsA(isApiRequestError));
850 });
851
852 var options = DownloadOptions.FullMedia;
853 test('media-http-client', () {
854 makeTestError();
855 expect(requester.request('abc', 'GET', downloadOptions: options),
856 throwsA(isTestError));
857 });
858
859 test('media-detailed-400', () {
860 makeDetailed400Error();
861 requester.request('abc', 'GET')
862 .catchError(expectAsync((error, stack) {
863 expect(error, isDetailedApiRequestError);
864 DetailedApiRequestError e = error;
865 expect(e.status, equals(42));
866 expect(e.message, equals('foo'));
867 }));
868 });
869
870 test('media-199', () {
871 makeNormal199Error();
872 expect(requester.request('abc', 'GET', downloadOptions: options),
873 throwsA(isApiRequestError));
874 });
875 });
876
877
878 // Tests for path/query parameters
879
880 test('request-parameters-query', () {
881 var queryParams = {
882 'a' : ['a1', 'a2'],
883 's' : ['s1']
884 };
885 httpMock.register(expectAsync((http.BaseRequest request, json) {
886 expect(request.method, equals('GET'));
887 expect('${request.url}',
888 equals('http://example.com/base/abc?a=a1&a=a2&s=s1&alt=json'));
889 return stringResponse(200, responseHeaders, '');
890 }), true);
891 requester.request('abc', 'GET', queryParams: queryParams)
892 .then(expectAsync((response) {
893 expect(response, isNull);
894 }));
895 });
896
897 test('request-parameters-path', () {
898 httpMock.register(expectAsync((http.BaseRequest request, json) {
899 expect(request.method, equals('GET'));
900 expect('${request.url}', equals(
901 'http://example.com/base/s/foo/a1/a2/bar/s1/e?alt=json'));
902 return stringResponse(200, responseHeaders, '');
903 }), true);
904 requester.request('s/foo/a1/a2/bar/s1/e', 'GET')
905 .then(expectAsync((response) {
906 expect(response, isNull);
907 }));
908 });
909 });
910 });
911 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698