diff --git a/lib/storage/file.js b/lib/storage/file.js index 3c3a4939fe7..aea2487d26e 100644 --- a/lib/storage/file.js +++ b/lib/storage/file.js @@ -1427,6 +1427,37 @@ File.prototype.move = function(destination, callback) { }); }; +/** + * Write arbitrary data to a file. + * + * *This is a convenience method which wraps + * {module:storage/file#createWriteStream}.* + * + * @param {*} data - The data to write to a file. + * @param {object=} options - See {module:storage/file#createWriteStream}'s + * `options` parameter. + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this request + * + * @example + * file.save('This is the contents of the file.', function(err) { + * if (!err) { + * // File written successfully. + * } + * }); + */ +File.prototype.save = function(data, options, callback) { + if (is.fn(options)) { + callback = options; + options = {}; + } + + this.createWriteStream(options) + .on('error', callback) + .on('finish', callback) + .end(data); +}; + /** * This creates a gcs-resumable-upload upload stream. * diff --git a/system-test/storage.js b/system-test/storage.js index a941ad27aa8..59f8d741b57 100644 --- a/system-test/storage.js +++ b/system-test/storage.js @@ -582,6 +582,22 @@ describe('storage', function() { }); }); + describe('simple write', function() { + it('should save arbitrary data', function(done) { + var file = bucket.file('TestFile'); + var data = 'hello'; + + file.save(data, function(err) { + assert.ifError(err); + + file.download(function(err, contents) { + assert.strictEqual(contents.toString(), data); + done(); + }); + }); + }); + }); + describe('stream write', function() { it('should stream write, then remove file (3mb)', function(done) { var file = bucket.file('LargeFile'); diff --git a/test/storage/file.js b/test/storage/file.js index 443c82a7b8c..07b55f537d6 100644 --- a/test/storage/file.js +++ b/test/storage/file.js @@ -2072,6 +2072,68 @@ describe('File', function() { }); }); + describe('save', function() { + var DATA = 'Data!'; + + it('should accept an options object', function(done) { + var options = {}; + + file.createWriteStream = function(options_) { + assert.strictEqual(options_, options); + setImmediate(done); + return new stream.PassThrough(); + }; + + file.save(DATA, options, assert.ifError); + }); + + it('should not require options', function(done) { + file.createWriteStream = function(options_) { + assert.deepEqual(options_, {}); + setImmediate(done); + return new stream.PassThrough(); + }; + + file.save(DATA, assert.ifError); + }); + + it('should register the error listener', function(done) { + file.createWriteStream = function() { + var writeStream = new stream.PassThrough(); + writeStream.on('error', done); + setImmediate(function() { + writeStream.emit('error'); + }); + return writeStream; + }; + + file.save(DATA, assert.ifError); + }); + + it('should register the finish listener', function(done) { + file.createWriteStream = function() { + var writeStream = new stream.PassThrough(); + writeStream.once('finish', done); + return writeStream; + }; + + file.save(DATA, assert.ifError); + }); + + it('should write the data', function(done) { + file.createWriteStream = function() { + var writeStream = new stream.PassThrough(); + writeStream.on('data', function(data) { + assert.strictEqual(data.toString(), DATA); + done(); + }); + return writeStream; + }; + + file.save(DATA, assert.ifError); + }); + }); + describe('startResumableUpload_', function() { describe('starting', function() { it('should start a resumable upload', function(done) {