| 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
|
| deleted file mode 100644
|
| index 54fd30998d9de4aab9fe371915492b240986c064..0000000000000000000000000000000000000000
|
| --- a/generated/googleapis/test/common/common_internal_test.dart
|
| +++ /dev/null
|
| @@ -1,923 +0,0 @@
|
| -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('length-big-block-parts-non-divisible', () {
|
| - runTest(1, 1024 * 1024 + 1,
|
| - [1,
|
| - 256*1024-1,
|
| - 256*1024,
|
| - 256*1024+1,
|
| - 1024*1024-1,
|
| - 1024*1024,
|
| - 1024*1024+1], 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);
|
| - }));
|
| - });
|
| - });
|
| - });
|
| -}
|
|
|