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

Unified Diff: generated/googleapis/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 side-by-side diff with in-line comments
Download patch
Index: generated/googleapis/test/common/common_internal_test.dart
diff --git a/generated/googleapis/test/common/common_internal_test.dart b/generated/googleapis/test/common/common_internal_test.dart
new file mode 100644
index 0000000000000000000000000000000000000000..afae3baf8467b831003f3c1f1b82356bf693c148
--- /dev/null
+++ b/generated/googleapis/test/common/common_internal_test.dart
@@ -0,0 +1,911 @@
+library googleapis.common_internal_test;
+import 'dart:async';
+import 'dart:convert';
+
+import 'package:crypto/crypto.dart' as crypto;
+import 'package:googleapis/common/common.dart';
+import 'package:googleapis/src/common_internal.dart';
+import 'package:http/http.dart' as http;
+import 'package:unittest/unittest.dart';
+class HttpServerMock extends http.BaseClient {
+ Function _callback;
+ bool _expectJson;
+
+ void register(Function callback, bool expectJson) {
+ _callback = callback;
+ _expectJson = expectJson;
+ }
+
+ Future<http.StreamedResponse> send(http.BaseRequest request) {
+ if (_expectJson) {
+ return request.finalize()
+ .transform(UTF8.decoder)
+ .join('')
+ .then((String jsonString) {
+ if (jsonString.isEmpty) {
+ return _callback(request, null);
+ } else {
+ return _callback(request, JSON.decode(jsonString));
+ }
+ });
+ } else {
+ var stream = request.finalize();
+ if (stream == null) {
+ return _callback(request, []);
+ } else {
+ return stream.toBytes().then((data) {
+ return _callback(request, data);
+ });
+ }
+ }
+ }
+}
+
+http.StreamedResponse stringResponse(int status, Map headers, String body) {
+ var stream = new Stream.fromIterable([UTF8.encode(body)]);
+ return new http.StreamedResponse(stream, status, headers: headers);
+}
+
+http.StreamedResponse binaryResponse(int status,
+ Map<String,String> headers,
+ List<int> bytes) {
+ var stream = new Stream.fromIterable([bytes]);
+ return new http.StreamedResponse(stream, status, headers: headers);
+}
+
+Stream<List<int>> byteStream(String s) {
+ var bodyController = new StreamController();
+ bodyController.add(UTF8.encode(s));
+ bodyController.close();
+ return bodyController.stream;
+}
+
+class _ApiRequestError extends TypeMatcher {
+ const _ApiRequestError() : super("ApiRequestError");
+ bool matches(item, Map matchState) => item is ApiRequestError;
+}
+
+class _DetailedApiRequestError extends TypeMatcher {
+ const _DetailedApiRequestError() : super("DetailedApiRequestError");
+ bool matches(item, Map matchState) => item is DetailedApiRequestError;
+}
+
+class TestError {}
+
+class _TestError extends TypeMatcher {
+ const _TestError() : super("TestError");
+ bool matches(item, Map matchState) => item is TestError;
+}
+
+const isApiRequestError = const _ApiRequestError();
+const isDetailedApiRequestError = const _DetailedApiRequestError();
+const isTestError = const _TestError();
+
+
+main() {
+ group('common-external', () {
+ test('escaper', () {
+ expect(Escaper.ecapePathComponent('a/b%c '), equals('a%2Fb%25c%20'));
+ expect(Escaper.ecapeVariable('a/b%c '), equals('a%2Fb%25c%20'));
+ expect(Escaper.ecapeVariableReserved('a/b%c+ '), equals('a/b%25c+%20'));
+ expect(Escaper.escapeQueryComponent('a/b%c '), equals('a%2Fb%25c%20'));
+ });
+
+ test('mapMap', () {
+ newTestMap() => {
+ 's' : 'string',
+ 'i' : 42,
+ };
+
+ var copy = mapMap(newTestMap());
+ expect(copy, hasLength(2));
+ expect(copy['s'], equals('string'));
+ expect(copy['i'], equals(42));
+
+
+ var mod = mapMap(newTestMap(), (x) => '$x foobar');
+ expect(mod, hasLength(2));
+ expect(mod['s'], equals('string foobar'));
+ expect(mod['i'], equals('42 foobar'));
+ });
+
+ test('base64-encoder', () {
+ var base64encoder = new Base64Encoder();
+
+ testString(String msg, String expectedBase64) {
+ var msgBytes = UTF8.encode(msg);
+
+ Stream singleByteStream(List<int> msgBytes) {
+ var controller = new StreamController();
+ for (var byte in msgBytes) {
+ controller.add([byte]);
+ }
+ controller.close();
+ return controller.stream;
+ }
+
+ Stream allByteStream(List<int> msgBytes) {
+ var controller = new StreamController();
+ controller.add(msgBytes);
+ controller.close();
+ return controller.stream;
+ }
+
+ singleByteStream(msgBytes)
+ .transform(base64encoder)
+ .join('')
+ .then(expectAsync((String result) {
+ expect(result, equals(expectedBase64));
+ }));
+
+ allByteStream(msgBytes)
+ .transform(base64encoder)
+ .join('')
+ .then(expectAsync((String result) {
+ expect(result, equals(expectedBase64));
+ }));
+
+ expect(Base64Encoder.lengthOfBase64Stream(msg.length),
+ equals(expectedBase64.length));
+ }
+
+ testString('pleasure.', 'cGxlYXN1cmUu');
+ testString('leasure.', 'bGVhc3VyZS4=');
+ testString('easure.', 'ZWFzdXJlLg==');
+ testString('asure.', 'YXN1cmUu');
+ testString('sure.', 'c3VyZS4=');
+ testString('', '');
+ });
+
+ group('chunk-stack', () {
+ var chunkSize = 9;
+
+ folded(List<List<int>> byteArrays) {
+ return byteArrays.fold([], (buf, e) => buf..addAll(e));
+ }
+
+ test('finalize', () {
+ var chunkStack = new ChunkStack(9);
+ chunkStack.finalize();
+ expect(() => chunkStack.addBytes([1]), throwsA(isStateError));
+ expect(() => chunkStack.finalize(), throwsA(isStateError));
+ });
+
+ test('empty', () {
+ var chunkStack = new ChunkStack(9);
+ expect(chunkStack.length, equals(0));
+ chunkStack.finalize();
+ expect(chunkStack.length, equals(0));
+ });
+
+ test('sub-chunk-size', () {
+ var bytes = [1, 2, 3];
+
+ var chunkStack = new ChunkStack(9);
+ chunkStack.addBytes(bytes);
+ expect(chunkStack.length, equals(0));
+ chunkStack.finalize();
+ expect(chunkStack.length, equals(1));
+ expect(chunkStack.totalByteLength, equals(bytes.length));
+
+ var chunks = chunkStack.removeSublist(0, chunkStack.length);
+ expect(chunkStack.length, equals(0));
+ expect(chunks, hasLength(1));
+
+ expect(folded(chunks.first.byteArrays), equals(bytes));
+ expect(chunks.first.offset, equals(0));
+ expect(chunks.first.length, equals(3));
+ expect(chunks.first.endOfChunk, equals(bytes.length));
+ });
+
+ test('exact-chunk-size', () {
+ var bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9];
+
+ var chunkStack = new ChunkStack(9);
+ chunkStack.addBytes(bytes);
+ expect(chunkStack.length, equals(1));
+ chunkStack.finalize();
+ expect(chunkStack.length, equals(1));
+ expect(chunkStack.totalByteLength, equals(bytes.length));
+
+ var chunks = chunkStack.removeSublist(0, chunkStack.length);
+ expect(chunkStack.length, equals(0));
+ expect(chunks, hasLength(1));
+
+ expect(folded(chunks.first.byteArrays), equals(bytes));
+ expect(chunks.first.offset, equals(0));
+ expect(chunks.first.length, equals(bytes.length));
+ expect(chunks.first.endOfChunk, equals(bytes.length));
+ });
+
+ test('super-chunk-size', () {
+ var bytes0 = [1, 2, 3, 4];
+ var bytes1 = [1, 2, 3, 4];
+ var bytes2 = [5, 6, 7, 8, 9, 10, 11];
+ var bytes = folded([bytes0, bytes1, bytes2]);
+
+ var chunkStack = new ChunkStack(9);
+ chunkStack.addBytes(bytes0);
+ chunkStack.addBytes(bytes1);
+ chunkStack.addBytes(bytes2);
+ expect(chunkStack.length, equals(1));
+ chunkStack.finalize();
+ expect(chunkStack.length, equals(2));
+ expect(chunkStack.totalByteLength, equals(bytes.length));
+
+ var chunks = chunkStack.removeSublist(0, chunkStack.length);
+ expect(chunkStack.length, equals(0));
+ expect(chunks, hasLength(2));
+
+ expect(folded(chunks.first.byteArrays),
+ equals(bytes.sublist(0, chunkSize)));
+ expect(chunks.first.offset, equals(0));
+ expect(chunks.first.length, equals(chunkSize));
+ expect(chunks.first.endOfChunk, equals(chunkSize));
+
+ expect(folded(chunks.last.byteArrays),
+ equals(bytes.sublist(chunkSize)));
+ expect(chunks.last.offset, equals(chunkSize));
+ expect(chunks.last.length, equals(bytes.length - chunkSize));
+ expect(chunks.last.endOfChunk, equals(bytes.length));
+ });
+ });
+
+ test('media', () {
+ // Tests for [MediaRange]
+ var partialRange = new ByteRange(1, 100);
+ expect(partialRange.start, equals(1));
+ expect(partialRange.end, equals(100));
+
+ var fullRange = new ByteRange(0, -1);
+ expect(fullRange.start, equals(0));
+ expect(fullRange.end, equals(-1));
+
+ expect(() => new ByteRange(0, 0), throws);
+ expect(() => new ByteRange(-1, 0), throws);
+ expect(() => new ByteRange(-1, 1), throws);
+
+ // Tests for [DownloadOptions]
+ expect(DownloadOptions.Metadata.isMetadataDownload, isTrue);
+
+ expect(DownloadOptions.FullMedia.isFullDownload, isTrue);
+ expect(DownloadOptions.FullMedia.isMetadataDownload, isFalse);
+
+ // Tests for [Media]
+ var stream = new StreamController().stream;
+ expect(() => new Media(null, 0, contentType: 'foobar'),
+ throwsA(isArgumentError));
+ expect(() => new Media(stream, 0, contentType: null),
+ throwsA(isArgumentError));
+ expect(() => new Media(stream, -1, contentType: 'foobar'),
+ throwsA(isArgumentError));
+
+ var lengthUnknownMedia = new Media(stream, null);
+ expect(lengthUnknownMedia.stream, equals(stream));
+ expect(lengthUnknownMedia.length, equals(null));
+
+ var media = new Media(stream, 10, contentType: 'foobar');
+ expect(media.stream, equals(stream));
+ expect(media.length, equals(10));
+ expect(media.contentType, equals('foobar'));
+
+ // Tests for [ResumableUploadOptions]
+ expect(() => new ResumableUploadOptions(numberOfAttempts: 0),
+ throwsA(isArgumentError));
+ expect(() => new ResumableUploadOptions(chunkSize: 1),
+ throwsA(isArgumentError));
+ });
+
+ group('api-requester', () {
+ var httpMock, rootUrl, basePath;
+ ApiRequester requester;
+
+ var responseHeaders = {
+ 'content-type' : 'application/json; charset=utf-8',
+ };
+
+ setUp(() {
+ httpMock = new HttpServerMock();
+ rootUrl = 'http://example.com/';
+ basePath = '/base/';
+ requester = new ApiRequester(httpMock, rootUrl, basePath);
+ });
+
+
+ // Tests for Request, Response
+
+ group('metadata-request-response', () {
+ test('empty-request-empty-response', () {
+ httpMock.register(expectAsync((http.BaseRequest request, json) {
+ expect(request.method, equals('GET'));
+ expect('${request.url}',
+ equals('http://example.com/base/abc?alt=json'));
+ return stringResponse(200, responseHeaders, '');
+ }), true);
+ requester.request('abc', 'GET').then(expectAsync((response) {
+ expect(response, isNull);
+ }));
+ });
+
+ test('json-map-request-json-map-response', () {
+ httpMock.register(expectAsync((http.BaseRequest request, json) {
+ expect(request.method, equals('GET'));
+ expect('${request.url}',
+ equals('http://example.com/base/abc?alt=json'));
+ expect(json is Map, isTrue);
+ expect(json, hasLength(1));
+ expect(json['foo'], equals('bar'));
+ return stringResponse(200, responseHeaders, '{"foo2" : "bar2"}');
+ }), true);
+ requester.request('abc',
+ 'GET',
+ body: JSON.encode({'foo' : 'bar'})).then(
+ expectAsync((response) {
+ expect(response is Map, isTrue);
+ expect(response, hasLength(1));
+ expect(response['foo2'], equals('bar2'));
+ }));
+ });
+
+ test('json-list-request-json-list-response', () {
+ httpMock.register(expectAsync((http.BaseRequest request, json) {
+ expect(request.method, equals('GET'));
+ expect('${request.url}',
+ equals('http://example.com/base/abc?alt=json'));
+ expect(json is List, isTrue);
+ expect(json, hasLength(2));
+ expect(json[0], equals('a'));
+ expect(json[1], equals(1));
+ return stringResponse(200, responseHeaders, '["b", 2]');
+ }), true);
+ requester.request('abc',
+ 'GET',
+ body: JSON.encode(['a', 1])).then(
+ expectAsync((response) {
+ expect(response is List, isTrue);
+ expect(response[0], equals('b'));
+ expect(response[1], equals(2));
+ }));
+ });
+ });
+
+ group('media-download', () {
+ test('media-download', () {
+ var data256 = new List.generate(256, (i) => i);
+ httpMock.register(expectAsync((http.BaseRequest request, data) {
+ expect(request.method, equals('GET'));
+ expect('${request.url}',
+ equals('http://example.com/base/abc?alt=media'));
+ expect(data, isEmpty);
+ var headers = {
+ 'content-length' : '${data256.length}',
+ 'content-type' : 'foobar',
+ };
+ return binaryResponse(200, headers, data256);
+ }), false);
+ requester.request('abc',
+ 'GET',
+ body: '',
+ downloadOptions: DownloadOptions.FullMedia).then(
+ expectAsync((Media media) {
+ expect(media.contentType, equals('foobar'));
+ expect(media.length, equals(data256.length));
+ media.stream.fold([], (b, d) => b..addAll(d)).then(expectAsync((d) {
+ expect(d, equals(data256));
+ }));
+ }));
+ });
+
+ test('media-download-partial', () {
+ var data256 = new List.generate(256, (i) => i);
+ var data64 = data256.sublist(128, 128 + 64);
+
+ httpMock.register(expectAsync((http.BaseRequest request, data) {
+ expect(request.method, equals('GET'));
+ expect('${request.url}',
+ equals('http://example.com/base/abc?alt=media'));
+ expect(data, isEmpty);
+ expect(request.headers['range'],
+ equals('bytes=128-191'));
+ var headers = {
+ 'content-length' : '${data64.length}',
+ 'content-type' : 'foobar',
+ 'content-range' : 'bytes 128-191/256',
+ };
+ return binaryResponse(200, headers, data64);
+ }), false);
+ var range = new ByteRange(128, 128 + 64 - 1);
+ var options = new PartialDownloadOptions(range);
+ requester.request('abc',
+ 'GET',
+ body: '',
+ downloadOptions: options).then(
+ expectAsync((Media media) {
+ expect(media.contentType, equals('foobar'));
+ expect(media.length, equals(data64.length));
+ media.stream.fold([], (b, d) => b..addAll(d)).then(expectAsync((d) {
+ expect(d, equals(data64));
+ }));
+ }));
+ });
+
+ test('json-upload-media-download', () {
+ var data256 = new List.generate(256, (i) => i);
+ httpMock.register(expectAsync((http.BaseRequest request, json) {
+ expect(request.method, equals('GET'));
+ expect('${request.url}',
+ equals('http://example.com/base/abc?alt=media'));
+ expect(json is List, isTrue);
+ expect(json, hasLength(2));
+ expect(json[0], equals('a'));
+ expect(json[1], equals(1));
+
+ var headers = {
+ 'content-length' : '${data256.length}',
+ 'content-type' : 'foobar',
+ };
+ return binaryResponse(200, headers, data256);
+ }), true);
+ requester.request('abc',
+ 'GET',
+ body: JSON.encode(['a', 1]),
+ downloadOptions: DownloadOptions.FullMedia).then(
+ expectAsync((Media media) {
+ expect(media.contentType, equals('foobar'));
+ expect(media.length, equals(data256.length));
+ media.stream.fold([], (b, d) => b..addAll(d)).then(expectAsync((d) {
+ expect(d, equals(data256));
+ }));
+ }));
+ });
+ });
+
+ // Tests for media uploads
+
+ group('media-upload', () {
+ Stream streamFromByteArrays(byteArrays) {
+ var controller = new StreamController();
+ for (var array in byteArrays) {
+ controller.add(array);
+ }
+ controller.close();
+ return controller.stream;
+ }
+ Media mediaFromByteArrays(byteArrays, {bool withLen: true}) {
+ int len = 0;
+ byteArrays.forEach((array) { len += array.length; });
+ if (!withLen) len = null;
+ return new Media(streamFromByteArrays(byteArrays),
+ len,
+ contentType: 'foobar');
+ }
+ validateServerRequest(e, http.BaseRequest request, List<int> data) {
+ return new Future.sync(() {
+ var h = e['headers'];
+ var r = e['response'];
+
+ expect(request.url.toString(), equals(e['url']));
+ expect(request.method, equals(e['method']));
+ h.forEach((k, v) {
+ expect(request.headers[k], equals(v));
+ });
+
+ expect(data, equals(e['data']));
+ return r;
+ });
+ }
+ serverRequestValidator(List expectations) {
+ int i = 0;
+ return (http.BaseRequest request, List<int> data) {
+ return validateServerRequest(expectations[i++], request, data);
+ };
+ }
+
+ test('simple', () {
+ var bytes = new List.generate(10 * 256 * 1024 + 1, (i) => i % 256);
+ var expectations = [
+ {
+ 'url' : 'http://example.com/xyz?uploadType=media&alt=json',
+ 'method' : 'POST',
+ 'data' : bytes,
+ 'headers' : {
+ 'content-length' : '${bytes.length}',
+ 'content-type' : 'foobar',
+ },
+ 'response' : stringResponse(200, responseHeaders, '')
+ },
+ ];
+
+ httpMock.register(
+ expectAsync(serverRequestValidator(expectations)), false);
+ var media = mediaFromByteArrays([bytes]);
+ requester.request('/xyz',
+ 'POST',
+ uploadMedia: media).then(
+ expectAsync((response) {}));
+ });
+
+ test('multipart-upload', () {
+ var bytes = new List.generate(10 * 256 * 1024 + 1, (i) => i % 256);
+ var contentBytes =
+ '--314159265358979323846\r\n'
+ 'Content-Type: $CONTENT_TYPE_JSON_UTF8\r\n\r\n'
+ 'BODY'
+ '\r\n--314159265358979323846\r\n'
+ 'Content-Type: foobar\r\n'
+ 'Content-Transfer-Encoding: base64\r\n\r\n'
+ '${crypto.CryptoUtils.bytesToBase64(bytes)}'
+ '\r\n--314159265358979323846--';
+
+ var expectations = [
+ {
+ 'url' : 'http://example.com/xyz?uploadType=multipart&alt=json',
+ 'method' : 'POST',
+ 'data' : UTF8.encode('$contentBytes'),
+ 'headers' : {
+ 'content-length' : '${contentBytes.length}',
+ 'content-type' :
+ 'multipart/related; boundary="314159265358979323846"',
+ },
+ 'response' : stringResponse(200, responseHeaders, '')
+ },
+ ];
+
+ httpMock.register(
+ expectAsync(serverRequestValidator(expectations)), false);
+ var media = mediaFromByteArrays([bytes]);
+ requester.request('/xyz',
+ 'POST',
+ body: 'BODY',
+ uploadMedia: media).then(
+ expectAsync((response) {}));
+ });
+
+ group('resumable-upload', () {
+ // TODO: respect [stream]
+ buildExpectations(List<int> bytes, int chunkSize, bool stream,
+ {int numberOfServerErrors: 0}) {
+ int totalLength = bytes.length;
+ int numberOfChunks = totalLength ~/ chunkSize;
+ int numberOfBytesInLastChunk = totalLength % chunkSize;
+
+ if (numberOfBytesInLastChunk > 0) {
+ numberOfChunks++;
+ } else {
+ numberOfBytesInLastChunk = chunkSize;
+ }
+
+ var expectations = [];
+
+ // First request is making a POST and gets the upload URL.
+ expectations.add({
+ 'url' : 'http://example.com/xyz?uploadType=resumable&alt=json',
+ 'method' : 'POST',
+ 'data' : [],
+ 'headers' : {
+ 'content-length' : '0',
+ 'content-type' : 'application/json; charset=utf-8',
+ 'x-upload-content-type' : 'foobar',
+ }..addAll(stream ? {} : {
+ 'x-upload-content-length' : '$totalLength',
+ }),
+ 'response' : stringResponse(
+ 200, {'location' : 'http://upload.com/'}, '')
+ });
+
+ var lastEnd = 0;
+ for (int i = 0; i < numberOfChunks; i++) {
+ bool isLast = i == (numberOfChunks - 1);
+ var lengthMarker = stream && !isLast ? '*' : '$totalLength';
+
+ int bytesToExpect = chunkSize;
+ if (isLast) {
+ bytesToExpect = numberOfBytesInLastChunk;
+ }
+
+ var start = i * chunkSize;
+ var end = start + bytesToExpect;
+ var sublist = bytes.sublist(start, end);
+
+ var firstContentRange =
+ 'bytes $start-${end-1}/$lengthMarker';
+ var firstRange =
+ 'bytes=0-${end-1}';
+
+ // We issue [numberOfServerErrors] 503 errors first, and then a
+ // successfull response.
+ for (var j = 0; j < (numberOfServerErrors + 1); j++) {
+ bool successfullResponse = j == numberOfServerErrors;
+
+ var response;
+ if (successfullResponse) {
+ var headers = isLast
+ ? { 'content-type' : 'application/json; charset=utf-8' }
+ : {'range' : firstRange };
+ response = stringResponse(isLast ? 200 : 308, headers, '');
+ } else {
+ var headers = {};
+ response = stringResponse(503, headers, '');
+ }
+
+ expectations.add({
+ 'url' : 'http://upload.com/',
+ 'method' : 'PUT',
+ 'data' : sublist,
+ 'headers' : {
+ 'content-length' : '${sublist.length}',
+ 'content-range' : firstContentRange,
+ 'content-type' : 'foobar',
+ },
+ 'response' : response,
+ });
+ }
+ }
+ return expectations;
+ }
+
+ List<List<int>> makeParts(List<int> bytes, List<int> splits) {
+ var parts = [];
+ int lastEnd = 0;
+ for (int i = 0; i < splits.length; i++) {
+ parts.add(bytes.sublist(lastEnd, splits[i]));
+ lastEnd = splits[i];
+ }
+ return parts;
+ }
+
+ runTest(int chunkSizeInBlocks, int length, List splits, bool stream,
+ {int numberOfServerErrors: 0, resumableOptions,
+ int expectedErrorStatus, int messagesNrOfFailure}) {
+ int chunkSize = chunkSizeInBlocks * 256 * 1024;
+
+ int i = 0;
+ var bytes = new List.generate(length, (i) => i % 256);
+ var parts = makeParts(bytes, splits);
+
+ // Simulation of our server
+ var expectations = buildExpectations(
+ bytes, chunkSize, false,
+ numberOfServerErrors: numberOfServerErrors);
+ // If the server simulates 50X errors and the client resumes only
+ // a limited amount of time, we'll trunkate the number of requests
+ // the server expects.
+ // [The client will give up and if the server expects more, the test
+ // would timeout.]
+ if (expectedErrorStatus != null) {
+ expectations = expectations.sublist(0, messagesNrOfFailure);
+ }
+ httpMock.register(
+ expectAsync(serverRequestValidator(expectations),
+ count: expectations.length),
+ false);
+
+ // Our client
+ var media = mediaFromByteArrays(parts);
+ if (resumableOptions == null) {
+ resumableOptions =
+ new ResumableUploadOptions(chunkSize: chunkSize);
+ }
+ var result = requester.request('/xyz',
+ 'POST',
+ uploadMedia: media,
+ uploadOptions: resumableOptions);
+ if (expectedErrorStatus != null) {
+ result.catchError(expectAsync((error) {
+ expect(error is DetailedApiRequestError, isTrue);
+ expect(error.status, equals(expectedErrorStatus));
+ }));
+ } else {
+ result.then(expectAsync((_) {}));
+ }
+ }
+
+ Function backoffWrapper(int callCount) {
+ return expectAsync((int failedAttempts) {
+ var exp = ResumableUploadOptions.ExponentialBackoff;
+ Duration duration = exp(failedAttempts);
+ expect(duration.inSeconds, equals(1 << (failedAttempts - 1)));
+ return const Duration(milliseconds: 1);
+ }, count: callCount);
+ }
+
+ test('length-small-block', () {
+ runTest(1, 10, [10], false);
+ });
+
+ test('length-small-block-parts', () {
+ runTest(1, 20, [1, 2, 3, 4, 5, 6, 7, 19, 20], false);
+ });
+
+ test('length-big-block', () {
+ runTest(1, 1024 * 1024, [1024*1024], false);
+ });
+
+ test('length-big-block-parts', () {
+ runTest(1, 1024 * 1024,
+ [1,
+ 256*1024-1,
+ 256*1024,
+ 256*1024+1,
+ 1024*1024-1,
+ 1024*1024], false);
+ });
+
+ test('stream-small-block', () {
+ runTest(1, 10, [10], true);
+ });
+
+ test('stream-small-block-parts', () {
+ runTest(1, 20, [1, 2, 3, 4, 5, 6, 7, 19, 20], true);
+ });
+
+ test('stream-big-block', () {
+ runTest(1, 1024 * 1024, [1024*1024], true);
+ });
+
+ test('stream-big-block-parts', () {
+ runTest(1, 1024 * 1024,
+ [1,
+ 256*1024-1,
+ 256*1024,
+ 256*1024+1,
+ 1024*1024-1,
+ 1024*1024], true);
+ });
+
+ test('stream-big-block-parts--with-server-error-recovery', () {
+ var numFailedAttempts = 4 * 3;
+ var options = new ResumableUploadOptions(
+ chunkSize: 256 * 1024, numberOfAttempts: 4,
+ backoffFunction: backoffWrapper(numFailedAttempts));
+ runTest(1, 1024 * 1024,
+ [1,
+ 256*1024-1,
+ 256*1024,
+ 256*1024+1,
+ 1024*1024-1,
+ 1024*1024],
+ true,
+ numberOfServerErrors: 3,
+ resumableOptions: options);
+ });
+
+ test('stream-big-block-parts--server-error', () {
+ var numFailedAttempts = 2;
+ var options = new ResumableUploadOptions(
+ chunkSize: 256 * 1024, numberOfAttempts: 3,
+ backoffFunction: backoffWrapper(numFailedAttempts));
+ runTest(1, 1024 * 1024,
+ [1,
+ 256*1024-1,
+ 256*1024,
+ 256*1024+1,
+ 1024*1024-1,
+ 1024*1024],
+ true,
+ numberOfServerErrors: 3,
+ resumableOptions: options,
+ expectedErrorStatus: 503,
+ messagesNrOfFailure: 4);
+ });
+ });
+ });
+
+ // Tests for error responses
+ group('request-errors', () {
+ makeTestError() {
+ // All errors from the [http.Client] propagate through.
+ // We use [TestError] to simulate it.
+ httpMock.register(expectAsync((http.BaseRequest request, string) {
+ return new Future.error(new TestError());
+ }), false);
+ }
+
+ makeDetailed400Error() {
+ httpMock.register(expectAsync((http.BaseRequest request, string) {
+ return stringResponse(400,
+ responseHeaders,
+ '{"error" : {"code" : 42, "message": "foo"}}');
+ }), false);
+ }
+
+ makeNormal199Error() {
+ httpMock.register(expectAsync((http.BaseRequest request, string) {
+ return stringResponse(199, {}, '');
+ }), false);
+ }
+
+ makeInvalidContentTypeError() {
+ httpMock.register(expectAsync((http.BaseRequest request, string) {
+ var responseHeaders = { 'content-type' : 'image/png'};
+ return stringResponse(200, responseHeaders, '');
+ }), false);
+ }
+
+
+ test('normal-http-client', () {
+ makeTestError();
+ expect(requester.request('abc', 'GET'), throwsA(isTestError));
+ });
+
+ test('normal-detailed-400', () {
+ makeDetailed400Error();
+ requester.request('abc', 'GET')
+ .catchError(expectAsync((error, stack) {
+ expect(error, isDetailedApiRequestError);
+ DetailedApiRequestError e = error;
+ expect(e.status, equals(42));
+ expect(e.message, equals('foo'));
+ }));
+ });
+
+ test('normal-199', () {
+ makeNormal199Error();
+ expect(requester.request('abc', 'GET'), throwsA(isApiRequestError));
+ });
+
+ test('normal-invalid-content-type', () {
+ makeInvalidContentTypeError();
+ expect(requester.request('abc', 'GET'), throwsA(isApiRequestError));
+ });
+
+ var options = DownloadOptions.FullMedia;
+ test('media-http-client', () {
+ makeTestError();
+ expect(requester.request('abc', 'GET', downloadOptions: options),
+ throwsA(isTestError));
+ });
+
+ test('media-detailed-400', () {
+ makeDetailed400Error();
+ requester.request('abc', 'GET')
+ .catchError(expectAsync((error, stack) {
+ expect(error, isDetailedApiRequestError);
+ DetailedApiRequestError e = error;
+ expect(e.status, equals(42));
+ expect(e.message, equals('foo'));
+ }));
+ });
+
+ test('media-199', () {
+ makeNormal199Error();
+ expect(requester.request('abc', 'GET', downloadOptions: options),
+ throwsA(isApiRequestError));
+ });
+ });
+
+
+ // Tests for path/query parameters
+
+ test('request-parameters-query', () {
+ var queryParams = {
+ 'a' : ['a1', 'a2'],
+ 's' : ['s1']
+ };
+ httpMock.register(expectAsync((http.BaseRequest request, json) {
+ expect(request.method, equals('GET'));
+ expect('${request.url}',
+ equals('http://example.com/base/abc?a=a1&a=a2&s=s1&alt=json'));
+ return stringResponse(200, responseHeaders, '');
+ }), true);
+ requester.request('abc', 'GET', queryParams: queryParams)
+ .then(expectAsync((response) {
+ expect(response, isNull);
+ }));
+ });
+
+ test('request-parameters-path', () {
+ httpMock.register(expectAsync((http.BaseRequest request, json) {
+ expect(request.method, equals('GET'));
+ expect('${request.url}', equals(
+ 'http://example.com/base/s/foo/a1/a2/bar/s1/e?alt=json'));
+ return stringResponse(200, responseHeaders, '');
+ }), true);
+ requester.request('s/foo/a1/a2/bar/s1/e', 'GET')
+ .then(expectAsync((response) {
+ expect(response, isNull);
+ }));
+ });
+ });
+ });
+}

Powered by Google App Engine
This is Rietveld 408576698