From 215cf624e7892816477cee732b66378697478eab Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Tue, 16 Aug 2016 20:31:24 -0700 Subject: [PATCH] Start storagetransfer samples. (#168) * StorageTransfer API samples. * Address comments --- storage/package.json | 4 +- storage/system-test/transfer.test.js | 125 ++++++ storage/test/transfer.test.js | 639 +++++++++++++++++++++++++++ storage/transfer.js | 453 +++++++++++++++++++ 4 files changed, 1220 insertions(+), 1 deletion(-) create mode 100644 storage/system-test/transfer.test.js create mode 100644 storage/test/transfer.test.js create mode 100644 storage/transfer.js diff --git a/storage/package.json b/storage/package.json index 2b982bbd95..f1a7ffa106 100644 --- a/storage/package.json +++ b/storage/package.json @@ -9,7 +9,9 @@ "system-test": "mocha -R spec -t 120000 --require intelli-espower-loader ../system-test/_setup.js system-test/*.test.js" }, "dependencies": { - "@google-cloud/storage": "^0.1.1" + "@google-cloud/storage": "^0.1.1", + "googleapis": "^12.2.0", + "moment": "^2.14.1" }, "devDependencies": { "mocha": "^3.0.2", diff --git a/storage/system-test/transfer.test.js b/storage/system-test/transfer.test.js new file mode 100644 index 0000000000..15687f3ca3 --- /dev/null +++ b/storage/system-test/transfer.test.js @@ -0,0 +1,125 @@ +// 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 uuid = require('node-uuid'); +var program = require('../transfer'); +var Storage = require('@google-cloud/storage'); + +var storage = Storage(); +var firstBucketName = 'nodejs-docs-samples-test-' + uuid.v4(); +var secondBucketName = 'nodejs-docs-samples-test-' + uuid.v4(); + +describe('storage:transfer', function () { + var jobName; + var date = '2222/08/11'; + var time = '15:30'; + var description = 'this is a test'; + var status = 'DISABLED'; + + before(function (done) { + storage.createBucket(firstBucketName, function (err) { + if (err) { + return done(err); + } + storage.createBucket(secondBucketName, done); + }); + }); + + after(function (done) { + storage.bucket(firstBucketName).deleteFiles({ force: true }, function (err) { + if (err) { + return done(err); + } + storage.bucket(firstBucketName).delete(function (err) { + if (err) { + return done(err); + } + storage.bucket(secondBucketName).deleteFiles({ force: true }, function (err) { + if (err) { + return done(err); + } + storage.bucket(secondBucketName).delete(done); + }); + }); + }); + }); + + describe('createTransferJob', function () { + it('should create a storage transfer job', function (done) { + program.createTransferJob(firstBucketName, secondBucketName, date, time, description, function (err, transferJob) { + assert.ifError(err); + jobName = transferJob.name; + assert.equal(transferJob.name.indexOf('transferJobs/'), 0); + assert.equal(transferJob.description, description); + assert.equal(transferJob.status, 'ENABLED'); + assert(console.log.calledWith('Created transfer job: %s', transferJob.name)); + setTimeout(done, 2000); + }); + }); + }); + + describe('getTransferJob', function () { + it('should get a transferJob', function (done) { + program.getTransferJob(jobName, function (err, transferJob) { + assert.ifError(err); + assert.equal(transferJob.name, jobName); + assert.equal(transferJob.description, description); + assert.equal(transferJob.status, 'ENABLED'); + assert(console.log.calledWith('Found transfer job: %s', transferJob.name)); + setTimeout(done, 2000); + }); + }); + }); + + describe('updateTransferJob', function () { + it('should update a transferJob', function (done) { + program.updateTransferJob(jobName, 'status', status, function (err, transferJob) { + assert.ifError(err); + assert.equal(transferJob.name, jobName); + assert.equal(transferJob.description, description); + assert.equal(transferJob.status, status); + assert(console.log.calledWith('Updated transfer job: %s', transferJob.name)); + setTimeout(done, 2000); + }); + }); + }); + + describe('listTransferJobs', function () { + it('should list transferJobs', function (done) { + program.listTransferJobs(function (err, transferJobs) { + assert.ifError(err); + var matchingTransferJobs = transferJobs.filter(function (transferJob) { + return transferJob.name === jobName; + }); + assert.equal(matchingTransferJobs.length, 1); + assert.equal(matchingTransferJobs[0].name, jobName); + assert.equal(matchingTransferJobs[0].description, description); + assert.equal(matchingTransferJobs[0].status, status); + assert(console.log.calledWith('Found %d jobs!', transferJobs.length)); + setTimeout(done, 2000); + }); + }); + }); + + describe('listTransferOperations', function () { + it('should list transferJobs', function (done) { + program.listTransferOperations(jobName, function (err, operations) { + assert.ifError(err); + assert(Array.isArray(operations)); + done(); + }); + }); + }); +}); diff --git a/storage/test/transfer.test.js b/storage/test/transfer.test.js new file mode 100644 index 0000000000..55f0e2d467 --- /dev/null +++ b/storage/test/transfer.test.js @@ -0,0 +1,639 @@ +// 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 jobName = 'transferJobs/123456789012345678'; +var transferOperationName = 'transferOperations/123456789012345678'; + +function getSample () { + var transferJobMock = {}; + var transferOperationMock = {}; + var storagetransferMock = { + transferJobs: { + create: sinon.stub().callsArgWith(1, null, transferJobMock), + get: sinon.stub().callsArgWith(1, null, transferJobMock), + patch: sinon.stub().callsArgWith(1, null, transferJobMock), + list: sinon.stub().callsArgWith(1, null, { transferJobs: [transferJobMock] }) + }, + transferOperations: { + get: sinon.stub().callsArgWith(1, null, transferOperationMock), + pause: sinon.stub().callsArgWith(1, null, transferOperationMock), + resume: sinon.stub().callsArgWith(1, null, transferOperationMock), + list: sinon.stub().callsArgWith(1, null, { operations: [transferOperationMock] }) + } + }; + var googleapisMock = { + storagetransfer: sinon.stub().returns(storagetransferMock), + auth: { + getApplicationDefault: sinon.stub().callsArgWith(0, null, {}) + } + }; + return { + program: proxyquire('../transfer', { + googleapis: googleapisMock + }), + mocks: { + googleapis: googleapisMock, + storagetransfer: storagetransferMock, + transferJob: transferJobMock, + transferOperation: transferOperationMock + } + }; +} + +describe('storage:transfer', function () { + describe('jobs', function () { + describe('create', function () { + it('should create a transfer job', function () { + var description = 'description'; + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.createTransferJob(bucketName, bucketName, '2016/08/11', '15:30', null, callback); + + 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.transferJob, 'callback received transfer job'); + + sample.program.createTransferJob(bucketName, bucketName, '2016/08/11', '15:30', description, callback); + + assert(callback.calledTwice, 'callback called twice'); + assert.equal(callback.secondCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.secondCall.args[0], 'callback did not receive error'); + assert.strictEqual(callback.secondCall.args[1], sample.mocks.transferJob, 'callback received transfer job'); + assert.equal(sample.mocks.storagetransfer.transferJobs.create.secondCall.args[0].resource.description, description, 'description was set'); + }); + + it('should require "srcBucketName"', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.createTransferJob(null, null, null, null, null, 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, '"srcBucketName" is required!', 'error has correct message'); + }); + + it('should require "destBucketName"', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.createTransferJob(bucketName, null, null, null, null, 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, '"destBucketName" is required!', 'error has correct message'); + }); + + it('should handle auth error', function () { + var error = new Error('error'); + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.googleapis.auth.getApplicationDefault.callsArgWith(0, error); + + sample.program.createTransferJob(bucketName, bucketName, 'time', 'date', null, 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'); + }); + + it('should handle create error', function () { + var error = new Error('error'); + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.storagetransfer.transferJobs.create.callsArgWith(1, error); + + sample.program.createTransferJob(bucketName, bucketName, 'time', 'date', null, 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 a transfer job', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.getTransferJob(jobName, callback); + + 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.transferJob, 'callback received transfer job'); + }); + + it('should require "jobName"', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.getTransferJob(null, 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, '"jobName" is required!', 'error has correct message'); + }); + + it('should handle auth error', function () { + var error = new Error('error'); + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.googleapis.auth.getApplicationDefault.callsArgWith(0, error); + + sample.program.getTransferJob(jobName, 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'); + }); + + it('should handle get error', function () { + var error = new Error('error'); + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.storagetransfer.transferJobs.get.callsArgWith(1, error); + + sample.program.getTransferJob(jobName, 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('set', function () { + it('should update a transfer job', function () { + var field = 'status'; + var value = 'DISABLED'; + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.updateTransferJob(jobName, field, value, callback); + + 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.transferJob, 'callback received transfer job'); + + field = 'description'; + value = 'description'; + + sample.program.updateTransferJob(jobName, field, value, callback); + + assert(callback.calledTwice, 'callback called twice'); + assert.equal(callback.secondCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.secondCall.args[0], 'callback did not receive error'); + assert.strictEqual(callback.secondCall.args[1], sample.mocks.transferJob, 'callback received transfer job'); + + field = 'transferSpec'; + value = '{"foo":"bar"}'; + + sample.program.updateTransferJob(jobName, field, value, callback); + + assert(callback.calledThrice, 'callback called thrice'); + assert.equal(callback.thirdCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.thirdCall.args[0], 'callback did not receive error'); + assert.strictEqual(callback.thirdCall.args[1], sample.mocks.transferJob, 'callback received transfer job'); + }); + + it('should require "jobName"', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.updateTransferJob(null, null, null, 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, '"jobName" is required!', 'error has correct message'); + }); + + it('should require "field"', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.updateTransferJob(jobName, null, null, 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, '"field" is required!', 'error has correct message'); + }); + + it('should require "value"', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.updateTransferJob(jobName, 'field', null, 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, '"value" is required!', 'error has correct message'); + }); + + it('should handle auth error', function () { + var error = new Error('error'); + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.googleapis.auth.getApplicationDefault.callsArgWith(0, error); + + sample.program.updateTransferJob(jobName, 'field', 'value', 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'); + }); + + it('should handle patch error', function () { + var error = new Error('error'); + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.storagetransfer.transferJobs.patch.callsArgWith(1, error); + + sample.program.updateTransferJob(jobName, 'field', 'value', 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('list', function () { + it('should list transfer jobs', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.listTransferJobs(callback); + + 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.deepEqual(callback.firstCall.args[1], [sample.mocks.transferJob], 'callback received transfer jobs'); + + sample.mocks.storagetransfer.transferJobs.list.callsArgWith(1, null, {}); + sample.program.listTransferJobs(callback); + + assert(callback.calledTwice, 'callback called twice'); + assert.equal(callback.secondCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.secondCall.args[0], 'callback did not receive error'); + assert.deepEqual(callback.secondCall.args[1], [], 'callback received no transfer jobs'); + }); + + it('should handle auth error', function () { + var error = new Error('error'); + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.googleapis.auth.getApplicationDefault.callsArgWith(0, error); + + sample.program.listTransferJobs(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'); + }); + + it('should handle list error', function () { + var error = new Error('error'); + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.storagetransfer.transferJobs.list.callsArgWith(1, error); + + sample.program.listTransferJobs(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('operations', function () { + describe('list', function () { + it('should list transfer operations', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.listTransferOperations(undefined, callback); + + 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.deepEqual(callback.firstCall.args[1], [sample.mocks.transferOperation], 'callback received transfer operations'); + + sample.program.listTransferOperations(jobName, callback); + + assert(callback.calledTwice, 'callback called twice'); + assert.equal(callback.secondCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.secondCall.args[0], 'callback did not receive error'); + assert.deepEqual(callback.secondCall.args[1], [sample.mocks.transferOperation], 'callback received transfer operations'); + + sample.mocks.storagetransfer.transferOperations.list.callsArgWith(1, null, {}); + sample.program.listTransferOperations(jobName, callback); + + assert(callback.calledThrice, 'callback called thrice'); + assert.equal(callback.thirdCall.args.length, 2, 'callback received 2 arguments'); + assert.ifError(callback.thirdCall.args[0], 'callback did not receive error'); + assert.deepEqual(callback.thirdCall.args[1], [], 'callback received no transfer operations'); + }); + + it('should handle auth error', function () { + var error = new Error('error'); + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.googleapis.auth.getApplicationDefault.callsArgWith(0, error); + + sample.program.listTransferOperations(undefined, 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'); + }); + + it('should handle list error', function () { + var error = new Error('error'); + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.storagetransfer.transferOperations.list.callsArgWith(1, error); + + sample.program.listTransferOperations(undefined, 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 a transfer operation', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.getTransferOperation(transferOperationName, callback); + + 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.transferOperation, 'callback received transfer operation'); + }); + + it('should require "transferOperationName"', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.getTransferOperation(null, 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, '"transferOperationName" is required!', 'error has correct message'); + }); + + it('should handle auth error', function () { + var error = new Error('error'); + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.googleapis.auth.getApplicationDefault.callsArgWith(0, error); + + sample.program.getTransferOperation(jobName, 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'); + }); + + it('should handle get error', function () { + var error = new Error('error'); + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.storagetransfer.transferOperations.get.callsArgWith(1, error); + + sample.program.getTransferOperation(jobName, 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('pause', function () { + it('should pause a transfer operation', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.pauseTransferOperation(transferOperationName, callback); + + 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'); + }); + + it('should require "transferOperationName"', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.pauseTransferOperation(null, 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, '"transferOperationName" is required!', 'error has correct message'); + }); + + it('should handle auth error', function () { + var error = new Error('error'); + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.googleapis.auth.getApplicationDefault.callsArgWith(0, error); + + sample.program.pauseTransferOperation(jobName, 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'); + }); + + it('should handle pause error', function () { + var error = new Error('error'); + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.storagetransfer.transferOperations.pause.callsArgWith(1, error); + + sample.program.pauseTransferOperation(jobName, 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('resume', function () { + it('should resume a transfer operation', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.resumeTransferOperation(transferOperationName, callback); + + 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'); + }); + + it('should require "transferOperationName"', function () { + var sample = getSample(); + var callback = sinon.stub(); + + sample.program.resumeTransferOperation(null, 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, '"transferOperationName" is required!', 'error has correct message'); + }); + + it('should handle auth error', function () { + var error = new Error('error'); + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.googleapis.auth.getApplicationDefault.callsArgWith(0, error); + + sample.program.resumeTransferOperation(jobName, 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'); + }); + + it('should handle resume error', function () { + var error = new Error('error'); + var sample = getSample(); + var callback = sinon.stub(); + sample.mocks.storagetransfer.transferOperations.resume.callsArgWith(1, error); + + sample.program.resumeTransferOperation(jobName, 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('printUsage', function () { + it('should print usage', function () { + var program = getSample().program; + + program.printUsage(); + + assert(console.log.calledWith('Usage: node encryption RESOURCE COMMAND [ARGS...]')); + assert(console.log.calledWith('\nResources:\n')); + assert(console.log.calledWith(' jobs')); + assert(console.log.calledWith('\n\tCommands:\n')); + assert(console.log.calledWith('\t\tcreate SRC_BUCKET_NAME DEST_BUCKET_NAME DATE TIME [DESCRIPTION]')); + assert(console.log.calledWith('\t\tget JOB_NAME')); + assert(console.log.calledWith('\t\tlist')); + assert(console.log.calledWith('\t\tset JOB_NAME FIELD VALUE')); + assert(console.log.calledWith('\n operations')); + assert(console.log.calledWith('\n\tCommands:\n')); + assert(console.log.calledWith('\t\tlist [JOB_NAME]')); + assert(console.log.calledWith('\t\tget TRANSFER_NAME')); + assert(console.log.calledWith('\t\tpause TRANSFER_NAME')); + assert(console.log.calledWith('\t\tresume TRANSFER_NAME')); + assert(console.log.calledWith('\nExamples:\n')); + assert(console.log.calledWith('\tnode transfer jobs create my-bucket my-other-bucket 2016/08/12 16:30 "Move my files"')); + assert(console.log.calledWith('\tnode transfer jobs get transferJobs/123456789012345678')); + assert(console.log.calledWith('\tnode transfer jobs list')); + assert(console.log.calledWith('\tnode transfer jobs set transferJobs/123456789012345678 description "My new description"')); + assert(console.log.calledWith('\tnode transfer jobs set transferJobs/123456789012345678 status DISABLED')); + assert(console.log.calledWith('\tnode transfer operations list')); + assert(console.log.calledWith('\tnode transfer operations list transferJobs/123456789012345678')); + assert(console.log.calledWith('\tnode transfer operations get transferOperations/123456789012345678')); + assert(console.log.calledWith('\tnode transfer operations pause transferOperations/123456789012345678')); + assert(console.log.calledWith('\tnode transfer operations resume transferOperations/123456789012345678')); + }); + }); + + describe('main', function () { + it('should call the right commands', function () { + var program = getSample().program; + + sinon.stub(program, 'createTransferJob'); + program.main(['jobs', 'create']); + assert(program.createTransferJob.calledOnce); + + sinon.stub(program, 'getTransferJob'); + program.main(['jobs', 'get']); + assert(program.getTransferJob.calledOnce); + + sinon.stub(program, 'listTransferJobs'); + program.main(['jobs', 'list']); + assert(program.listTransferJobs.calledOnce); + + sinon.stub(program, 'updateTransferJob'); + program.main(['jobs', 'set']); + assert(program.updateTransferJob.calledOnce); + + sinon.stub(program, 'listTransferOperations'); + program.main(['operations', 'list']); + assert(program.listTransferOperations.calledOnce); + + sinon.stub(program, 'getTransferOperation'); + program.main(['operations', 'get']); + assert(program.getTransferOperation.calledOnce); + + sinon.stub(program, 'pauseTransferOperation'); + program.main(['operations', 'pause']); + assert(program.pauseTransferOperation.calledOnce); + + sinon.stub(program, 'resumeTransferOperation'); + program.main(['operations', 'resume']); + assert(program.resumeTransferOperation.calledOnce); + + sinon.stub(program, 'printUsage'); + program.main(['--help']); + assert(program.printUsage.calledOnce); + + program.main(['jobs']); + assert(program.printUsage.calledTwice); + + program.main(['operations']); + assert(program.printUsage.calledThrice); + }); + }); +}); diff --git a/storage/transfer.js b/storage/transfer.js new file mode 100644 index 0000000000..dd1a1246b1 --- /dev/null +++ b/storage/transfer.js @@ -0,0 +1,453 @@ +// 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] +var moment = require('moment'); +var google = require('googleapis'); + +// Instantiate a storage client +var storagetransfer = google.storagetransfer('v1'); +// [END setup] + +// [START auth] +function auth (callback) { + google.auth.getApplicationDefault(function (err, authClient) { + if (err) { + return callback(err); + } + + // The createScopedRequired method returns true when running on GAE or a + // local developer machine. In that case, the desired scopes must be passed + // in manually. When the code is running in GCE or a Managed VM, the scopes + // are pulled from the GCE metadata server. + // See https://cloud.google.com/compute/docs/authentication for more + // information. + if (authClient.createScopedRequired && authClient.createScopedRequired()) { + // Scopes can be specified either as an array or as a single, + // space-delimited string. + authClient = authClient.createScoped([ + 'https://www.googleapis.com/auth/cloud-platform' + ]); + } + callback(null, authClient); + }); +} +// [END auth] + +// [START create_transfer_job] +/** + * Review the transfer operations associated with a transfer job. + * + * @param {string} srcBucketName The name of the source bucket. + * @param {string} destBucketName The name of the destination bucket. + * @param {string} [description] Optional description for the new transfer job. + * @param {function} callback The callback function. + */ +function createTransferJob (srcBucketName, destBucketName, date, time, description, callback) { + if (!srcBucketName) { + return callback(new Error('"srcBucketName" is required!')); + } else if (!destBucketName) { + return callback(new Error('"destBucketName" is required!')); + } + + var startDate = moment(date, 'YYYY/MM/DD'); + var transferTime = moment(time, 'HH:mm'); + + auth(function (err, authClient) { + if (err) { + return callback(err); + } + + var transferJob = { + projectId: process.env.GCLOUD_PROJECT, + status: 'ENABLED', + transferSpec: { + gcsDataSource: { + bucketName: srcBucketName + }, + gcsDataSink: { + bucketName: destBucketName + }, + transferOptions: { + deleteObjectsFromSourceAfterTransfer: false + } + }, + schedule: { + scheduleStartDate: { + year: startDate.year(), + month: startDate.month() + 1, + day: startDate.date() + }, + startTimeOfDay: { + hours: transferTime.hours(), + minutes: transferTime.minutes() + } + } + }; + + if (description) { + transferJob.description = description; + } + + storagetransfer.transferJobs.create({ + auth: authClient, + resource: transferJob + }, function (err, transferJob) { + if (err) { + return callback(err); + } + + console.log('Created transfer job: %s', transferJob.name); + return callback(null, transferJob); + }); + }); +} +// [END create_transfer_job] + +// [START get_transfer_job] +/** + * Get a transfer job. + * + * @param {string} jobName The name of the transfer job to get. + * @param {function} callback The callback function. + */ +function getTransferJob (jobName, callback) { + if (!jobName) { + return callback(new Error('"jobName" is required!')); + } + + auth(function (err, authClient) { + if (err) { + return callback(err); + } + + storagetransfer.transferJobs.get({ + auth: authClient, + projectId: process.env.GCLOUD_PROJECT, + jobName: jobName + }, function (err, transferJob) { + if (err) { + return callback(err); + } + + console.log('Found transfer job: %s', transferJob.name); + return callback(null, transferJob); + }); + }); +} +// [END get_transfer_job] + +// [START update_transfer_job] +/** + * Get a transfer job. + * + * @param {string} jobName The name of the transfer job to get. + * @param {string} field The field to update. Can be description, status, or transferSpec. + * @param {string} value The new value for the field. + * @param {function} callback The callback function. + */ +function updateTransferJob (jobName, field, value, callback) { + if (!jobName) { + return callback(new Error('"jobName" is required!')); + } else if (!field) { + return callback(new Error('"field" is required!')); + } else if (!value) { + return callback(new Error('"value" is required!')); + } + + auth(function (err, authClient) { + if (err) { + return callback(err); + } + + var patchRequest = { + projectId: process.env.GCLOUD_PROJECT, + transferJob: { + name: jobName + }, + updateTransferJobFieldMask: field + }; + + if (field === 'description') { + patchRequest.transferJob.description = value; + } else if (field === 'status') { + patchRequest.transferJob.status = value; + } else if (field === 'transferSpec') { + patchRequest.transferJob.transferSpec = JSON.parse(value); + } + + storagetransfer.transferJobs.patch({ + auth: authClient, + jobName: jobName, + resource: patchRequest + }, function (err, transferJob) { + if (err) { + return callback(err); + } + + console.log('Updated transfer job: %s', transferJob.name); + return callback(null, transferJob); + }); + }); +} +// [END update_transfer_job] + +// [START list_transfer_jobs] +/** + * List transfer jobs for the authenticated project. + * + * @param {function} callback The callback function. + */ +function listTransferJobs (callback) { + auth(function (err, authClient) { + if (err) { + return callback(err); + } + + storagetransfer.transferJobs.list({ + auth: authClient, + filter: JSON.stringify({ project_id: process.env.GCLOUD_PROJECT }) + }, function (err, result) { + if (err) { + return callback(err); + } else if (!result.transferJobs) { + return callback(null, []); + } + + console.log('Found %d jobs!', result.transferJobs.length); + return callback(null, result.transferJobs); + }); + }); +} +// [END list_transfer_jobs] + +// [START list_transfer_operations] +/** + * List transfer operations in the authenticated project. + * + * @param {string} [jobName] An optional job name by which to filter results. + * @param {function} callback The callback function. + */ +function listTransferOperations (jobName, callback) { + auth(function (err, authClient) { + if (err) { + return callback(err); + } + + var filter = { + project_id: process.env.GCLOUD_PROJECT + }; + + if (jobName) { + filter.job_names = [jobName]; + } + + storagetransfer.transferOperations.list({ + name: 'transferOperations', + filter: JSON.stringify(filter), + auth: authClient + }, function (err, result, apiResponse) { + if (err) { + return callback(err); + } else if (!result.operations) { + return callback(null, []); + } + + console.log('Found %d operations!', result.operations.length); + return callback(null, result.operations); + }); + }); +} +// [END list_transfer_operations] + +// [START get_transfer_operation] +/** + * Get the specified transfer operation. + * + * @param {string} transferOperationName The name of the transfer operation. + * @param {function} callback The callback function. + */ +function getTransferOperation (transferOperationName, callback) { + if (!transferOperationName) { + return callback(new Error('"transferOperationName" is required!')); + } + + auth(function (err, authClient) { + if (err) { + return callback(err); + } + + storagetransfer.transferOperations.get({ + name: transferOperationName, + auth: authClient + }, function (err, transferOperation) { + if (err) { + return callback(err); + } + + console.log('Found transfer operation: %s', transferOperation); + return callback(null, transferOperation); + }); + }); +} +// [END get_transfer_operation] + +// [START pause_transfer_operation] +/** + * Pause the specified transfer operation. + * + * @param {string} transferOperationName The name of the transfer operation. + * @param {function} callback The callback function. + */ +function pauseTransferOperation (transferOperationName, callback) { + if (!transferOperationName) { + return callback(new Error('"transferOperationName" is required!')); + } + + auth(function (err, authClient) { + if (err) { + return callback(err); + } + + storagetransfer.transferOperations.pause({ + name: transferOperationName, + auth: authClient + }, function (err) { + if (err) { + return callback(err); + } + + console.log('Paused transfer operation: %s', transferOperationName); + return callback(null); + }); + }); +} +// [END pause_transfer_operation] + +// [START resume_transfer_operation] +/** + * Pause the specified transfer operation. + * + * @param {string} transferOperationName The name of the transfer operation. + * @param {function} callback The callback function. + */ +function resumeTransferOperation (transferOperationName, callback) { + if (!transferOperationName) { + return callback(new Error('"transferOperationName" is required!')); + } + + auth(function (err, authClient) { + if (err) { + return callback(err); + } + + storagetransfer.transferOperations.resume({ + name: transferOperationName, + auth: authClient + }, function (err) { + if (err) { + return callback(err); + } + + console.log('Resumed transfer operation: %s', transferOperationName); + return callback(null); + }); + }); +} +// [END resume_transfer_operation] + +// [START usage] +function printUsage () { + console.log('Usage: node encryption RESOURCE COMMAND [ARGS...]'); + console.log('\nResources:\n'); + console.log(' jobs'); + console.log('\n\tCommands:\n'); + console.log('\t\tcreate SRC_BUCKET_NAME DEST_BUCKET_NAME DATE TIME [DESCRIPTION]'); + console.log('\t\tget JOB_NAME'); + console.log('\t\tlist'); + console.log('\t\tset JOB_NAME FIELD VALUE'); + console.log('\n operations'); + console.log('\n\tCommands:\n'); + console.log('\t\tlist [JOB_NAME]'); + console.log('\t\tget TRANSFER_NAME'); + console.log('\t\tpause TRANSFER_NAME'); + console.log('\t\tresume TRANSFER_NAME'); + console.log('\nExamples:\n'); + console.log('\tnode transfer jobs create my-bucket my-other-bucket 2016/08/12 16:30 "Move my files"'); + console.log('\tnode transfer jobs get transferJobs/123456789012345678'); + console.log('\tnode transfer jobs list'); + console.log('\tnode transfer jobs set transferJobs/123456789012345678 description "My new description"'); + console.log('\tnode transfer jobs set transferJobs/123456789012345678 status DISABLED'); + console.log('\tnode transfer operations list'); + console.log('\tnode transfer operations list transferJobs/123456789012345678'); + console.log('\tnode transfer operations get transferOperations/123456789012345678'); + console.log('\tnode transfer operations pause transferOperations/123456789012345678'); + console.log('\tnode transfer operations resume transferOperations/123456789012345678'); +} +// [END usage] + +// The command-line program +var program = { + createTransferJob: createTransferJob, + getTransferJob: getTransferJob, + listTransferJobs: listTransferJobs, + updateTransferJob: updateTransferJob, + listTransferOperations: listTransferOperations, + getTransferOperation: getTransferOperation, + pauseTransferOperation: pauseTransferOperation, + resumeTransferOperation: resumeTransferOperation, + printUsage: printUsage, + + // Executed when this program is run from the command-line + main: function (args, cb) { + var resource = args.shift(); + var command = args.shift(); + if (resource === 'jobs') { + if (command === 'create') { + this.createTransferJob(args[0], args[1], args[2], args[3], args[4], cb); + } else if (command === 'get') { + this.getTransferJob(args[0], cb); + } else if (command === 'list') { + this.listTransferJobs(cb); + } else if (command === 'set') { + this.updateTransferJob(args[0], args[1], args[2], cb); + } else { + this.printUsage(); + } + } else if (resource === 'operations') { + if (command === 'list') { + this.listTransferOperations(args[0], cb); + } else if (command === 'get') { + this.getTransferOperation(args[0], cb); + } else if (command === 'pause') { + this.pauseTransferOperation(args[0], cb); + } else if (command === 'resume') { + this.resumeTransferOperation(args[0], cb); + } else { + this.printUsage(); + } + } else { + this.printUsage(); + } + } +}; + +if (module === require.main) { + program.main(process.argv.slice(2), console.log); +} +// [END all] + +module.exports = program;