diff --git a/storage/README.md b/storage/README.md index 4a58f7129e..a5a54eb01b 100644 --- a/storage/README.md +++ b/storage/README.md @@ -11,6 +11,7 @@ amount of data at any time. * [Setup](#setup) * [Samples](#samples) + * [ACL (Access Control Lists)](#acl-access-control-lists) * [Buckets](#buckets) * [Encryption](#encryption) * [Files](#files) @@ -28,6 +29,41 @@ amount of data at any time. ## Samples +### ACL (Access Control Lists) + +View the [documentation][acl_docs] or the [source code][acl_code]. + +__Usage:__ `node acl --help` + +``` +Commands: + add Add access controls on a bucket or file. + get [entity] Get access controls on a bucket or file. + delete Delete access controls from a bucket or file. + +Options: + --bucket, -b The target storage bucket. [string] [required] + --default, -d Whether to set default access controls. Only valid when setting access controls on + a bucket. [boolean] + --file, -f The target file. [string] + --help Show help [boolean] + +Examples: + node acl add user-bob@domain.com OWNER -b mybucket Add OWNER access controls for + "user-bob@domain.com" to "mybucket". + node acl add viewers-2256 WRITER -b mybucket -d Add default WRITER access controls to + "mybucket" for "viewers-2256". + node acl get editors-1234 -b mybucket Get access controls for "editors-1234" in + "mybucket". + node acl delete -b mybucket -f file.txt Delete all access controls for all entities + from "file.txt" in "mybucket". + +For more information, see https://cloud.google.com/storage/docs/access-control/create-manage-lists +``` + +[acl_docs]: https://cloud.google.com/storage/docs/access-control/create-manage-lists +[acl_code]: acl.js + ### Buckets View the [documentation][buckets_docs] or the [source code][buckets_code]. diff --git a/storage/acl.js b/storage/acl.js new file mode 100644 index 0000000000..20fbf2e88e --- /dev/null +++ b/storage/acl.js @@ -0,0 +1,218 @@ +// Copyright 2015-2016, Google, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +// [START all] +// [START setup] +// By default, the client will authenticate using the service account file +// specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable and use +// the project specified by the GCLOUD_PROJECT environment variable. See +// https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/guides/authentication +var Storage = require('@google-cloud/storage'); + +// Instantiate a storage client +var storage = Storage(); +// [END setup] + +// [START add_access_control] +/** + * Add access controls to a bucket or file. + * + * @param {object} options Configuration options. + * @param {string} options.bucket The bucket for the new access controls. + * @param {string} options.entity The entity for the new access controls. + * @param {string} options.role The role for the new access controls. + * @param {string} [options.file] Optional. The file for the new access controls. + * @param {boolean} [options.default] Optional. Whether to set default access controls. + * @param {function} callback The callback function. + */ +function addAccessControl (options, callback) { + // Reference the specified storage bucket + var bucket = storage.bucket(options.bucket); + // Reference the bucket's acl resource + // See https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/storage/bucket?method=acl.add + var acl = bucket.acl; + + if (options.file) { + // Optionally target a file's acl resource + // See https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/storage/file?method=acl.add + acl = bucket.file(options.file).acl; + } else if (options.default) { + // Optionally add "default" access controls to the bucket + // See https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/storage/bucket?method=acl.default.add + acl = acl.default; + } + + // Specify the entity and role for the new access control object + var config = { + entity: options.entity, + role: options.role + }; + + acl.add(config, function (err, aclObject) { + if (err) { + return callback(err); + } + + console.log('Added access controls to: gs://%s' + (options.file ? '/%s' : ''), options.bucket, options.file || ''); + return callback(null, aclObject); + }); +} +// [END add_access_control] + +// [START get_access_control] +/** + * Get access controls for a bucket or file. + * + * @param {object} options Configuration options. + * @param {string} options.bucket The bucket to target. + * @param {string} [options.entity] Optional. The entity to filter by. + * @param {string} [options.file] Optional. The file to target. + * @param {boolean} [options.default] Optional. Whether to get default access controls. + * @param {function} callback The callback function. + */ +function getAccessControl (options, callback) { + // Reference the specified storage bucket + var bucket = storage.bucket(options.bucket); + // Reference the bucket's acl resource + // See https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/storage/bucket?method=acl.get + var acl = bucket.acl; + + if (options.file) { + // Optionally target a file's acl resource + // See https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/storage/file?method=acl.get + acl = bucket.file(options.file).acl; + } else if (options.default) { + // Optionally get "default" access controls for the bucket + // See https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/storage/bucket?method=acl.default.get + acl = acl.default; + } + + if (options.entity) { + // Get a list of access controls for a specific entity + acl.get({ entity: options.entity }, handleResponse); + } else { + // Get a list of all access controls + acl.get(handleResponse); + } + + function handleResponse (err, aclObject) { + if (err) { + return callback(err); + } + + console.log('Got access controls for: gs://%s' + (options.file ? '/%s' : ''), options.bucket, options.file || ''); + return callback(null, aclObject); + } +} +// [END get_access_control] + +// [START delete_access_control] +/** + * Delete access controls from a bucket or file. + * + * @param {object} options Configuration options. + * @param {string} options.bucket The bucket to target. + * @param {string} options.entity The entity whose access is to be revoked. + * @param {string} [options.file] Optional. The file to target. + * @param {boolean} [options.default] Optional. Whether to delete default access controls. + * @param {function} callback The callback function. + */ +function deleteAccessControl (options, callback) { + // Reference the specified storage bucket + var bucket = storage.bucket(options.bucket); + // Reference the bucket's acl resource + // See https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/storage/bucket?method=acl.delete + var acl = bucket.acl; + + if (options.file) { + // Optionally target a file's acl resource + // See https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/storage/file?method=acl.delete + acl = bucket.file(options.file).acl; + } else if (options.default) { + // Optionally delete "default" access controls from the bucket + // See https://googlecloudplatform.github.io/gcloud-node/#/docs/google-cloud/latest/storage/bucket?method=acl.default.delete + acl = acl.default; + } + + // Delete access controls for a specific entity + acl.delete({ entity: options.entity }, function (err) { + if (err) { + return callback(err); + } + + console.log('Deleted access controls from: gs://%s' + (options.file ? '/%s' : ''), options.bucket, options.file || ''); + return callback(null); + }); +} +// [END delete_access_control] +// [END all] + +// The command-line program +var cli = require('yargs'); + +var program = module.exports = { + addAccessControl: addAccessControl, + getAccessControl: getAccessControl, + deleteAccessControl: deleteAccessControl, + main: function (args) { + // Run the command-line program + cli.help().strict().parse(args).argv; + } +}; + +cli + .command('add ', 'Add access controls on a bucket or file.', {}, function (options) { + program.addAccessControl(options, console.log); + }) + .command('get [entity]', 'Get access controls on a bucket or file.', {}, function (options) { + program.getAccessControl(options, console.log); + }) + .command('delete ', 'Delete access controls from a bucket or file.', {}, function (options) { + program.deleteAccessControl(options, console.log); + }) + .example('node $0 add user-bob@domain.com OWNER -b mybucket', 'Add OWNER access controls for "user-bob@domain.com" to "mybucket".') + .example('node $0 add viewers-2256 WRITER -b mybucket -d', 'Add default WRITER access controls to "mybucket" for "viewers-2256".') + .example('node $0 get editors-1234 -b mybucket', 'Get access controls for "editors-1234" in "mybucket".') + .example('node $0 delete -b mybucket -f file.txt', 'Delete all access controls for all entities from "file.txt" in "mybucket".') + .options({ + bucket: { + alias: 'b', + global: true, + demand: true, + requiresArg: true, + type: 'string', + description: 'The target storage bucket.' + }, + default: { + alias: 'd', + global: true, + type: 'boolean', + description: 'Whether to set default access controls. Only valid when setting access controls on a bucket.' + }, + file: { + alias: 'f', + global: true, + requiresArg: true, + type: 'string', + description: 'The target file.' + } + }) + .wrap(100) + .recommendCommands() + .epilogue('For more information, see https://cloud.google.com/storage/docs/access-control/create-manage-lists'); + +if (module === require.main) { + program.main(process.argv.slice(2)); +} diff --git a/storage/iam.js b/storage/iam.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/storage/package.json b/storage/package.json index f1a7ffa106..2a705e0460 100644 --- a/storage/package.json +++ b/storage/package.json @@ -11,7 +11,8 @@ "dependencies": { "@google-cloud/storage": "^0.1.1", "googleapis": "^12.2.0", - "moment": "^2.14.1" + "moment": "^2.14.1", + "yargs": "^5.0.0" }, "devDependencies": { "mocha": "^3.0.2", diff --git a/storage/system-test/acl.test.js b/storage/system-test/acl.test.js new file mode 100644 index 0000000000..12cddde3f0 --- /dev/null +++ b/storage/system-test/acl.test.js @@ -0,0 +1,237 @@ +// Copyright 2015-2016, Google, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +var path = require('path'); +var Storage = require('@google-cloud/storage'); +var uuid = require('node-uuid'); +var program = require('../acl'); + +var storage = Storage(); +var bucketName = 'nodejs-docs-samples-test-' + uuid.v4(); +var fileName = 'test.txt'; +var entity = 'allAuthenticatedUsers'; +var role = 'READER'; +var filePath = path.join(__dirname, '../resources', fileName); + +var expected = { + entity: entity, + role: role +}; + +describe('storage:acl', function () { + before(function (done) { + storage.createBucket(bucketName, function (err, bucket) { + if (err) { + return done(err); + } + bucket.upload(filePath, done); + }); + }); + + after(function (done) { + storage.bucket(bucketName).deleteFiles({ force: true }, function (err) { + if (err) { + return done(err); + } + storage.bucket(bucketName).delete(done); + }); + }); + + describe('add', function () { + it('should add access controls to a bucket', function (done) { + program.addAccessControl({ + bucket: bucketName, + entity: entity, + role: role + }, function (err, aclObject) { + assert.ifError(err); + assert.deepEqual(aclObject, expected); + done(); + }); + }); + + it('should add "default" access controls to a bucket', function (done) { + program.addAccessControl({ + bucket: bucketName, + entity: entity, + role: role, + default: true + }, function (err, aclObject) { + assert.ifError(err); + assert.deepEqual(aclObject, expected); + done(); + }); + }); + + it('should add access controls to a file', function (done) { + program.addAccessControl({ + bucket: bucketName, + file: fileName, + entity: entity, + role: role + }, function (err, aclObject) { + assert.ifError(err); + assert.ifError(err); + assert.deepEqual(aclObject, expected); + setTimeout(done, 2000); // Make sure changes have time to take effect + }); + }); + }); + + describe('get', function () { + it('should get all access controls for a bucket', function (done) { + program.getAccessControl({ + bucket: bucketName + }, function (err, aclObjects) { + assert.ifError(err); + assert(Array.isArray(aclObjects)); + assert(aclObjects.length > 1); + var matchesExpected = aclObjects.filter(function (aclObject) { + return aclObject.entity === entity && aclObject.role === role; + }); + assert.equal(matchesExpected.length, 1, 'Recently added aclObject should be in list'); + done(); + }); + }); + + it('should get an entity\'s access controls for a bucket', function (done) { + program.getAccessControl({ + bucket: bucketName, + entity: entity + }, function (err, aclObject) { + assert.ifError(err); + assert.deepEqual(aclObject, expected); + done(); + }); + }); + + it('should get all "default" access controls for a bucket', function (done) { + program.getAccessControl({ + bucket: bucketName, + default: true + }, function (err, aclObjects) { + assert.ifError(err); + assert(Array.isArray(aclObjects)); + assert(aclObjects.length > 1); + var matchesExpected = aclObjects.filter(function (aclObject) { + return aclObject.entity === entity && aclObject.role === role; + }); + assert.equal(matchesExpected.length, 1, 'Recently added aclObject should be in list'); + done(); + }); + }); + + it('should get an entity\'s "default" access controls for a bucket', function (done) { + program.getAccessControl({ + bucket: bucketName, + entity: entity, + default: true + }, function (err, aclObject) { + assert.ifError(err); + assert.deepEqual(aclObject, expected); + done(); + }); + }); + + it('should get all access controls for a file', function (done) { + program.getAccessControl({ + bucket: bucketName, + file: fileName + }, function (err, aclObjects) { + assert.ifError(err); + assert(Array.isArray(aclObjects)); + assert(aclObjects.length > 1); + var matchesExpected = aclObjects.filter(function (aclObject) { + return aclObject.entity === entity && aclObject.role === role; + }); + assert.equal(matchesExpected.length, 1, 'Recently added aclObject should be in list'); + done(); + }); + }); + + it('should get an entity\'s access controls for a file', function (done) { + program.getAccessControl({ + bucket: bucketName, + file: fileName, + entity: entity + }, function (err, aclObject) { + assert.ifError(err); + assert.deepEqual(aclObject, expected); + done(); + }); + }); + }); + + describe('delete', function () { + it('should delete an entity\'s access controls from a file', function (done) { + program.deleteAccessControl({ + bucket: bucketName, + file: fileName, + entity: entity + }, function (err) { + assert.ifError(err); + + program.getAccessControl({ + bucket: bucketName, + file: fileName, + entity: entity + }, function (err, aclObject) { + assert(err); + assert.equal(err.message, 'Not Found'); + done(); + }); + }); + }); + + it('should delete an entity\'s access controls from a bucket', function (done) { + program.deleteAccessControl({ + bucket: bucketName, + entity: entity + }, function (err, aclObject) { + assert.ifError(err); + + program.getAccessControl({ + bucket: bucketName, + entity: entity + }, function (err, aclObject) { + assert(err); + assert.equal(err.message, 'Not Found'); + done(); + }); + }); + }); + + it('should delete an entity\'s "default" access controls from a bucket', function (done) { + program.deleteAccessControl({ + bucket: bucketName, + entity: entity, + default: true + }, function (err, aclObject) { + assert.ifError(err); + + program.getAccessControl({ + bucket: bucketName, + file: fileName, + entity: entity, + default: true + }, function (err, aclObject) { + assert(err); + assert.equal(err.message, 'Not Found'); + done(); + }); + }); + }); + }); +}); diff --git a/storage/test/acl.test.js b/storage/test/acl.test.js new file mode 100644 index 0000000000..5f1aedad9e --- /dev/null +++ b/storage/test/acl.test.js @@ -0,0 +1,379 @@ +// Copyright 2016, Google, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +var proxyquire = require('proxyquire').noCallThru(); +var bucketName = 'foo'; +var fileName = 'file.txt'; +var entity = 'user-bob@domain.com'; +var role = 'OWNER'; + +function getSample () { + var aclObjectMock = {}; + var fileMock = { + acl: { + add: sinon.stub().callsArgWith(1, null, aclObjectMock), + get: sinon.stub().callsArgWith(0, null, aclObjectMock), + delete: sinon.stub().callsArgWith(1, null, aclObjectMock) + }, + name: fileName + }; + var bucketMock = { + acl: { + add: sinon.stub().callsArgWith(1, null, aclObjectMock), + get: sinon.stub().callsArgWith(0, null, aclObjectMock), + delete: sinon.stub().callsArgWith(1, null, aclObjectMock), + default: { + add: sinon.stub().callsArgWith(1, null, aclObjectMock), + get: sinon.stub().callsArgWith(0, null, aclObjectMock), + delete: sinon.stub().callsArgWith(1, null, aclObjectMock) + } + }, + file: sinon.stub().returns(fileMock), + name: bucketName + }; + var storageMock = { + bucket: sinon.stub().returns(bucketMock) + }; + var StorageMock = sinon.stub().returns(storageMock); + + return { + program: proxyquire('../acl', { + '@google-cloud/storage': StorageMock + }), + mocks: { + Storage: StorageMock, + storage: storageMock, + bucket: bucketMock, + file: fileMock, + aclObject: aclObjectMock + } + }; +} + +describe('storage:acl', function () { + describe('add', function () { + it('should add access controls to bucket', function () { + var sample = getSample(); + var callback = sinon.stub(); + var options = { + bucket: bucketName, + entity: entity, + role: role + }; + + sample.program.addAccessControl(options, callback); + + assert(sample.mocks.bucket.acl.add.calledOnce, 'add called once'); + assert.equal(sample.mocks.bucket.acl.add.firstCall.args.length, 2, 'add received 2 arguments'); + assert.deepEqual(sample.mocks.bucket.acl.add.firstCall.args[0], { + entity: entity, + role: role + }, 'add received options'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert.strictEqual(callback.firstCall.args[1], sample.mocks.aclObject, 'callback received acl object'); + assert(console.log.calledWith('Added access controls to: gs://%s', bucketName, '')); + }); + it('should add "default" access controls to bucket', function () { + var sample = getSample(); + var callback = sinon.stub(); + var options = { + bucket: bucketName, + entity: entity, + role: role, + default: true + }; + + sample.program.addAccessControl(options, callback); + + assert(sample.mocks.bucket.acl.default.add.calledOnce, 'add called once'); + assert.equal(sample.mocks.bucket.acl.default.add.firstCall.args.length, 2, 'add received 2 arguments'); + assert.deepEqual(sample.mocks.bucket.acl.default.add.firstCall.args[0], { + entity: entity, + role: role + }, 'add received options'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert.strictEqual(callback.firstCall.args[1], sample.mocks.aclObject, 'callback received acl object'); + assert(console.log.calledWith('Added access controls to: gs://%s', bucketName, '')); + }); + it('should add access controls to a file', function () { + var sample = getSample(); + var callback = sinon.stub(); + var options = { + bucket: bucketName, + entity: entity, + role: role, + file: fileName + }; + + sample.program.addAccessControl(options, callback); + + assert(sample.mocks.file.acl.add.calledOnce, 'add called once'); + assert.equal(sample.mocks.file.acl.add.firstCall.args.length, 2, 'add received 2 arguments'); + assert.deepEqual(sample.mocks.file.acl.add.firstCall.args[0], { + entity: entity, + role: role + }, 'add received options'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert.strictEqual(callback.firstCall.args[1], sample.mocks.aclObject, 'callback received acl object'); + assert(console.log.calledWith('Added access controls to: gs://%s/%s', bucketName, fileName)); + }); + it('should handle error', function () { + var error = 'error'; + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.bucket.acl.add = sinon.stub().callsArgWith(1, error); + + sample.program.addAccessControl({ + bucket: bucketName, + entity: entity, + role: role + }, callback); + + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 1, 'callback received 1 argument'); + assert(callback.firstCall.args[0], 'callback received error'); + assert.equal(callback.firstCall.args[0].message, error.message, 'error has correct message'); + }); + }); + + describe('get', function () { + it('should get all access controls for a bucket', function () { + var sample = getSample(); + var callback = sinon.stub(); + var options = { + bucket: bucketName + }; + + sample.program.getAccessControl(options, callback); + + assert(sample.mocks.bucket.acl.get.calledOnce, 'add called once'); + assert.equal(sample.mocks.bucket.acl.get.firstCall.args.length, 1, 'add received 1 argument'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert.strictEqual(callback.firstCall.args[1], sample.mocks.aclObject, 'callback received acl object'); + assert(console.log.calledWith('Got access controls for: gs://%s', bucketName, '')); + }); + it('should get all "default" access controls for a bucket', function () { + var sample = getSample(); + var callback = sinon.stub(); + var options = { + bucket: bucketName, + default: true + }; + + sample.program.getAccessControl(options, callback); + + assert(sample.mocks.bucket.acl.default.get.calledOnce, 'add called once'); + assert.equal(sample.mocks.bucket.acl.default.get.firstCall.args.length, 1, 'add received 1 argument'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert.strictEqual(callback.firstCall.args[1], sample.mocks.aclObject, 'callback received acl object'); + assert(console.log.calledWith('Got access controls for: gs://%s', bucketName, '')); + }); + it('should get an entity\'s access controls for a bucket', function () { + var sample = getSample(); + var callback = sinon.stub(); + var options = { + bucket: bucketName, + entity: entity + }; + sample.mocks.bucket.acl.get.callsArgWith(1, null, sample.mocks.aclObject); + + sample.program.getAccessControl(options, callback); + + assert(sample.mocks.bucket.acl.get.calledOnce, 'add called once'); + assert.equal(sample.mocks.bucket.acl.get.firstCall.args.length, 2, 'add received 2 arguments'); + assert.deepEqual(sample.mocks.bucket.acl.get.firstCall.args[0], { + entity: entity + }, 'get received options'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert.strictEqual(callback.firstCall.args[1], sample.mocks.aclObject, 'callback received acl object'); + assert(console.log.calledWith('Got access controls for: gs://%s', bucketName, '')); + }); + it('should get an entity\'s "default" access controls for a bucket', function () { + var sample = getSample(); + var callback = sinon.stub(); + var options = { + bucket: bucketName, + entity: entity, + default: true + }; + sample.mocks.bucket.acl.default.get.callsArgWith(1, null, sample.mocks.aclObject); + + sample.program.getAccessControl(options, callback); + + assert(sample.mocks.bucket.acl.default.get.calledOnce, 'add called once'); + assert.equal(sample.mocks.bucket.acl.default.get.firstCall.args.length, 2, 'add received 2 arguments'); + assert.deepEqual(sample.mocks.bucket.acl.default.get.firstCall.args[0], { + entity: entity + }, 'get received options'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert.strictEqual(callback.firstCall.args[1], sample.mocks.aclObject, 'callback received acl object'); + assert(console.log.calledWith('Got access controls for: gs://%s', bucketName, '')); + }); + it('should get access controls for a file', function () { + var sample = getSample(); + var callback = sinon.stub(); + var options = { + bucket: bucketName, + file: fileName + }; + + sample.program.getAccessControl(options, callback); + + assert(sample.mocks.file.acl.get.calledOnce, 'add called once'); + assert.equal(sample.mocks.file.acl.get.firstCall.args.length, 1, 'add received 1 argument'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert.strictEqual(callback.firstCall.args[1], sample.mocks.aclObject, 'callback received acl object'); + assert(console.log.calledWith('Got access controls for: gs://%s/%s', bucketName, fileName)); + }); + it('should handle error', function () { + var error = 'error'; + var sample = getSample(); + var callback = sinon.stub(); + var options = { + bucket: bucketName + }; + sample.mocks.bucket.acl.get = sinon.stub().callsArgWith(0, error); + + sample.program.getAccessControl(options, callback); + + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 1, 'callback received 1 argument'); + assert(callback.firstCall.args[0], 'callback received error'); + assert.equal(callback.firstCall.args[0].message, error.message, 'error has correct message'); + }); + }); + + describe('delete', function () { + it('should delete an entity\'s access controls from a bucket', function () { + var sample = getSample(); + var callback = sinon.stub(); + var options = { + bucket: bucketName, + entity: entity + }; + sample.mocks.bucket.acl.delete.callsArgWith(1, null, sample.mocks.aclObject); + + sample.program.deleteAccessControl(options, callback); + + assert(sample.mocks.bucket.acl.delete.calledOnce, 'add called once'); + assert.equal(sample.mocks.bucket.acl.delete.firstCall.args.length, 2, 'add received 2 arguments'); + assert.deepEqual(sample.mocks.bucket.acl.delete.firstCall.args[0], { + entity: entity + }, 'get received options'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 1, 'callback received 1 argument'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert(console.log.calledWith('Deleted access controls from: gs://%s', bucketName, '')); + }); + it('should delete an entity\'s "default" access controls from a bucket', function () { + var sample = getSample(); + var callback = sinon.stub(); + var options = { + bucket: bucketName, + entity: entity, + default: true + }; + sample.mocks.bucket.acl.default.delete.callsArgWith(1, null, sample.mocks.aclObject); + + sample.program.deleteAccessControl(options, callback); + + assert(sample.mocks.bucket.acl.default.delete.calledOnce, 'add called once'); + assert.equal(sample.mocks.bucket.acl.default.delete.firstCall.args.length, 2, 'add received 2 arguments'); + assert.deepEqual(sample.mocks.bucket.acl.default.delete.firstCall.args[0], { + entity: entity + }, 'get received options'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 1, 'callback received 1 argument'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert(console.log.calledWith('Deleted access controls from: gs://%s', bucketName, '')); + }); + it('should delete access controls from a file', function () { + var sample = getSample(); + var callback = sinon.stub(); + var options = { + bucket: bucketName, + file: fileName, + entity: entity + }; + + sample.program.deleteAccessControl(options, callback); + + assert(sample.mocks.file.acl.delete.calledOnce, 'add called once'); + assert.equal(sample.mocks.file.acl.delete.firstCall.args.length, 2, 'delete received 2 arguments'); + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 1, 'callback received 1 argument'); + assert.ifError(callback.firstCall.args[0], 'callback did not receive error'); + assert(console.log.calledWith('Deleted access controls from: gs://%s/%s', bucketName, fileName)); + }); + it('should handle error', function () { + var error = 'error'; + var sample = getSample(); + var callback = sinon.stub(); + var options = { + bucket: bucketName + }; + sample.mocks.bucket.acl.delete = sinon.stub().callsArgWith(1, error); + + sample.program.deleteAccessControl(options, callback); + + assert(callback.calledOnce, 'callback called once'); + assert.equal(callback.firstCall.args.length, 1, 'callback received 1 argument'); + assert(callback.firstCall.args[0], 'callback received error'); + assert.equal(callback.firstCall.args[0].message, error.message, 'error has correct message'); + }); + }); + + describe('main', function () { + it('should call addAccessControl', function () { + var program = getSample().program; + + sinon.stub(program, 'addAccessControl'); + program.main(['add', 'owners-1234', 'OWNER', '-b', 'nodejs-docs-samples']); + assert(program.addAccessControl.calledOnce); + }); + + it('should call getAccessControl', function () { + var program = getSample().program; + + sinon.stub(program, 'getAccessControl'); + program.main(['get', 'owners-1234', '-b', 'nodejs-docs-samples']); + assert(program.getAccessControl.calledOnce); + }); + + it('should call getAccessControl', function () { + var program = getSample().program; + + sinon.stub(program, 'deleteAccessControl'); + program.main(['delete', 'owners-1234', '-b', 'nodejs-docs-samples']); + assert(program.deleteAccessControl.calledOnce); + }); + }); +});