| 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);
 | 
| -        }));
 | 
| -      });
 | 
| -    });
 | 
| -  });
 | 
| -}
 | 
| 
 |