diff --git a/appengine/disk/.gitignore b/appengine/disk/.gitignore new file mode 100644 index 0000000000..a7ba602ce9 --- /dev/null +++ b/appengine/disk/.gitignore @@ -0,0 +1 @@ +seen.txt \ No newline at end of file diff --git a/appengine/disk/seen.txt b/appengine/disk/seen.txt deleted file mode 100644 index a50fdfecab..0000000000 --- a/appengine/disk/seen.txt +++ /dev/null @@ -1,17 +0,0 @@ -{"timestamp":"2016-07-30T21:42:56.044Z","userIp":"3e48ef9"} -{"timestamp":"2016-07-30T21:43:24.472Z","userIp":"3e48ef9"} -{"timestamp":"2016-07-30T21:43:32.490Z","userIp":"3e48ef9"} -{"timestamp":"2016-07-30T21:43:57.796Z","userIp":"3e48ef9"} -{"timestamp":"2016-07-30T21:44:18.904Z","userIp":"3e48ef9"} -{"timestamp":"2016-07-30T21:45:02.660Z","userIp":"3e48ef9"} -{"timestamp":"2016-07-30T21:47:08.526Z","userIp":"eff8e7c"} -{"timestamp":"2016-07-30T21:47:09.554Z","userIp":"eff8e7c"} -{"timestamp":"2016-07-30T21:47:10.193Z","userIp":"eff8e7c"} -{"timestamp":"2016-07-30T21:47:10.824Z","userIp":"eff8e7c"} -{"timestamp":"2016-07-30T22:48:12.899Z","userIp":"3e48ef9"} -{"timestamp":"2016-07-30T22:54:23.811Z","userIp":"3e48ef9"} -{"timestamp":"2016-07-30T22:57:47.814Z","userIp":"3e48ef9"} -{"timestamp":"2016-07-30T22:58:00.879Z","userIp":"3e48ef9"} -{"timestamp":"2016-07-30T22:58:33.160Z","userIp":"3e48ef9"} -{"timestamp":"2016-07-30T22:59:15.916Z","userIp":"3e48ef9"} -{"timestamp":"2016-07-30T23:03:10.316Z","userIp":"3e48ef9"} diff --git a/package.json b/package.json index 0b045a6b48..0cac61124d 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,8 @@ "describe", "it", "assert", - "sinon" + "sinon", + "uuid" ], "ignore": [ "appengine/bower/public/bower_components", @@ -58,17 +59,17 @@ "all-cover": "npm run pretest && nyc --cache npm run all-test && nyc report --reporter=html && nyc report --reporter=lcov" }, "devDependencies": { - "async": "^1.5.2", + "async": "^2.0.1", "intelli-espower-loader": "^1.0.1", - "mocha": "^2.5.3", + "mocha": "^3.0.2", "nodejs-repo-tools": "git+https://github.com/GoogleCloudPlatform/nodejs-repo-tools.git#bbbb6035d77671eb053dbe6b6f0e3ff983f79639", - "nyc": "^6.4.4", + "nyc": "^7.1.0", "power-assert": "^1.4.1", "proxyquire": "^1.7.10", "request": "^2.72.0", "semistandard": "^8.0.0", "shelljs": "^0.7.3", "sinon": "^1.17.5", - "supertest": "^1.2.0" + "supertest": "^2.0.0" } } diff --git a/storage/README.md b/storage/README.md index 726c8d74b9..5116817041 100644 --- a/storage/README.md +++ b/storage/README.md @@ -12,6 +12,7 @@ amount of data at any time. * [Setup](#setup) * [Samples](#samples) * [Buckets](#buckets) + * [Files](#files) ## Setup @@ -29,7 +30,7 @@ amount of data at any time. View the [documentation][buckets_docs] or the [source code][buckets_code]. -__Usage:__ +__Usage:__ `node buckets --help` ``` Usage: node buckets [COMMAND] [ARGS...] @@ -41,17 +42,30 @@ Commands: delete [BUCKET_NAME] ``` -__Create a bucket:__ +[buckets_docs]: https://cloud.google.com/storage/docs +[buckets_code]: buckets.js + +### Files - node buckets create [BUCKET_NAME] +View the [documentation][files_docs] or the [source code][files_code]. -__List buckets:__ +__Usage:__ `node files --help` - node buckets list +``` +Usage: node files [COMMAND] [ARGS...] -__Delete a bucket:__ +Commands: - node buckets delete [BUCKET_NAME] + list [BUCKET_NAME] + listByPrefix [BUCKET_NAME] [PREFIX] [DELIMITER] + upload [BUCKET_NAME] [FILE_NAME] + download [BUCKET_NAME] [SRC_FILE_NAME] [DEST_FILE_NAME] + delete [BUCKET_NAME] [FILE_NAME] + getMetadata [BUCKET_NAME] [FILE_NAME] + makePublic [BUCKET_NAME] [FILE_NAME] + move [BUCKET_NAME] [SRC_FILE_NAME] [DEST_FILE_NAME] + copy [BUCKET_NAME] [SRC_FILE_NAME] [DEST_BUCKET_NAME] [DEST_FILE_NAME] +``` -[buckets_docs]: https://cloud.google.com/storage/docs/json_api/v1/json-api-nodejs-samples -[buckets_code]: buckets.js +[files_docs]: https://cloud.google.com/storage/docs +[files_code]: files.js diff --git a/storage/buckets.js b/storage/buckets.js index 3ab1c3950d..4d809e9fae 100644 --- a/storage/buckets.js +++ b/storage/buckets.js @@ -32,18 +32,17 @@ var storage = gcloud.storage(); * @param {string} name The name of the new bucket. * @param {function} cb The callback function. */ -function createBucketExample (name, callback) { +function createBucket (name, callback) { if (!name) { return callback(new Error('"name" is required!')); } - // See https://googlecloudplatform.github.io/gcloud-node/#/docs/storage?method=createBucket - storage.createBucket(name, function (err, bucket, apiResponse) { + storage.createBucket(name, function (err, bucket) { if (err) { return callback(err); } - console.log('Created bucket: ' + name); + console.log('Created bucket: %s', name); return callback(null, bucket); }); } @@ -55,15 +54,14 @@ function createBucketExample (name, callback) { * * @param {function} cb The callback function. */ -function listBucketsExample (callback) { - // See https://googlecloudplatform.github.io/gcloud-node/#/docs/storage?method=getBuckets - storage.getBuckets(function (err, buckets, apiResponse) { +function listBuckets (callback) { + storage.getBuckets(function (err, buckets) { if (err) { return callback(err); } - console.log('Found ' + buckets.length + ' buckets!'); - return callback(null, buckets, apiResponse); + console.log('Found %d buckets!', buckets.length); + return callback(null, buckets); }); } // [END list] @@ -75,21 +73,19 @@ function listBucketsExample (callback) { * @param {string} name The name of the bucket to delete. * @param {function} cb The callback function. */ -function deleteBucketExample (name, callback) { +function deleteBucket (name, callback) { if (!name) { return callback(new Error('"name" is required!')); } - // See https://googlecloudplatform.github.io/gcloud-node/#/docs/storage?method=bucket var bucket = storage.bucket(name); - // See https://googlecloudplatform.github.io/gcloud-node/#/docs/storage/bucket?method=delete bucket.delete(function (err, apiResponse) { if (err) { return callback(err); } - console.log('Deleted bucket: ' + name); + console.log('Deleted bucket: %s', name); return callback(null, apiResponse); }); } @@ -105,28 +101,31 @@ function printUsage () { } // [END usage] -// Run the command-line program -function main (args, cb) { - var command = args.shift(); - if (command === 'create') { - createBucketExample(args[0], cb); - } else if (command === 'list') { - listBucketsExample(cb); - } else if (command === 'delete') { - deleteBucketExample(args[0], cb); - } else { - printUsage(); - cb(); +// The command-line program +var program = { + createBucket: createBucket, + listBuckets: listBuckets, + deleteBucket: deleteBucket, + printUsage: printUsage, + + // Executed when this program is run from the command-line + main: function (args, cb) { + var command = args.shift(); + if (command === 'create') { + this.createBucket(args[0], cb); + } else if (command === 'list') { + this.listBuckets(cb); + } else if (command === 'delete') { + this.deleteBucket(args[0], cb); + } else { + this.printUsage(); + } } -} +}; if (module === require.main) { - main(process.argv.slice(2), console.log); + program.main(process.argv.slice(2), console.log); } // [END all] -exports.createBucketExample = createBucketExample; -exports.listBucketsExample = listBucketsExample; -exports.deleteBucketExample = deleteBucketExample; -exports.printUsage = printUsage; -exports.main = main; +module.exports = program; diff --git a/storage/files.js b/storage/files.js new file mode 100644 index 0000000000..c248c06eef --- /dev/null +++ b/storage/files.js @@ -0,0 +1,386 @@ +// 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, gcloud 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/guides/authentication +var gcloud = require('gcloud'); + +// Get a reference to the storage component +var storage = gcloud.storage(); +// [END setup] + +// [START list] +/** + * Lists files in a bucket. + * + * @param {string} name The name of the bucket. + * @param {function} cb The callback function. + */ +function listFiles (name, callback) { + if (!name) { + return callback(new Error('"name" is required!')); + } + + var bucket = storage.bucket(name); + + bucket.getFiles(function (err, files, apiResponse) { + if (err) { + return callback(err); + } + + console.log('Found %d files!', files.length); + return callback(null, files); + }); +} +// [END list] + +// [START listPrefix] +/** + * Lists files in a bucket that match a certain prefix. + * + * This can be used to list all blobs in a "folder", e.g. "public/". + * + * The delimiter argument can be used to restrict the results to only the + * "files" in the given "folder". Without the delimiter, the entire tree under + * the prefix is returned. For example, given these blobs: + * + * /a/1.txt + * /a/b/2.txt + * + * If you just specify prefix = '/a', you'll get back: + * + * /a/1.txt + * /a/b/2.txt + * + * However, if you specify prefix='/a' and delimiter='/', you'll get back: + * + * /a/1.txt + * + * @param {string} name The name of the bucket. + * @param {string} prefix Filter results to objects whose names begin with this prefix. + * @param {string} [delimiter] Results will contain only objects whose names, aside from the prefix, do not contain delimiter. + * @param {function} cb The callback function. + */ +function listFilesWithPrefix (name, prefix, delimiter, callback) { + if (!name) { + return callback(new Error('"name" is required!')); + } else if (!prefix) { + return callback(new Error('"prefix" is required!')); + } + + var bucket = storage.bucket(name); + var options = { + prefix: prefix + }; + if (delimiter && typeof delimiter === 'string') { + options.delimiter = delimiter; + } + + bucket.getFiles(options, function (err, files, apiResponse) { + if (err) { + return callback(err); + } + + console.log('Found %d files!', files.length); + return callback(null, files); + }); +} +// [END listPrefix] + +// [START upload] +/** + * Upload a file to a bucket. + * + * @param {string} name The name of the bucket. + * @param {string} fileName The name of the file. + * @param {function} cb The callback function. + */ +function uploadFile (name, fileName, callback) { + if (!name) { + return callback(new Error('"name" is required!')); + } else if (!fileName) { + return callback(new Error('"fileName" is required!')); + } + + var bucket = storage.bucket(name); + + bucket.upload(fileName, function (err, file) { + if (err) { + return callback(err); + } + + console.log('Uploaded file: %s', fileName); + return callback(null, file); + }); +} +// [END upload] + +// [START download] +/** + * Download a file from a bucket. + * + * @param {string} name The name of the bucket. + * @param {string} srcFileName The source file name. + * @param {string} destFileName The destination file name. + * @param {function} cb The callback function. + */ +function downloadFile (name, srcFileName, destFileName, callback) { + if (!name) { + return callback(new Error('"name" is required!')); + } else if (!srcFileName) { + return callback(new Error('"srcFileName" is required!')); + } else if (!destFileName) { + return callback(new Error('"destFileName" is required!')); + } + + var bucket = storage.bucket(name); + var file = bucket.file(srcFileName); + var options = { + destination: destFileName + }; + + file.download(options, function (err) { + if (err) { + return callback(err); + } + + console.log('Downloaded %s to %s', srcFileName, destFileName); + return callback(null); + }); +} +// [END download] + +// [START delete] +/** + * Delete a file from a bucket. + * + * @param {string} name The name of the bucket. + * @param {string} fileName The file to delete. + * @param {function} cb The callback function. + */ +function deleteFile (name, fileName, callback) { + if (!name) { + return callback(new Error('"name" is required!')); + } else if (!fileName) { + return callback(new Error('"fileName" is required!')); + } + + var bucket = storage.bucket(name); + var file = bucket.file(fileName); + + file.delete(function (err) { + if (err) { + return callback(err); + } + + console.log('Deleted file: %s', fileName); + return callback(null); + }); +} +// [END delete] + +// [START metadata] +/** + * Get a file's metadata. + * + * @param {string} name The name of the bucket. + * @param {string} fileName The name of the file. + * @param {function} cb The callback function. + */ +function getMetadata (name, fileName, callback) { + if (!name) { + return callback(new Error('"name" is required!')); + } else if (!fileName) { + return callback(new Error('"fileName" is required!')); + } + + var bucket = storage.bucket(name); + var file = bucket.file(fileName); + + file.getMetadata(function (err, metadata) { + if (err) { + return callback(err); + } + + console.log('Got metadata for file: %s', fileName); + return callback(null, metadata); + }); +} +// [END metadata] + +// [START public] +/** + * Make a file public. + * + * @param {string} name The name of the bucket. + * @param {string} fileName The name of the file to make public. + * @param {function} cb The callback function. + */ +function makePublic (name, fileName, callback) { + if (!name) { + return callback(new Error('"name" is required!')); + } else if (!fileName) { + return callback(new Error('"fileName" is required!')); + } + + var bucket = storage.bucket(name); + var file = bucket.file(fileName); + + file.makePublic(function (err, apiResponse) { + if (err) { + return callback(err); + } + + console.log('Made %s public!', fileName); + return callback(null, apiResponse); + }); +} +// [END public] + +// [START move] +/** + * Move a file to a new location within the same bucket. + * + * @param {string} name The name of the bucket. + * @param {string} srcFileName The source file name. + * @param {string} destFileName The destination file name. + * @param {function} cb The callback function. + */ +function moveFile (name, srcFileName, destFileName, callback) { + if (!name) { + return callback(new Error('"name" is required!')); + } else if (!srcFileName) { + return callback(new Error('"srcFileName" is required!')); + } else if (!destFileName) { + return callback(new Error('"destFileName" is required!')); + } + + var bucket = storage.bucket(name); + var file = bucket.file(srcFileName); + + file.move(destFileName, function (err, file) { + if (err) { + return callback(err); + } + + console.log('%s moved to %s', srcFileName, destFileName); + return callback(null, file); + }); +} +// [END move] + +// [START copy] +/** + * Copy a file to a new bucket with a new name. + * + * @param {string} name The name of the bucket. + * @param {string} srcFileName The source file name. + * @param {string} destBucketName The destination bucket name. + * @param {string} destFileName The destination file name. + * @param {function} cb The callback function. + */ +function copyFile (name, srcFileName, destBucketName, destFileName, callback) { + if (!name) { + return callback(new Error('"name" is required!')); + } else if (!srcFileName) { + return callback(new Error('"srcFileName" is required!')); + } else if (!destBucketName) { + return callback(new Error('"destBucketName" is required!')); + } else if (!destFileName) { + return callback(new Error('"destFileName" is required!')); + } + + var bucket = storage.bucket(name); + var file = bucket.file(srcFileName); + var newBucket = storage.bucket(destBucketName); + var newFile = newBucket.file(destFileName); + + file.move(newFile, function (err, file) { + if (err) { + return callback(err); + } + + console.log('%s moved to %s in %s', srcFileName, destFileName, destBucketName); + return callback(null, file); + }); +} +// [END copy] + +// [START usage] +function printUsage () { + console.log('Usage: node files [COMMAND] [ARGS...]'); + console.log('\nCommands:\n'); + console.log('\tlist [BUCKET_NAME]'); + console.log('\tlistByPrefix [BUCKET_NAME] [PREFIX] [DELIMITER]'); + console.log('\tupload [BUCKET_NAME] [FILE_NAME]'); + console.log('\tdownload [BUCKET_NAME] [SRC_FILE_NAME] [DEST_FILE_NAME]'); + console.log('\tdelete [BUCKET_NAME] [FILE_NAME]'); + console.log('\tgetMetadata [BUCKET_NAME] [FILE_NAME]'); + console.log('\tmakePublic [BUCKET_NAME] [FILE_NAME]'); + console.log('\tmove [BUCKET_NAME] [SRC_FILE_NAME] [DEST_FILE_NAME]'); + console.log('\tcopy [BUCKET_NAME] [SRC_FILE_NAME] [DEST_BUCKET_NAME] [DEST_FILE_NAME]'); +} +// [END usage] + +// The command-line program +var program = { + listFiles: listFiles, + listFilesWithPrefix: listFilesWithPrefix, + uploadFile: uploadFile, + downloadFile: downloadFile, + deleteFile: deleteFile, + getMetadata: getMetadata, + makePublic: makePublic, + moveFile: moveFile, + copyFile: copyFile, + printUsage: printUsage, + + // Executed when this program is run from the command-line + main: function (args, cb) { + var command = args.shift(); + if (command === 'list') { + this.listFiles(args[0], cb); + } else if (command === 'listByPrefix') { + this.listFilesWithPrefix(args[0], args[1], args[2], cb); + } else if (command === 'upload') { + this.uploadFile(args[0], args[1], cb); + } else if (command === 'download') { + this.downloadFile(args[0], args[1], args[2], cb); + } else if (command === 'delete') { + this.deleteFile(args[0], args[1], cb); + } else if (command === 'getMetadata') { + this.getMetadata(args[0], args[1], cb); + } else if (command === 'makePublic') { + this.makePublic(args[0], args[1], cb); + } else if (command === 'move') { + this.moveFile(args[0], args[1], args[2], cb); + } else if (command === 'copy') { + this.copyFile(args[0], args[1], args[2], args[3], cb); + } else { + this.printUsage(); + } + } +}; + +if (module === require.main) { + program.main(process.argv.slice(2), console.log); +} +// [END all] + +module.exports = program; diff --git a/storage/package.json b/storage/package.json index e8adcd5dbf..5fb5187e32 100644 --- a/storage/package.json +++ b/storage/package.json @@ -12,6 +12,7 @@ "gcloud": "^0.37.0" }, "devDependencies": { - "mocha": "^3.0.1" + "mocha": "^3.0.2", + "node-uuid": "^1.4.7" } } diff --git a/storage/resources/test.txt b/storage/resources/test.txt new file mode 100644 index 0000000000..c57eff55eb --- /dev/null +++ b/storage/resources/test.txt @@ -0,0 +1 @@ +Hello World! \ No newline at end of file diff --git a/storage/system-test/buckets.test.js b/storage/system-test/buckets.test.js index d050dbb2f0..634ed71b4a 100644 --- a/storage/system-test/buckets.test.js +++ b/storage/system-test/buckets.test.js @@ -13,37 +13,37 @@ 'use strict'; +var uuid = require('node-uuid'); var bucketsExample = require('../buckets'); -var bucketName = '' + new Date().getTime() + Math.floor(Math.random() * 100000000); +var bucketName = 'nodejs-docs-samples-test-' + uuid.v4(); describe('storage:buckets', function () { describe('create', function () { it('should create a bucket', function (done) { - bucketsExample.createBucketExample(bucketName, function (err, bucket) { + bucketsExample.createBucket(bucketName, function (err, bucket) { assert.ifError(err); assert.equal(bucket.name, bucketName); - assert(console.log.calledWith('Created bucket: ' + bucketName)); + assert(console.log.calledWith('Created bucket: %s', bucketName)); done(); }); }); }); describe('list', function () { it('should list buckets', function (done) { - bucketsExample.listBucketsExample(function (err, buckets) { + bucketsExample.listBuckets(function (err, buckets) { assert.ifError(err); assert(Array.isArray(buckets)); assert(buckets.length > 0); - assert(console.log.calledWith('Found ' + buckets.length + ' buckets!')); + assert(console.log.calledWith('Found %d buckets!', buckets.length)); done(); }); }); }); describe('delete', function () { it('should delete a bucket', function (done) { - bucketsExample.deleteBucketExample(bucketName, function (err, apiResponse) { + bucketsExample.deleteBucket(bucketName, function (err, apiResponse) { assert.ifError(err); - console.log(apiResponse); - assert(console.log.calledWith('Deleted bucket: ' + bucketName)); + assert(console.log.calledWith('Deleted bucket: %s', bucketName)); done(); }); }); diff --git a/storage/system-test/files.test.js b/storage/system-test/files.test.js new file mode 100644 index 0000000000..0dc55c1449 --- /dev/null +++ b/storage/system-test/files.test.js @@ -0,0 +1,150 @@ +// 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 fs = require('fs'); +var path = require('path'); +var gcloud = require('gcloud'); +var uuid = require('node-uuid'); +var storage = gcloud.storage(); +var filesExample = require('../files'); + +var bucketName = 'nodejs-docs-samples-test-' + uuid.v4(); +var fileName = 'test.txt'; +var movedFileName = 'test2.txt'; +var copiedFileName = 'test3.txt'; +var filePath = path.join(__dirname, '../resources', fileName); +var downloadFilePath = path.join(__dirname, '../resources/downloaded.txt'); + +describe('storage:files', function () { + before(function (done) { + storage.createBucket(bucketName, done); + }); + after(function (done) { + try { + fs.unlinkSync(downloadFilePath); + } catch (err) { + console.log(err); + } + storage.bucket(bucketName).deleteFiles({ force: true }, function (err) { + if (err) { + return done(err); + } + storage.bucket(bucketName).delete(done); + }); + }); + describe('uploadFile', function () { + it('should upload a file', function (done) { + filesExample.uploadFile(bucketName, filePath, function (err, file) { + assert.ifError(err); + assert(file); + assert.equal(file.name, fileName); + assert(console.log.calledWith('Uploaded file: %s', filePath)); + done(); + }); + }); + }); + describe('downloadFile', function () { + it('should download a file', function (done) { + filesExample.downloadFile(bucketName, fileName, downloadFilePath, function (err) { + assert.ifError(err); + assert.doesNotThrow(function () { + fs.statSync(downloadFilePath); + }); + assert(console.log.calledWith('Downloaded %s to %s', fileName, downloadFilePath)); + done(); + }); + }); + }); + describe('moveFile', function () { + it('should move a file', function (done) { + filesExample.moveFile(bucketName, fileName, movedFileName, function (err, file) { + assert.ifError(err); + assert.equal(file.name, movedFileName); + assert(console.log.calledWith('%s moved to %s', fileName, movedFileName)); + done(); + }); + }); + }); + describe('listFiles', function () { + it('should list files', function (done) { + filesExample.listFiles(bucketName, function (err, files) { + assert.ifError(err); + assert(Array.isArray(files)); + assert.equal(files.length, 1); + assert.equal(files[0].name, movedFileName); + assert(console.log.calledWith('Found %d files!', files.length)); + done(); + }); + }); + }); + describe('copyFile', function () { + it('should copy a file', function (done) { + filesExample.copyFile(bucketName, movedFileName, bucketName, copiedFileName, function (err, file) { + assert.ifError(err); + assert.equal(file.name, copiedFileName); + assert(console.log.calledWith('%s moved to %s in %s', movedFileName, copiedFileName, bucketName)); + done(); + }); + }); + }); + describe('listFilesWithPrefix', function () { + it('should list files by a prefix', function (done) { + filesExample.listFilesWithPrefix(bucketName, 'test', undefined, function (err, files) { + assert.ifError(err); + assert(Array.isArray(files)); + assert.equal(files.length, 1); + assert.equal(files[0].name, copiedFileName); + assert(console.log.calledWith('Found %d files!', files.length)); + filesExample.listFilesWithPrefix(bucketName, 'foo', undefined, function (err, files) { + assert.ifError(err); + assert(Array.isArray(files)); + assert.equal(files.length, 0); + assert(console.log.calledWith('Found %d files!', files.length)); + done(); + }); + }); + }); + }); + describe('makePublic', function () { + it('should make a file public', function (done) { + filesExample.makePublic(bucketName, copiedFileName, function (err, apiResponse) { + assert.ifError(err); + assert(apiResponse); + assert(console.log.calledWith('Made %s public!', copiedFileName)); + done(); + }); + }); + }); + describe('getMetadata', function () { + it('should get metadata for a file', function (done) { + filesExample.getMetadata(bucketName, copiedFileName, function (err, metadata) { + assert.ifError(err); + assert(metadata); + assert.equal(metadata.name, copiedFileName); + assert(console.log.calledWith('Got metadata for file: %s', copiedFileName)); + done(); + }); + }); + }); + describe('deleteFile', function () { + it('should delete a file', function (done) { + filesExample.deleteFile(bucketName, copiedFileName, function (err) { + assert.ifError(err); + assert(console.log.calledWith('Deleted file: %s', copiedFileName)); + done(); + }); + }); + }); +}); diff --git a/storage/test/buckets.test.js b/storage/test/buckets.test.js index 546cc0fcdc..f80b60fa70 100644 --- a/storage/test/buckets.test.js +++ b/storage/test/buckets.test.js @@ -52,16 +52,16 @@ describe('storage:buckets', function () { it('should create a bucket', function () { var bucketsSample = getSample(); - bucketsSample.sample.createBucketExample(bucketName, function (err, bucket) { + bucketsSample.sample.createBucket(bucketName, function (err, bucket) { assert.ifError(err); assert.strictEqual(bucket, bucketsSample.mocks.buckets[0]); - assert(console.log.calledWith('Created bucket: ' + bucketName)); + assert(console.log.calledWith('Created bucket: %s', bucketName)); }); }); it('should require name', function () { var bucketsSample = getSample(); - bucketsSample.sample.createBucketExample(undefined, function (err, bucket) { + bucketsSample.sample.createBucket(undefined, function (err, bucket) { assert(err); assert(err.message = '"name" is required!'); assert.equal(bucket, undefined); @@ -72,7 +72,7 @@ describe('storage:buckets', function () { var bucketsSample = getSample(); bucketsSample.mocks.storage.createBucket = sinon.stub().callsArgWith(1, error); - bucketsSample.sample.createBucketExample(bucketName, function (err, bucket) { + bucketsSample.sample.createBucket(bucketName, function (err, bucket) { assert.equal(err, error); assert.equal(bucket, undefined); }); @@ -82,10 +82,10 @@ describe('storage:buckets', function () { it('should list buckets', function () { var bucketsSample = getSample(); - bucketsSample.sample.listBucketsExample(function (err, buckets) { + bucketsSample.sample.listBuckets(function (err, buckets) { assert.ifError(err); assert.strictEqual(buckets, bucketsSample.mocks.buckets); - assert(console.log.calledWith('Found 1 buckets!')); + assert(console.log.calledWith('Found %d buckets!', bucketsSample.mocks.buckets.length)); }); }); it('should handle error', function () { @@ -93,7 +93,7 @@ describe('storage:buckets', function () { var bucketsSample = getSample(); bucketsSample.mocks.storage.getBuckets = sinon.stub().callsArgWith(0, error); - bucketsSample.sample.listBucketsExample(function (err, buckets) { + bucketsSample.sample.listBuckets(function (err, buckets) { assert.equal(err, error); assert.equal(buckets, undefined); }); @@ -103,16 +103,16 @@ describe('storage:buckets', function () { it('should delete a bucket', function () { var bucketsSample = getSample(); - bucketsSample.sample.deleteBucketExample(bucketName, function (err, apiResponse) { + bucketsSample.sample.deleteBucket(bucketName, function (err, apiResponse) { assert.ifError(err); assert.equal(bucketsSample.mocks.storage.bucket.firstCall.args[0], bucketName); - assert(console.log.calledWith('Deleted bucket: ' + bucketName)); + assert(console.log.calledWith('Deleted bucket: %s', bucketName)); }); }); it('should require name', function () { var bucketsSample = getSample(); - bucketsSample.sample.deleteBucketExample(undefined, function (err, apiResponse) { + bucketsSample.sample.deleteBucket(undefined, function (err, apiResponse) { assert(err); assert(err.message = '"name" is required!'); assert.equal(apiResponse, undefined); @@ -123,40 +123,12 @@ describe('storage:buckets', function () { var bucketsSample = getSample(); bucketsSample.mocks.bucket.delete = sinon.stub().callsArgWith(0, error); - bucketsSample.sample.deleteBucketExample(bucketName, function (err, apiResponse) { + bucketsSample.sample.deleteBucket(bucketName, function (err, apiResponse) { assert.equal(err, error); assert.equal(apiResponse, undefined); }); }); }); - describe('main', function () { - it('should call the right commands', function () { - var bucketsSample = getSample(); - - bucketsSample.sample.main(['create', bucketName], function (err, bucket) { - assert.ifError(err); - assert.strictEqual(bucket, bucketsSample.mocks.buckets[0]); - assert(console.log.calledWith('Created bucket: ' + bucketName)); - }); - bucketsSample.sample.main(['list'], function (err, buckets) { - assert.ifError(err); - assert.strictEqual(buckets, bucketsSample.mocks.buckets); - assert(console.log.calledWith('Found 1 buckets!')); - }); - bucketsSample.sample.main(['delete', bucketName], function (err, apiResponse) { - assert.ifError(err); - assert.equal(bucketsSample.mocks.storage.bucket.firstCall.args[0], bucketName); - assert(console.log.calledWith('Deleted bucket: ' + bucketName)); - }); - bucketsSample.sample.main(['foo'], function () { - assert(console.log.calledWith('Usage: node buckets [COMMAND] [ARGS...]')); - assert(console.log.calledWith('\nCommands:\n')); - assert(console.log.calledWith('\tcreate [BUCKET_NAME]')); - assert(console.log.calledWith('\tlist')); - assert(console.log.calledWith('\tdelete [BUCKET_NAME]')); - }); - }); - }); describe('printUsage', function () { it('should print usage', function () { var bucketsSample = getSample(); @@ -170,4 +142,25 @@ describe('storage:buckets', function () { assert(console.log.calledWith('\tdelete [BUCKET_NAME]')); }); }); + describe('main', function () { + it('should call the right commands', function () { + var program = getSample().sample; + + sinon.stub(program, 'createBucket'); + program.main(['create']); + assert(program.createBucket.calledOnce); + + sinon.stub(program, 'listBuckets'); + program.main(['list']); + assert(program.listBuckets.calledOnce); + + sinon.stub(program, 'deleteBucket'); + program.main(['delete']); + assert(program.deleteBucket.calledOnce); + + sinon.stub(program, 'printUsage'); + program.main(['--help']); + assert(program.printUsage.calledOnce); + }); + }); }); diff --git a/storage/test/files.test.js b/storage/test/files.test.js new file mode 100644 index 0000000000..ba21df7125 --- /dev/null +++ b/storage/test/files.test.js @@ -0,0 +1,482 @@ +// 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'; + +function getSample () { + var filesMock = [ + { + id: 'foo', + name: 'foo' + } + ]; + var fileMock = { + download: sinon.stub().callsArgWith(1, null), + getMetadata: sinon.stub().callsArgWith(0, null, { foo: 'bar' }), + makePublic: sinon.stub().callsArgWith(0, null), + delete: sinon.stub().callsArgWith(0, null), + move: sinon.stub().callsArgWith(1, null, filesMock[0]) + }; + var bucketMock = { + getFiles: sinon.stub().callsArgWith(0, null, filesMock, null, filesMock), + file: sinon.stub().returns(fileMock), + upload: sinon.stub().callsArgWith(1, null, filesMock[0]) + }; + var storageMock = { + bucket: sinon.stub().returns(bucketMock) + }; + var gcloudMock = { + storage: sinon.stub().returns(storageMock) + }; + return { + sample: proxyquire('../files', { + gcloud: gcloudMock + }), + mocks: { + gcloud: gcloudMock, + storage: storageMock, + files: filesMock, + file: fileMock, + bucket: bucketMock + } + }; +} + +describe('storage:files', function () { + describe('list', function () { + it('should list files', function () { + var filesSample = getSample(); + + filesSample.sample.listFiles(bucketName, function (err, files) { + assert.ifError(err); + assert.strictEqual(files, filesSample.mocks.files); + assert(console.log.calledWith('Found %d files!', filesSample.mocks.files.length)); + }); + }); + it('should require name', function () { + var filesSample = getSample(); + + filesSample.sample.listFiles(undefined, function (err, files) { + assert(err); + assert(err.message = '"name" is required!'); + assert.equal(files, undefined); + }); + }); + it('should handle error', function () { + var error = 'listError'; + var filesSample = getSample(); + filesSample.mocks.bucket.getFiles = sinon.stub().callsArgWith(0, error); + + filesSample.sample.listFiles(bucketName, function (err, files) { + assert.equal(err, error); + assert.equal(files, undefined); + }); + }); + }); + describe('listWithPrefix', function () { + it('should list files with prefix', function () { + var filesSample = getSample(); + filesSample.mocks.bucket.getFiles = sinon.stub().callsArgWith(1, null, filesSample.mocks.files); + + filesSample.sample.listFilesWithPrefix(bucketName, '/a', undefined, function (err, files) { + assert.ifError(err); + assert.strictEqual(files, filesSample.mocks.files); + assert(console.log.calledWith('Found %d files!', filesSample.mocks.files.length)); + }); + }); + it('should require name', function () { + var filesSample = getSample(); + + filesSample.sample.listFilesWithPrefix(undefined, undefined, undefined, function (err, files) { + assert(err); + assert(err.message = '"name" is required!'); + assert.equal(files, undefined); + }); + }); + it('should require prefix', function () { + var filesSample = getSample(); + + filesSample.sample.listFilesWithPrefix(bucketName, undefined, undefined, function (err, files) { + assert(err); + assert(err.message = '"prefix" is required!'); + assert.equal(files, undefined); + }); + }); + it('should handle error', function () { + var error = 'listError'; + var filesSample = getSample(); + filesSample.mocks.bucket.getFiles = sinon.stub().callsArgWith(1, error); + + filesSample.sample.listFilesWithPrefix(bucketName, '/a', undefined, function (err, files) { + assert.equal(err, error); + assert.equal(files, undefined); + }); + }); + }); + describe('uploadFile', function () { + var fileName = 'test.txt'; + it('should upload a file', function () { + var filesSample = getSample(); + + filesSample.sample.uploadFile(bucketName, fileName, function (err, file) { + assert.ifError(err); + assert.strictEqual(file, filesSample.mocks.files[0]); + assert(console.log.calledWith('Uploaded file: %s', fileName)); + }); + }); + it('should require name', function () { + var filesSample = getSample(); + + filesSample.sample.uploadFile(undefined, undefined, function (err, file) { + assert(err); + assert(err.message = '"name" is required!'); + assert.equal(file, undefined); + }); + }); + it('should require fileName', function () { + var filesSample = getSample(); + + filesSample.sample.uploadFile(bucketName, undefined, function (err, file) { + assert(err); + assert(err.message = '"fileName" is required!'); + assert.equal(file, undefined); + }); + }); + it('should handle error', function () { + var error = 'uploadError'; + var filesSample = getSample(); + filesSample.mocks.bucket.upload = sinon.stub().callsArgWith(1, error); + + filesSample.sample.uploadFile(bucketName, fileName, function (err, file) { + assert.equal(err, error); + assert.equal(file, undefined); + }); + }); + }); + describe('downloadFile', function () { + var fileName = 'test.txt'; + it('should download a file', function () { + var filesSample = getSample(); + + filesSample.sample.downloadFile(bucketName, fileName, fileName, function (err) { + assert.ifError(err); + assert(console.log.calledWith('Downloaded %s to %s', fileName, fileName)); + }); + }); + it('should require name', function () { + var filesSample = getSample(); + + filesSample.sample.downloadFile(undefined, undefined, undefined, function (err) { + assert(err); + assert(err.message = '"name" is required!'); + }); + }); + it('should require srcFileName', function () { + var filesSample = getSample(); + + filesSample.sample.downloadFile(bucketName, undefined, undefined, function (err) { + assert(err); + assert(err.message = '"srcFileName" is required!'); + }); + }); + it('should require destFileName', function () { + var filesSample = getSample(); + + filesSample.sample.downloadFile(bucketName, fileName, undefined, function (err) { + assert(err); + assert(err.message = '"destFileName" is required!'); + }); + }); + it('should handle error', function () { + var error = 'downloadError'; + var filesSample = getSample(); + filesSample.mocks.file.download = sinon.stub().callsArgWith(1, error); + + filesSample.sample.downloadFile(bucketName, fileName, fileName, function (err) { + assert.equal(err, error); + }); + }); + }); + describe('deleteFile', function () { + var fileName = 'test.txt'; + it('should delete a file', function () { + var filesSample = getSample(); + + filesSample.sample.deleteFile(bucketName, fileName, function (err) { + assert.ifError(err); + assert(console.log.calledWith('Deleted file: %s', fileName)); + }); + }); + it('should require name', function () { + var filesSample = getSample(); + + filesSample.sample.deleteFile(undefined, undefined, function (err) { + assert(err); + assert(err.message = '"name" is required!'); + }); + }); + it('should require fileName', function () { + var filesSample = getSample(); + + filesSample.sample.deleteFile(bucketName, undefined, function (err) { + assert(err); + assert(err.message = '"fileName" is required!'); + }); + }); + it('should handle error', function () { + var error = 'deleteError'; + var filesSample = getSample(); + filesSample.mocks.file.delete = sinon.stub().callsArgWith(0, error); + + filesSample.sample.deleteFile(bucketName, fileName, function (err) { + assert.equal(err, error); + }); + }); + }); + describe('getMetadata', function () { + var fileName = 'test.txt'; + it('should get metadata for a file', function () { + var filesSample = getSample(); + + filesSample.sample.getMetadata(bucketName, fileName, function (err, metadata) { + assert.ifError(err); + assert.deepEqual(metadata, { foo: 'bar' }); + assert(console.log.calledWith('Got metadata for file: %s', fileName)); + }); + }); + it('should require name', function () { + var filesSample = getSample(); + + filesSample.sample.getMetadata(undefined, undefined, function (err) { + assert(err); + assert(err.message = '"name" is required!'); + }); + }); + it('should require fileName', function () { + var filesSample = getSample(); + + filesSample.sample.getMetadata(bucketName, undefined, function (err) { + assert(err); + assert(err.message = '"fileName" is required!'); + }); + }); + it('should handle error', function () { + var error = 'getMetadataError'; + var filesSample = getSample(); + filesSample.mocks.file.getMetadata = sinon.stub().callsArgWith(0, error); + + filesSample.sample.getMetadata(bucketName, fileName, function (err) { + assert.equal(err, error); + }); + }); + }); + describe('makePublic', function () { + var fileName = 'test.txt'; + it('should make a file public', function () { + var filesSample = getSample(); + + filesSample.sample.makePublic(bucketName, fileName, function (err) { + assert.ifError(err); + assert(console.log.calledWith('Made %s public!', fileName)); + }); + }); + it('should require name', function () { + var filesSample = getSample(); + + filesSample.sample.makePublic(undefined, undefined, function (err) { + assert(err); + assert(err.message = '"name" is required!'); + }); + }); + it('should require fileName', function () { + var filesSample = getSample(); + + filesSample.sample.makePublic(bucketName, undefined, function (err) { + assert(err); + assert(err.message = '"fileName" is required!'); + }); + }); + it('should handle error', function () { + var error = 'makePublicError'; + var filesSample = getSample(); + filesSample.mocks.file.makePublic = sinon.stub().callsArgWith(0, error); + + filesSample.sample.makePublic(bucketName, fileName, function (err) { + assert.equal(err, error); + }); + }); + }); + describe('moveFile', function () { + var fileName = 'test.txt'; + it('should move a file', function () { + var filesSample = getSample(); + + filesSample.sample.moveFile(bucketName, fileName, fileName, function (err) { + assert.ifError(err); + assert(console.log.calledWith('%s moved to %s', fileName, fileName)); + }); + }); + it('should require name', function () { + var filesSample = getSample(); + + filesSample.sample.moveFile(undefined, undefined, undefined, function (err) { + assert(err); + assert(err.message = '"name" is required!'); + }); + }); + it('should require srcFileName', function () { + var filesSample = getSample(); + + filesSample.sample.moveFile(bucketName, undefined, undefined, function (err) { + assert(err); + assert(err.message = '"srcFileName" is required!'); + }); + }); + it('should require destFileName', function () { + var filesSample = getSample(); + + filesSample.sample.moveFile(bucketName, fileName, undefined, function (err) { + assert(err); + assert(err.message = '"destFileName" is required!'); + }); + }); + it('should handle error', function () { + var error = 'moveFileError'; + var filesSample = getSample(); + filesSample.mocks.file.move = sinon.stub().callsArgWith(1, error); + + filesSample.sample.moveFile(bucketName, fileName, fileName, function (err) { + assert.equal(err, error); + }); + }); + }); + describe('copyFile', function () { + var fileName = 'test.txt'; + it('should copy a file', function () { + var filesSample = getSample(); + + filesSample.sample.copyFile(bucketName, fileName, bucketName, fileName, function (err) { + assert.ifError(err); + assert(console.log.calledWith('%s moved to %s in %s', fileName, fileName, bucketName)); + }); + }); + it('should require name', function () { + var filesSample = getSample(); + + filesSample.sample.copyFile(undefined, undefined, undefined, undefined, function (err) { + assert(err); + assert(err.message = '"name" is required!'); + }); + }); + it('should require srcFileName', function () { + var filesSample = getSample(); + + filesSample.sample.copyFile(bucketName, undefined, undefined, undefined, function (err) { + assert(err); + assert(err.message = '"srcFileName" is required!'); + }); + }); + it('should require destBucketName', function () { + var filesSample = getSample(); + + filesSample.sample.copyFile(bucketName, fileName, undefined, undefined, function (err) { + assert(err); + assert(err.message = '"destBucketName" is required!'); + }); + }); + it('should require destFileName', function () { + var filesSample = getSample(); + + filesSample.sample.copyFile(bucketName, fileName, bucketName, undefined, function (err) { + assert(err); + assert(err.message = '"destFileName" is required!'); + }); + }); + it('should handle error', function () { + var error = 'copyFileError'; + var filesSample = getSample(); + filesSample.mocks.file.move = sinon.stub().callsArgWith(1, error); + + filesSample.sample.copyFile(bucketName, fileName, bucketName, fileName, function (err) { + assert.equal(err, error); + }); + }); + }); + describe('printUsage', function () { + it('should print usage', function () { + var filesSample = getSample(); + + filesSample.sample.printUsage(); + + assert(console.log.calledWith('Usage: node files [COMMAND] [ARGS...]')); + assert(console.log.calledWith('\nCommands:\n')); + assert(console.log.calledWith('\tlist [BUCKET_NAME]')); + assert(console.log.calledWith('\tlistByPrefix [BUCKET_NAME] [PREFIX] [DELIMITER]')); + assert(console.log.calledWith('\tupload [BUCKET_NAME] [FILE_NAME]')); + assert(console.log.calledWith('\tdownload [BUCKET_NAME] [SRC_FILE_NAME] [DEST_FILE_NAME]')); + assert(console.log.calledWith('\tdelete [BUCKET_NAME] [FILE_NAME]')); + assert(console.log.calledWith('\tgetMetadata [BUCKET_NAME] [FILE_NAME]')); + assert(console.log.calledWith('\tmakePublic [BUCKET_NAME] [FILE_NAME]')); + assert(console.log.calledWith('\tmove [BUCKET_NAME] [SRC_FILE_NAME] [DEST_FILE_NAME]')); + assert(console.log.calledWith('\tcopy [BUCKET_NAME] [SRC_FILE_NAME] [DEST_BUCKET_NAME] [DEST_FILE_NAME]')); + }); + }); + describe('main', function () { + it('should call the right commands', function () { + var program = getSample().sample; + + sinon.stub(program, 'listFiles'); + program.main(['list']); + assert(program.listFiles.calledOnce); + + sinon.stub(program, 'listFilesWithPrefix'); + program.main(['listByPrefix']); + assert(program.listFilesWithPrefix.calledOnce); + + sinon.stub(program, 'uploadFile'); + program.main(['upload']); + assert(program.uploadFile.calledOnce); + + sinon.stub(program, 'downloadFile'); + program.main(['download']); + assert(program.downloadFile.calledOnce); + + sinon.stub(program, 'deleteFile'); + program.main(['delete']); + assert(program.deleteFile.calledOnce); + + sinon.stub(program, 'getMetadata'); + program.main(['getMetadata']); + assert(program.getMetadata.calledOnce); + + sinon.stub(program, 'makePublic'); + program.main(['makePublic']); + assert(program.makePublic.calledOnce); + + sinon.stub(program, 'moveFile'); + program.main(['move']); + assert(program.moveFile.calledOnce); + + sinon.stub(program, 'copyFile'); + program.main(['copy']); + assert(program.copyFile.calledOnce); + + sinon.stub(program, 'printUsage'); + program.main(['--help']); + assert(program.printUsage.calledOnce); + }); + }); +}); diff --git a/system-test/_setup.js b/system-test/_setup.js index 4420032d56..c2c3e4c461 100644 --- a/system-test/_setup.js +++ b/system-test/_setup.js @@ -13,15 +13,31 @@ 'use strict'; -require('../test/_setup'); - var assert = require('power-assert'); var sinon = require('sinon'); global.assert = assert; global.sinon = sinon; +var log = console.log; + beforeEach(function () { assert(process.env.GCLOUD_PROJECT, 'Must set GCLOUD_PROJECT environment variable!'); assert(process.env.GOOGLE_APPLICATION_CREDENTIALS, 'Must set GOOGLE_APPLICATION_CREDENTIALS environment variable!'); + if (process.env.DEBUG) { + sinon.spy(console, 'error'); + sinon.spy(console, 'log'); + } else { + sinon.stub(console, 'error'); + sinon.stub(console, 'log', function (a, b, c) { + if (typeof a === 'string' && a.indexOf('\u001b') !== -1 && typeof b === 'string') { + log.apply(console, arguments); + } + }); + } +}); + +afterEach(function () { + console.error.restore(); + console.log.restore(); }); diff --git a/test/_setup.js b/test/_setup.js index c6483a7956..22fe24d7d6 100644 --- a/test/_setup.js +++ b/test/_setup.js @@ -15,13 +15,17 @@ var assert = require('power-assert'); var sinon = require('sinon'); +var uuid = require('node-uuid'); global.assert = assert; global.sinon = sinon; +global.uuid = uuid; var log = console.log; beforeEach(function () { + assert(process.env.GCLOUD_PROJECT, 'Must set GCLOUD_PROJECT environment variable!'); + assert(process.env.GOOGLE_APPLICATION_CREDENTIALS, 'Must set GOOGLE_APPLICATION_CREDENTIALS environment variable!'); if (process.env.DEBUG) { sinon.spy(console, 'error'); sinon.spy(console, 'log');