| Index: pkg/gcloud/test/storage/storage_test.dart
|
| diff --git a/pkg/gcloud/test/storage/storage_test.dart b/pkg/gcloud/test/storage/storage_test.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..5d5068ac343d9cd9b1ee09ca9051cacfa33070c9
|
| --- /dev/null
|
| +++ b/pkg/gcloud/test/storage/storage_test.dart
|
| @@ -0,0 +1,1042 @@
|
| +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +library gcloud.storage;
|
| +
|
| +import 'dart:async';
|
| +import 'dart:convert';
|
| +
|
| +import 'package:http/http.dart' as http;
|
| +import 'package:unittest/unittest.dart';
|
| +
|
| +import 'package:gcloud/storage.dart';
|
| +
|
| +import 'package:googleapis/storage/v1.dart' as storage;
|
| +import 'package:googleapis/common/common.dart' as common;
|
| +
|
| +import '../common.dart';
|
| +import '../common_e2e.dart';
|
| +
|
| +
|
| +const String ROOT_PATH = '/storage/v1/';
|
| +
|
| +
|
| +http.Client mockClient() => new MockClient(ROOT_PATH);
|
| +
|
| +withMockClient(function) {
|
| + var mock = mockClient();
|
| + function(mock, new Storage(mock, PROJECT));
|
| +}
|
| +
|
| +main() {
|
| + group('bucket', () {
|
| + var bucketName = 'test-bucket';
|
| + var absoluteName = 'gs://test-bucket';
|
| +
|
| + test('create', () {
|
| + withMockClient((mock, api) {
|
| + mock.register('POST', 'b', expectAsync((request) {
|
| + var requestBucket =
|
| + new storage.Bucket.fromJson(JSON.decode(request.body));
|
| + expect(requestBucket.name, bucketName);
|
| + return mock.respond(new storage.Bucket()..name = bucketName);
|
| + }));
|
| +
|
| + expect(api.createBucket(bucketName), completion(isNull));
|
| + });
|
| + });
|
| +
|
| + test('create-with-predefined-acl', () {
|
| + var predefined =
|
| + [[PredefinedAcl.authenticatedRead, 'authenticatedRead'],
|
| + [PredefinedAcl.private, 'private'],
|
| + [PredefinedAcl.projectPrivate, 'projectPrivate'],
|
| + [PredefinedAcl.publicRead, 'publicRead'],
|
| + [PredefinedAcl.publicReadWrite, 'publicReadWrite']];
|
| +
|
| + withMockClient((mock, api) {
|
| + int count = 0;
|
| +
|
| + mock.register('POST', 'b', expectAsync((request) {
|
| + var requestBucket =
|
| + new storage.Bucket.fromJson(JSON.decode(request.body));
|
| + expect(requestBucket.name, bucketName);
|
| + expect(requestBucket.acl, isNull);
|
| + expect(request.url.queryParameters['predefinedAcl'],
|
| + predefined[count++][1]);
|
| + return mock.respond(new storage.Bucket()..name = bucketName);
|
| + }, count: predefined.length));
|
| +
|
| + var futures = [];
|
| + for (int i = 0; i < predefined.length; i++) {
|
| + futures.add(api.createBucket(bucketName,
|
| + predefinedAcl: predefined[i][0]));
|
| + }
|
| + return Future.wait(futures);
|
| + });
|
| + });
|
| +
|
| + test('create-with-acl', () {
|
| + var acl1 = new Acl([
|
| + new AclEntry(new AccountScope('user@example.com'),
|
| + AclPermission.FULL_CONTROL),
|
| + ]);
|
| + var acl2 = new Acl([
|
| + new AclEntry(new AccountScope('user@example.com'),
|
| + AclPermission.FULL_CONTROL),
|
| + new AclEntry(new GroupScope('group@example.com'),
|
| + AclPermission.WRITE),
|
| + ]);
|
| + var acl3 = new Acl([
|
| + new AclEntry(new AccountScope('user@example.com'),
|
| + AclPermission.FULL_CONTROL),
|
| + new AclEntry(new GroupScope('group@example.com'),
|
| + AclPermission.WRITE),
|
| + new AclEntry(new DomainScope('example.com'),
|
| + AclPermission.READ),
|
| + ]);
|
| +
|
| + var acls = [acl1, acl2, acl3];
|
| +
|
| + withMockClient((mock, api) {
|
| + int count = 0;
|
| +
|
| + mock.register('POST', 'b', expectAsync((request) {
|
| + var requestBucket =
|
| + new storage.Bucket.fromJson(JSON.decode(request.body));
|
| + expect(requestBucket.name, bucketName);
|
| + expect(request.url.queryParameters['predefinedAcl'], isNull);
|
| + expect(requestBucket.acl, isNotNull);
|
| + expect(requestBucket.acl.length, count + 1);
|
| + expect(requestBucket.acl[0].entity, 'user-user@example.com');
|
| + expect(requestBucket.acl[0].role, 'OWNER');
|
| + if (count > 0) {
|
| + expect(requestBucket.acl[1].entity, 'group-group@example.com');
|
| + expect(requestBucket.acl[1].role, 'WRITER');
|
| + }
|
| + if (count > 2) {
|
| + expect(requestBucket.acl[2].entity, 'domain-example.com');
|
| + expect(requestBucket.acl[2].role, 'READER');
|
| + }
|
| + count++;
|
| + return mock.respond(new storage.Bucket()..name = bucketName);
|
| + }, count: acls.length));
|
| +
|
| + var futures = [];
|
| + for (int i = 0; i < acls.length; i++) {
|
| + futures.add(api.createBucket(bucketName, acl: acls[i]));
|
| + }
|
| + return Future.wait(futures);
|
| + });
|
| + });
|
| +
|
| + test('create-with-acl-and-predefined-acl', () {
|
| + var predefined =
|
| + [[PredefinedAcl.authenticatedRead, 'authenticatedRead'],
|
| + [PredefinedAcl.private, 'private'],
|
| + [PredefinedAcl.projectPrivate, 'projectPrivate'],
|
| + [PredefinedAcl.publicRead, 'publicRead'],
|
| + [PredefinedAcl.publicReadWrite, 'publicReadWrite']];
|
| +
|
| + var acl1 = new Acl([
|
| + new AclEntry(new AccountScope('user@example.com'),
|
| + AclPermission.FULL_CONTROL),
|
| + ]);
|
| + var acl2 = new Acl([
|
| + new AclEntry(new AccountScope('user@example.com'),
|
| + AclPermission.FULL_CONTROL),
|
| + new AclEntry(new GroupScope('group@example.com'),
|
| + AclPermission.WRITE),
|
| + ]);
|
| + var acl3 = new Acl([
|
| + new AclEntry(new AccountScope('user@example.com'),
|
| + AclPermission.FULL_CONTROL),
|
| + new AclEntry(new GroupScope('group@example.com'),
|
| + AclPermission.WRITE),
|
| + new AclEntry(new DomainScope('example.com'),
|
| + AclPermission.READ),
|
| + ]);
|
| +
|
| + var acls = [acl1, acl2, acl3];
|
| +
|
| + withMockClient((mock, api) {
|
| + int count = 0;
|
| +
|
| + mock.register('POST', 'b', expectAsync((request) {
|
| + var requestBucket =
|
| + new storage.Bucket.fromJson(JSON.decode(request.body));
|
| + int predefinedIndex = count ~/ acls.length;
|
| + int aclIndex = count % acls.length;
|
| + expect(requestBucket.name, bucketName);
|
| + expect(request.url.queryParameters['predefinedAcl'],
|
| + predefined[predefinedIndex][1]);
|
| + expect(requestBucket.acl, isNotNull);
|
| + expect(requestBucket.acl.length, aclIndex + 1);
|
| + expect(requestBucket.acl[0].entity, 'user-user@example.com');
|
| + expect(requestBucket.acl[0].role, 'OWNER');
|
| + if (aclIndex > 0) {
|
| + expect(requestBucket.acl[1].entity, 'group-group@example.com');
|
| + expect(requestBucket.acl[1].role, 'WRITER');
|
| + }
|
| + if (aclIndex > 2) {
|
| + expect(requestBucket.acl[2].entity, 'domain-example.com');
|
| + expect(requestBucket.acl[2].role, 'READER');
|
| + }
|
| + count++;
|
| + return mock.respond(new storage.Bucket()..name = bucketName);
|
| + }, count: predefined.length * acls.length));
|
| +
|
| + var futures = [];
|
| + for (int i = 0; i < predefined.length; i++) {
|
| + for (int j = 0; j < acls.length; j++) {
|
| + futures.add(api.createBucket(
|
| + bucketName, predefinedAcl: predefined[i][0], acl: acls[j]));
|
| + }
|
| + }
|
| + return Future.wait(futures);
|
| + });
|
| + });
|
| +
|
| + test('delete', () {
|
| + withMockClient((mock, api) {
|
| + mock.register(
|
| + 'DELETE', new RegExp(r'b/[a-z/-]*$'), expectAsync((request) {
|
| + expect(request.url.path, '${ROOT_PATH}b/$bucketName');
|
| + expect(request.body.length, 0);
|
| + return mock.respond(new storage.Bucket()..name = bucketName);
|
| + }));
|
| +
|
| + expect(api.deleteBucket(bucketName), completion(isNull));
|
| + });
|
| + });
|
| +
|
| + test('exists', () {
|
| + var exists = true;
|
| +
|
| + withMockClient((mock, api) {
|
| + mock.register(
|
| + 'GET', new RegExp(r'b/[a-z/-]*$'), expectAsync((request) {
|
| + expect(request.url.path, '${ROOT_PATH}b/$bucketName');
|
| + expect(request.body.length, 0);
|
| + if (exists) {
|
| + return mock.respond(new storage.Bucket()..name = bucketName);
|
| + } else {
|
| + return mock.respondError(404);
|
| + }
|
| + }, count: 2));
|
| +
|
| + return api.bucketExists(bucketName).then(expectAsync((result) {
|
| + expect(result, isTrue);
|
| + exists = false;
|
| + expect(api.bucketExists(bucketName), completion(isFalse));
|
| + }));
|
| + });
|
| + });
|
| +
|
| + test('stat', () {
|
| + withMockClient((mock, api) {
|
| + mock.register(
|
| + 'GET', new RegExp(r'b/[a-z/-]*$'), expectAsync((request) {
|
| + expect(request.url.path, '${ROOT_PATH}b/$bucketName');
|
| + expect(request.body.length, 0);
|
| + return mock.respond(new storage.Bucket()
|
| + ..name = bucketName
|
| + ..timeCreated = new DateTime(2014));
|
| + }));
|
| +
|
| + return api.bucketInfo(bucketName).then(expectAsync((result) {
|
| + expect(result.bucketName, bucketName);
|
| + expect(result.created, new DateTime(2014));
|
| + }));
|
| + });
|
| + });
|
| +
|
| + group('list', () {
|
| + test('empty', () {
|
| + withMockClient((mock, api) {
|
| + mock.register('GET', 'b', expectAsync((request) {
|
| + expect(request.body.length, 0);
|
| + return mock.respond(new storage.Buckets());
|
| + }));
|
| +
|
| + api.listBucketNames().listen(
|
| + (_) => throw 'Unexpected',
|
| + onDone: expectAsync(() => null));
|
| + });
|
| + });
|
| +
|
| + test('immediate-cancel', () {
|
| + withMockClient((mock, api) {
|
| + api.listBucketNames().listen(
|
| + (_) => throw 'Unexpected',
|
| + onDone: () => throw 'Unexpected')
|
| + ..cancel();
|
| + });
|
| + });
|
| +
|
| + test('list', () {
|
| + // TODO: Test list.
|
| + });
|
| +
|
| + test('page', () {
|
| + // TODO: Test page.
|
| + });
|
| + });
|
| +
|
| + test('copy', () {
|
| + withMockClient((mock, api) {
|
| + mock.register(
|
| + 'POST',
|
| + 'b/srcBucket/o/srcObject/copyTo/b/destBucket/o/destObject',
|
| + expectAsync((request) {
|
| + return mock.respond(new storage.Object()..name = 'destObject');
|
| + }));
|
| + expect(api.copyObject('gs://srcBucket/srcObject',
|
| + 'gs://destBucket/destObject'),
|
| + completion(isNull));
|
| + });
|
| + });
|
| +
|
| + test('copy-invalid-args', () {
|
| + withMockClient((mock, api) {
|
| + expect(() => api.copyObject('a', 'b'), throwsA(isFormatException));
|
| + expect(() => api.copyObject('a/b', 'c/d'), throwsA(isFormatException));
|
| + expect(() => api.copyObject('gs://a/b', 'gs://c/'),
|
| + throwsA(isFormatException));
|
| + expect(() => api.copyObject('gs://a/b', 'gs:///c'),
|
| + throwsA(isFormatException));
|
| + });
|
| + });
|
| + });
|
| +
|
| + group('object', () {
|
| + var bucketName = 'test-bucket';
|
| + var objectName = 'test-object';
|
| +
|
| + var bytesNormalUpload = [1, 2, 3];
|
| +
|
| + // Generate a list just above the limit when changing to resumable upload.
|
| + const int MB = 1024 * 1024;
|
| + const int maxNormalUpload = 1 * MB;
|
| + const int minResumableUpload = maxNormalUpload + 1;
|
| + var bytesResumableUpload =
|
| + new List.generate(minResumableUpload, (e) => e & 255);
|
| +
|
| + bool testArgumentError(e) => e is ArgumentError;
|
| + bool testApiError(e) => e is common.ApiRequestError;
|
| + bool testDetailedApiError(e) => e is common.DetailedApiRequestError;
|
| + Function expectStatus(status) => (e) => expect(e.status, status);
|
| + Function expectNotNull(status) => (o) => expect(o, isNotNull);
|
| +
|
| + expectNormalUpload(mock, data, objectName) {
|
| + var bytes = data.fold([], (p, e) => p..addAll(e));
|
| + mock.registerUpload(
|
| + 'POST', 'b/$bucketName/o', expectAsync((request) {
|
| + return mock.processNormalMediaUpload(request)
|
| + .then(expectAsync((mediaUpload) {
|
| + var object =
|
| + new storage.Object.fromJson(JSON.decode(mediaUpload.json));
|
| + expect(object.name, objectName);
|
| + expect(mediaUpload.bytes, bytes);
|
| + expect(mediaUpload.contentType, 'application/octet-stream');
|
| + return mock.respond(new storage.Object()..name = objectName);
|
| + }));
|
| + }));
|
| + }
|
| +
|
| + expectResumableUpload(mock, data, objectName) {
|
| + var bytes = data.fold([], (p, e) => p..addAll(e));
|
| + expect(bytes.length, bytesResumableUpload.length);
|
| + int count = 0;
|
| + mock.registerResumableUpload(
|
| + 'POST', 'b/$bucketName/o', expectAsync((request) {
|
| + var requestObject =
|
| + new storage.Object.fromJson(JSON.decode(request.body));
|
| + expect(requestObject.name, objectName);
|
| + return mock.respondInitiateResumableUpload(PROJECT);
|
| + }));
|
| + mock.registerResumableUpload(
|
| + 'PUT', 'b/$PROJECT/o', expectAsync((request) {
|
| + count++;
|
| + if (count == 1) {
|
| + expect(request.bodyBytes.length, MB);
|
| + return mock.respondContinueResumableUpload();
|
| + } else {
|
| + expect(request.bodyBytes.length, 1);
|
| + return mock.respond(new storage.Object()..name = objectName);
|
| + }
|
| + }, count: 2));
|
| + }
|
| +
|
| + checkResult(result) {
|
| + expect(result.name, objectName);
|
| + }
|
| +
|
| + Future pipeToSink(sink, List<List<int>> data) {
|
| + sink.done.then(expectAsync(checkResult));
|
| + sink.done.catchError((e) => throw 'Unexpected $e');
|
| + return new Stream.fromIterable(data)
|
| + .pipe(sink)
|
| + .then(expectAsync(checkResult))
|
| + .catchError((e) => throw 'Unexpected $e');
|
| + }
|
| +
|
| + Future addStreamToSink(sink, List<List<int>> data) {
|
| + sink.done.then(expectAsync(checkResult));
|
| + sink.done.catchError((e) => throw 'Unexpected $e');
|
| + return sink.addStream(new Stream.fromIterable(data))
|
| + .then((_) => sink.close())
|
| + .then(expectAsync(checkResult))
|
| + .catchError((e) => throw 'Unexpected $e');
|
| + }
|
| +
|
| + Future addToSink(sink, List<List<int>> data) {
|
| + sink.done.then(expectAsync(checkResult));
|
| + sink.done.catchError((e) => throw 'Unexpected $e');
|
| + data.forEach((bytes) => sink.add(bytes));
|
| + return sink.close()
|
| + .then(expectAsync(checkResult))
|
| + .catchError((e) => throw 'Unexpected $e');
|
| + }
|
| +
|
| + Future runTest(mock, api, data, length) {
|
| + var bucket = api.bucket(bucketName);
|
| +
|
| + Future upload(fn, sendLength) {
|
| + mock.clear();
|
| + if (length <= maxNormalUpload) {
|
| + expectNormalUpload(mock, data, objectName);
|
| + } else {
|
| + expectResumableUpload(mock, data, objectName);
|
| + }
|
| + var sink;
|
| + if (sendLength) {
|
| + sink = bucket.write(objectName, length: length);
|
| + } else {
|
| + sink = bucket.write(objectName);
|
| + }
|
| + return fn(sink, data);
|
| + }
|
| +
|
| + return upload(pipeToSink, true)
|
| + .then(expectAsync((_) => upload(pipeToSink, false)))
|
| + .then(expectAsync((_) => upload(addStreamToSink, true)))
|
| + .then(expectAsync((_) => upload(addStreamToSink, false)))
|
| + .then(expectAsync((_) => upload(addToSink, true)))
|
| + .then(expectAsync((_) => upload(addToSink, false)));
|
| + };
|
| +
|
| + test('write-short-1', () {
|
| + withMockClient((mock, api) {
|
| + runTest(mock, api, [bytesNormalUpload], bytesNormalUpload.length);
|
| + });
|
| + });
|
| +
|
| + test('write-short-2', () {
|
| + withMockClient((mock, api) {
|
| + runTest(mock,
|
| + api,
|
| + [bytesNormalUpload, bytesNormalUpload],
|
| + bytesNormalUpload.length * 2);
|
| + });
|
| + });
|
| +
|
| + test('write-long', () {
|
| + withMockClient((mock, api) {
|
| + runTest(mock, api, [bytesResumableUpload], bytesResumableUpload.length);
|
| + });
|
| + });
|
| +
|
| + test('write-short-error', () {
|
| + withMockClient((mock, api) {
|
| +
|
| + Future test(length) {
|
| + mock.clear();
|
| + mock.registerUpload(
|
| + 'POST', 'b/$bucketName/o', expectAsync((request) {
|
| + return mock.respondError(500);
|
| + }));
|
| +
|
| + var bucket = api.bucket(bucketName);
|
| + var sink = bucket.write(bucketName, length: length);
|
| + sink.done
|
| + .then((_) => throw 'Unexpected')
|
| + .catchError(expectAsync(expectNotNull),
|
| + test: testDetailedApiError);
|
| + sink.done
|
| + .catchError(expectAsync(expectNotNull),
|
| + test: testDetailedApiError);
|
| + return new Stream.fromIterable([bytesNormalUpload])
|
| + .pipe(sink)
|
| + .then((_) => throw 'Unexpected')
|
| + .catchError(expectAsync(expectNotNull),
|
| + test: testDetailedApiError);
|
| + }
|
| +
|
| + test(null) // Unknown length.
|
| + .then(expectAsync((_) => test(1)))
|
| + .then(expectAsync((_) => test(10)))
|
| + .then(expectAsync((_) => test(maxNormalUpload)));
|
| + });
|
| + });
|
| +
|
| + // TODO: Mock the resumable upload timeout.
|
| + test('write-long-error', () {
|
| + withMockClient((mock, api) {
|
| +
|
| + Future test(length) {
|
| + mock.clear();
|
| + mock.registerResumableUpload(
|
| + 'POST', 'b/$bucketName/o', expectAsync((request) {
|
| + return mock.respondInitiateResumableUpload(PROJECT);
|
| + }));
|
| + mock.registerResumableUpload(
|
| + 'PUT', 'b/$PROJECT/o', expectAsync((request) {
|
| + return mock.respondError(502);
|
| + }, count: 3)); // Default 3 retries in googleapis library.
|
| +
|
| +
|
| + var bucket = api.bucket(bucketName);
|
| + var sink = bucket.write(bucketName);
|
| + sink.done
|
| + .then((_) => throw 'Unexpected')
|
| + .catchError(expectAsync(expectNotNull),
|
| + test: testDetailedApiError);
|
| + return new Stream.fromIterable([bytesResumableUpload])
|
| + .pipe(sink)
|
| + .then((_) => throw 'Unexpected')
|
| + .catchError(expectAsync(expectNotNull),
|
| + test: testDetailedApiError);
|
| + }
|
| +
|
| + test(null) // Unknown length.
|
| + .then(expectAsync((_) => test(minResumableUpload)));
|
| + });
|
| + });
|
| +
|
| + test('write-long-wrong-length', () {
|
| + withMockClient((mock, api) {
|
| +
|
| + Future test(data, length) {
|
| + mock.clear();
|
| + mock.registerResumableUpload(
|
| + 'POST', 'b/$bucketName/o', expectAsync((request) {
|
| + return mock.respondInitiateResumableUpload(PROJECT);
|
| + }));
|
| + mock.registerResumableUpload(
|
| + 'PUT', 'b/$PROJECT/o', expectAsync((request) {
|
| + return mock.respondContinueResumableUpload();
|
| + })); // Default 3 retries in googleapis library.
|
| +
|
| + var bucket = api.bucket(bucketName);
|
| + var sink = bucket.write(bucketName, length: length);
|
| + sink.done
|
| + .then((_) => throw 'Unexpected')
|
| + .catchError(
|
| + expectAsync(expectNotNull),
|
| + test: (e) => e is String || e is common.ApiRequestError);
|
| + return new Stream.fromIterable(data)
|
| + .pipe(sink)
|
| + .then((_) => throw 'Unexpected')
|
| + .catchError(
|
| + expectAsync(expectNotNull),
|
| + test: (e) => e is String || e is common.ApiRequestError);
|
| + }
|
| +
|
| + test([bytesResumableUpload], bytesResumableUpload.length + 1)
|
| + .then(expectAsync((_) => test([bytesResumableUpload, [1, 2]],
|
| + bytesResumableUpload.length + 1)));
|
| + });
|
| + });
|
| +
|
| + test('write-add-error', () {
|
| + withMockClient((mock, api) {
|
| + var bucket = api.bucket(bucketName);
|
| + var controller = new StreamController(sync: true);
|
| + var sink = bucket.write(bucketName);
|
| + sink.done
|
| + .then((_) => throw 'Unexpected')
|
| + .catchError(expectAsync(expectNotNull), test: testArgumentError);
|
| + var stream = new Stream.fromIterable([[1, 2, 3]]);
|
| + sink.addStream(stream).then((_) {
|
| + sink.addError(new ArgumentError());
|
| + sink.close()
|
| + .catchError(expectAsync(expectNotNull), test: testArgumentError);
|
| + });
|
| + });
|
| + });
|
| +
|
| + test('write-long-add-error', () {
|
| + int count = 0;
|
| + withMockClient((mock, api) {
|
| + mock.registerResumableUpload(
|
| + 'POST', 'b/$bucketName/o', expectAsync((request) {
|
| + return mock.respondInitiateResumableUpload(PROJECT);
|
| + }));
|
| + // The resumable upload will buffer until either close or a full chunk,
|
| + // so when we add an error the last byte is never sent. Therefore this
|
| + // PUT is only called once.
|
| + mock.registerResumableUpload(
|
| + 'PUT', 'b/$PROJECT/o', expectAsync((request) {
|
| + expect(request.bodyBytes.length, 1024 * 1024);
|
| + return mock.respondContinueResumableUpload();
|
| + }));
|
| +
|
| + var bucket = api.bucket(bucketName);
|
| + var sink = bucket.write(bucketName);
|
| + sink.done
|
| + .then((_) => throw 'Unexpected')
|
| + .catchError(expectAsync(expectNotNull), test: testArgumentError);
|
| + var stream = new Stream.fromIterable([bytesResumableUpload]);
|
| + sink.addStream(stream).then((_) {
|
| + sink.addError(new ArgumentError());
|
| + sink.close()
|
| + .catchError(expectAsync(expectNotNull), test: testArgumentError);
|
| + });
|
| + });
|
| + });
|
| +
|
| + test('write-with-metadata-short', () {
|
| + var metadata =
|
| + [new ObjectMetadata(contentType: 'mime/type'),
|
| + new ObjectMetadata(contentType: 'type/mime',
|
| + cacheControl: 'control-cache'),
|
| + new ObjectMetadata(cacheControl: 'control-cache'),
|
| + new ObjectMetadata(cacheControl: 'control-cache',
|
| + contentDisposition: 'disp-content'),
|
| + new ObjectMetadata(contentDisposition: 'disp-content',
|
| + contentEncoding: 'encoding',
|
| + contentLanguage: 'language'),
|
| + new ObjectMetadata(custom: {'x': 'y'}),
|
| + new ObjectMetadata(custom: {'a': 'b', 'x': 'y'})
|
| + ];
|
| +
|
| + withMockClient((mock, api) {
|
| + int count = 0;
|
| + var bytes = [1, 2, 3];
|
| +
|
| + mock.registerUpload(
|
| + 'POST', 'b/$bucketName/o', expectAsync((request) {
|
| + return mock.processNormalMediaUpload(request)
|
| + .then(expectAsync((mediaUpload) {
|
| + var object =
|
| + new storage.Object.fromJson(JSON.decode(mediaUpload.json));
|
| + ObjectMetadata m = metadata[count];
|
| + expect(object.name, objectName);
|
| + expect(mediaUpload.bytes, bytes);
|
| + var contentType = m.contentType != null
|
| + ? m.contentType : 'application/octet-stream';
|
| + expect(mediaUpload.contentType, contentType);
|
| + expect(object.cacheControl, m.cacheControl);
|
| + expect(object.contentDisposition, m.contentDisposition);
|
| + expect(object.contentEncoding, m.contentEncoding);
|
| + expect(object.contentLanguage, m.contentLanguage);
|
| + expect(object.metadata, m.custom);
|
| + count++;
|
| + return mock.respond(new storage.Object()..name = objectName);
|
| + }));
|
| + }, count: metadata.length));
|
| +
|
| + var bucket = api.bucket(bucketName);
|
| + var futures = [];
|
| + for (int i = 0; i < metadata.length; i++) {
|
| + futures.add(bucket.writeBytes(objectName, bytes,
|
| + metadata: metadata[i]));
|
| + }
|
| + return Future.wait(futures);
|
| + });
|
| + });
|
| +
|
| + test('write-with-metadata-long', () {
|
| + var metadata =
|
| + [new ObjectMetadata(contentType: 'mime/type'),
|
| + new ObjectMetadata(contentType: 'type/mime',
|
| + cacheControl: 'control-cache'),
|
| + new ObjectMetadata(cacheControl: 'control-cache'),
|
| + new ObjectMetadata(cacheControl: 'control-cache',
|
| + contentDisposition: 'disp-content'),
|
| + new ObjectMetadata(contentDisposition: 'disp-content',
|
| + contentEncoding: 'encoding',
|
| + contentLanguage: 'language'),
|
| + new ObjectMetadata(custom: {'x': 'y'}),
|
| + new ObjectMetadata(custom: {'a': 'b', 'x': 'y'})
|
| + ];
|
| +
|
| + withMockClient((mock, api) {
|
| + int countInitial = 0;
|
| + int countData = 0;
|
| +
|
| + mock.registerResumableUpload(
|
| + 'POST', 'b/$bucketName/o', expectAsync((request) {
|
| + var object = new storage.Object.fromJson(JSON.decode(request.body));
|
| + ObjectMetadata m = metadata[countInitial];
|
| + expect(object.name, objectName);
|
| + var contentType = m.contentType != null
|
| + ? m.contentType : 'application/octet-stream';
|
| + expect(object.cacheControl, m.cacheControl);
|
| + expect(object.contentDisposition, m.contentDisposition);
|
| + expect(object.contentEncoding, m.contentEncoding);
|
| + expect(object.contentLanguage, m.contentLanguage);
|
| + expect(object.metadata, m.custom);
|
| + countInitial++;
|
| + return mock.respondInitiateResumableUpload(PROJECT);
|
| + }, count: metadata.length));
|
| + mock.registerResumableUpload(
|
| + 'PUT', 'b/$PROJECT/o', expectAsync((request) {
|
| + ObjectMetadata m = metadata[countData % metadata.length];
|
| + var contentType = m.contentType != null
|
| + ? m.contentType : 'application/octet-stream';
|
| + expect(request.headers['content-type'], contentType);
|
| + bool firstPart = countData < metadata.length;
|
| + countData++;
|
| + if (firstPart) {
|
| + expect(request.bodyBytes.length, MB);
|
| + return mock.respondContinueResumableUpload();
|
| + } else {
|
| + expect(request.bodyBytes.length, 1);
|
| + return mock.respond(new storage.Object()..name = objectName);
|
| + }
|
| + }, count: metadata.length * 2));
|
| +
|
| + var bucket = api.bucket(bucketName);
|
| + var futures = [];
|
| + for (int i = 0; i < metadata.length; i++) {
|
| + futures.add(bucket.writeBytes(objectName, bytesResumableUpload,
|
| + metadata: metadata[i]));
|
| + }
|
| + return Future.wait(futures);
|
| + });
|
| + });
|
| +
|
| + test('write-with-predefined-acl', () {
|
| + var predefined =
|
| + [[PredefinedAcl.authenticatedRead, 'authenticatedRead'],
|
| + [PredefinedAcl.private, 'private'],
|
| + [PredefinedAcl.projectPrivate, 'projectPrivate'],
|
| + [PredefinedAcl.publicRead, 'publicRead'],
|
| + [PredefinedAcl.bucketOwnerFullControl, 'bucketOwnerFullControl'],
|
| + [PredefinedAcl.bucketOwnerRead, 'bucketOwnerRead']];
|
| +
|
| + withMockClient((mock, api) {
|
| + int count = 0;
|
| + var bytes = [1,2,3];
|
| +
|
| + mock.registerUpload(
|
| + 'POST', 'b/$bucketName/o', expectAsync((request) {
|
| + return mock.processNormalMediaUpload(request)
|
| + .then(expectAsync((mediaUpload) {
|
| + var object =
|
| + new storage.Object.fromJson(JSON.decode(mediaUpload.json));
|
| + expect(object.name, objectName);
|
| + expect(mediaUpload.bytes, bytes);
|
| + expect(mediaUpload.contentType, 'application/octet-stream');
|
| + expect(request.url.queryParameters['predefinedAcl'],
|
| + predefined[count++][1]);
|
| + expect(object.acl, isNull);
|
| + return mock.respond(new storage.Object()..name = objectName);
|
| + }));
|
| + }, count: predefined.length));
|
| +
|
| + var bucket = api.bucket(bucketName);
|
| + var futures = [];
|
| + for (int i = 0; i < predefined.length; i++) {
|
| + futures.add(bucket.writeBytes(objectName, bytes,
|
| + predefinedAcl: predefined[i][0]));
|
| + }
|
| + return Future.wait(futures);
|
| + });
|
| + });
|
| +
|
| + test('write-with-acl', () {
|
| + var acl1 = new Acl([
|
| + new AclEntry(new AccountScope('user@example.com'),
|
| + AclPermission.FULL_CONTROL),
|
| + ]);
|
| + var acl2 = new Acl([
|
| + new AclEntry(new AccountScope('user@example.com'),
|
| + AclPermission.FULL_CONTROL),
|
| + new AclEntry(new GroupScope('group@example.com'),
|
| + AclPermission.WRITE),
|
| + ]);
|
| + var acl3 = new Acl([
|
| + new AclEntry(new AccountScope('user@example.com'),
|
| + AclPermission.FULL_CONTROL),
|
| + new AclEntry(new GroupScope('group@example.com'),
|
| + AclPermission.WRITE),
|
| + new AclEntry(new DomainScope('example.com'),
|
| + AclPermission.READ),
|
| + ]);
|
| +
|
| + var acls = [acl1, acl2, acl3];
|
| +
|
| + withMockClient((mock, api) {
|
| + int count = 0;
|
| + var bytes = [1,2,3];
|
| +
|
| + mock.registerUpload(
|
| + 'POST', 'b/$bucketName/o', expectAsync((request) {
|
| + return mock.processNormalMediaUpload(request)
|
| + .then(expectAsync((mediaUpload) {
|
| + var object =
|
| + new storage.Object.fromJson(JSON.decode(mediaUpload.json));
|
| + expect(object.name, objectName);
|
| + expect(mediaUpload.bytes, bytes);
|
| + expect(mediaUpload.contentType, 'application/octet-stream');
|
| + expect(request.url.queryParameters['predefinedAcl'], isNull);
|
| + expect(object.acl, isNotNull);
|
| + expect(object.acl.length, count + 1);
|
| + expect(object.acl[0].entity, 'user-user@example.com');
|
| + expect(object.acl[0].role, 'OWNER');
|
| + if (count > 0) {
|
| + expect(object.acl[1].entity, 'group-group@example.com');
|
| + expect(object.acl[1].role, 'OWNER');
|
| + }
|
| + if (count > 2) {
|
| + expect(object.acl[2].entity, 'domain-example.com');
|
| + expect(object.acl[2].role, 'READER');
|
| + }
|
| + count++;
|
| + return mock.respond(new storage.Object()..name = objectName);
|
| + }));
|
| + }, count: acls.length));
|
| +
|
| + var bucket = api.bucket(bucketName);
|
| + var futures = [];
|
| + for (int i = 0; i < acls.length; i++) {
|
| + futures.add(bucket.writeBytes(objectName, bytes, acl: acls[i]));
|
| + }
|
| + return Future.wait(futures);
|
| + });
|
| + });
|
| +
|
| + test('write-with-acl-and-predefined-acl', () {
|
| + var predefined =
|
| + [[PredefinedAcl.authenticatedRead, 'authenticatedRead'],
|
| + [PredefinedAcl.private, 'private'],
|
| + [PredefinedAcl.projectPrivate, 'projectPrivate'],
|
| + [PredefinedAcl.publicRead, 'publicRead'],
|
| + [PredefinedAcl.bucketOwnerFullControl, 'bucketOwnerFullControl'],
|
| + [PredefinedAcl.bucketOwnerRead, 'bucketOwnerRead']];
|
| +
|
| + var acl1 = new Acl([
|
| + new AclEntry(new AccountScope('user@example.com'),
|
| + AclPermission.FULL_CONTROL),
|
| + ]);
|
| + var acl2 = new Acl([
|
| + new AclEntry(new AccountScope('user@example.com'),
|
| + AclPermission.FULL_CONTROL),
|
| + new AclEntry(new GroupScope('group@example.com'),
|
| + AclPermission.WRITE),
|
| + ]);
|
| + var acl3 = new Acl([
|
| + new AclEntry(new AccountScope('user@example.com'),
|
| + AclPermission.FULL_CONTROL),
|
| + new AclEntry(new GroupScope('group@example.com'),
|
| + AclPermission.WRITE),
|
| + new AclEntry(new DomainScope('example.com'),
|
| + AclPermission.READ),
|
| + ]);
|
| +
|
| + var acls = [acl1, acl2, acl3];
|
| +
|
| + withMockClient((mock, api) {
|
| + int count = 0;
|
| + var bytes = [1,2,3];
|
| +
|
| + mock.registerUpload(
|
| + 'POST', 'b/$bucketName/o', expectAsync((request) {
|
| + return mock.processNormalMediaUpload(request)
|
| + .then(expectAsync((mediaUpload) {
|
| + int predefinedIndex = count ~/ acls.length;
|
| + int aclIndex = count % acls.length;
|
| + var object =
|
| + new storage.Object.fromJson(JSON.decode(mediaUpload.json));
|
| + expect(object.name, objectName);
|
| + expect(mediaUpload.bytes, bytes);
|
| + expect(mediaUpload.contentType, 'application/octet-stream');
|
| + expect(request.url.queryParameters['predefinedAcl'],
|
| + predefined[predefinedIndex][1]);
|
| + expect(object.acl, isNotNull);
|
| + expect(object.acl.length, aclIndex + 1);
|
| + expect(object.acl[0].entity, 'user-user@example.com');
|
| + expect(object.acl[0].role, 'OWNER');
|
| + if (aclIndex > 0) {
|
| + expect(object.acl[1].entity, 'group-group@example.com');
|
| + expect(object.acl[1].role, 'OWNER');
|
| + }
|
| + if (aclIndex > 2) {
|
| + expect(object.acl[2].entity, 'domain-example.com');
|
| + expect(object.acl[2].role, 'READER');
|
| + }
|
| + count++;
|
| + return mock.respond(new storage.Object()..name = objectName);
|
| + }));
|
| + }, count: predefined.length * acls.length));
|
| +
|
| + var bucket = api.bucket(bucketName);
|
| + var futures = [];
|
| + for (int i = 0; i < predefined.length; i++) {
|
| + for (int j = 0; j < acls.length; j++) {
|
| + futures.add(bucket.writeBytes(
|
| + objectName, bytes,
|
| + acl: acls[j], predefinedAcl: predefined[i][0]));
|
| + }
|
| + }
|
| + return Future.wait(futures);
|
| + });
|
| + });
|
| +
|
| +
|
| +
|
| + test('read', () {
|
| + var bytes = [1, 2, 3];
|
| + withMockClient((mock, api) {
|
| + mock.register(
|
| + 'GET', 'b/$bucketName/o/$objectName', expectAsync((request) {
|
| + expect(request.url.queryParameters['alt'], 'media');
|
| + return mock.respondBytes(bytes);
|
| + }));
|
| +
|
| + var bucket = api.bucket(bucketName);
|
| + var data = [];
|
| + bucket.read(objectName).listen(data.addAll).asFuture()
|
| + .then(expectAsync((_) => expect(data, bytes)));
|
| + });
|
| + });
|
| +
|
| + test('stat', () {
|
| + withMockClient((mock, api) {
|
| + mock.register(
|
| + 'GET', 'b/$bucketName/o/$objectName', expectAsync((request) {
|
| + expect(request.url.queryParameters['alt'], 'json');
|
| + return mock.respond(new storage.Object()
|
| + ..name = objectName
|
| + ..updated = new DateTime(2014)
|
| + ..contentType = 'mime/type');
|
| + }));
|
| +
|
| + var api = new Storage(mock, PROJECT);
|
| + var bucket = api.bucket(bucketName);
|
| + bucket.info(objectName).then(expectAsync((stat) {
|
| + expect(stat.name, objectName);
|
| + expect(stat.updated, new DateTime(2014));
|
| + expect(stat.metadata.contentType, 'mime/type');
|
| + }));
|
| + });
|
| + });
|
| +
|
| + test('stat-acl', () {
|
| + withMockClient((mock, api) {
|
| + mock.register(
|
| + 'GET', 'b/$bucketName/o/$objectName', expectAsync((request) {
|
| + expect(request.url.queryParameters['alt'], 'json');
|
| + var acl1 = new storage.ObjectAccessControl();
|
| + acl1.entity = 'user-1234567890';
|
| + acl1.role = 'OWNER';
|
| + var acl2 = new storage.ObjectAccessControl();
|
| + acl2.entity = 'user-xxx@yyy.zzz';
|
| + acl2.role = 'OWNER';
|
| + var acl3 = new storage.ObjectAccessControl();
|
| + acl3.entity = 'xxx-1234567890';
|
| + acl3.role = 'OWNER';
|
| + return mock.respond(new storage.Object()
|
| + ..name = objectName
|
| + ..acl = [acl1, acl2, acl3]);
|
| + }));
|
| +
|
| + var api = new Storage(mock, PROJECT);
|
| + var bucket = api.bucket(bucketName);
|
| + bucket.info(objectName).then(expectAsync((ObjectInfo info) {
|
| + expect(info.name, objectName);
|
| + expect(info.metadata.acl.entries.length, 3);
|
| + expect(info.metadata.acl.entries[0] is AclEntry, isTrue);
|
| + expect(info.metadata.acl.entries[0].scope is StorageIdScope, isTrue);
|
| + expect(info.metadata.acl.entries[1] is AclEntry, isTrue);
|
| + expect(info.metadata.acl.entries[1].scope is AccountScope, isTrue);
|
| + expect(info.metadata.acl.entries[2] is AclEntry, isTrue);
|
| + expect(info.metadata.acl.entries[2].scope is OpaqueScope, isTrue);
|
| + }));
|
| + });
|
| + });
|
| +
|
| + group('list', () {
|
| + test('empty', () {
|
| + withMockClient((mock, api) {
|
| + mock.register('GET', 'b/$bucketName/o', expectAsync((request) {
|
| + expect(request.body.length, 0);
|
| + return mock.respond(new storage.Objects());
|
| + }));
|
| +
|
| + var bucket = api.bucket(bucketName);
|
| + bucket.list().listen(
|
| + (_) => throw 'Unexpected',
|
| + onDone: expectAsync(() => null));
|
| + });
|
| + });
|
| +
|
| + test('immediate-cancel', () {
|
| + withMockClient((mock, api) {
|
| + var bucket = api.bucket(bucketName);
|
| + bucket.list().listen(
|
| + (_) => throw 'Unexpected',
|
| + onDone: () => throw 'Unexpected')
|
| + ..cancel();
|
| + });
|
| + });
|
| +
|
| + test('list', () {
|
| + // TODO: Test list.
|
| + });
|
| +
|
| + test('page', () {
|
| + // TODO: Test page.
|
| + });
|
| + });
|
| + });
|
| +
|
| + group('acl', () {
|
| + var id = new StorageIdScope('1234567890');
|
| + var user = new AccountScope('sgjesse@google.com');
|
| + var group = new GroupScope('dart');
|
| + var domain = new DomainScope('dartlang.org');
|
| +
|
| + var userRead = new AclEntry(user, AclPermission.READ);
|
| + var groupWrite = new AclEntry(group, AclPermission.WRITE);
|
| + var domainFullControl =
|
| + new AclEntry(domain, AclPermission.FULL_CONTROL);
|
| +
|
| + test('compare-scope', () {
|
| + expect(id, new StorageIdScope('1234567890'));
|
| + expect(user, new AccountScope('sgjesse@google.com'));
|
| + expect(group, new GroupScope('dart'));
|
| + expect(domain, new DomainScope('dartlang.org'));
|
| + expect(AclScope.allAuthenticated, new AllAuthenticatedScope());
|
| + expect(AclScope.allUsers, new AllUsersScope());
|
| + });
|
| +
|
| + test('compare-entries', () {
|
| + expect(userRead, new AclEntry(user, AclPermission.READ));
|
| + expect(groupWrite, new AclEntry(group, AclPermission.WRITE));
|
| + expect(domainFullControl,
|
| + new AclEntry(domain, AclPermission.FULL_CONTROL));
|
| + });
|
| +
|
| + test('compare-acls', () {
|
| + var acl = new Acl([userRead, groupWrite, domainFullControl]);
|
| + expect(acl, new Acl([new AclEntry(user, AclPermission.READ),
|
| + new AclEntry(group, AclPermission.WRITE),
|
| + new AclEntry(domain, AclPermission.FULL_CONTROL)]));
|
| + expect(acl,
|
| + isNot(equals(new Acl([new AclEntry(group, AclPermission.WRITE),
|
| + new AclEntry(user, AclPermission.READ),
|
| + new AclEntry(domain, AclPermission.FULL_CONTROL)]))));
|
| + });
|
| +
|
| +
|
| + test('compare-predefined-acls', () {
|
| + expect(PredefinedAcl.private, PredefinedAcl.private);
|
| + expect(PredefinedAcl.private, isNot(equals(PredefinedAcl.publicRead)));
|
| + });
|
| + });
|
| +}
|
|
|