From 83a28273d4173ede0213b482062f799b60e6dfb4 Mon Sep 17 00:00:00 2001 From: Matteo Padovano Date: Tue, 16 Oct 2018 00:17:47 +0200 Subject: [PATCH] add support to promise --- lib/providers/filesystem/index.js | 34 +++++++++- lib/storage-service.js | 61 +++++++++++++++--- lib/utils.js | 15 +++++ test/fs.test.js | 104 ++++++++++++++++++++++++++++-- test/storage-service.test.js | 99 ++++++++++++++++++++++++++-- 5 files changed, 291 insertions(+), 22 deletions(-) create mode 100644 lib/utils.js diff --git a/lib/providers/filesystem/index.js b/lib/providers/filesystem/index.js index a941587..23f7249 100644 --- a/lib/providers/filesystem/index.js +++ b/lib/providers/filesystem/index.js @@ -18,6 +18,8 @@ var fs = require('fs'), File = require('./file').File, Container = require('./container').Container; +var utils = require('./../../utils'); + module.exports.storage = module.exports; // To make it consistent with pkgcloud module.exports.File = File; @@ -95,6 +97,8 @@ function populateMetadata(stat, props) { } FileSystemProvider.prototype.getContainers = function(cb) { + cb = cb || utils.createPromiseCallback(); + var self = this; fs.readdir(self.root, function(err, files) { var containers = []; @@ -119,15 +123,20 @@ FileSystemProvider.prototype.getContainers = function(cb) { } }); }); + + return cb.promise; }; FileSystemProvider.prototype.createContainer = function(options, cb) { + cb = cb || utils.createPromiseCallback(); + var self = this; var name = options.name; var dir = path.join(this.root, name); validateName(name, cb) && fs.mkdir(dir, options, function(err) { if (err) { - return cb && cb(err); + cb && cb(err); + return; } fs.stat(dir, function(err, stat) { var container = null; @@ -139,9 +148,13 @@ FileSystemProvider.prototype.createContainer = function(options, cb) { cb && cb(err, container); }); }); + + return cb.promise; }; FileSystemProvider.prototype.destroyContainer = function(containerName, cb) { + cb = cb || utils.createPromiseCallback(); + if (!validateName(containerName, cb)) return; var dir = path.join(this.root, containerName); @@ -160,9 +173,13 @@ FileSystemProvider.prototype.destroyContainer = function(containerName, cb) { } }); }); + + return cb.promise; }; FileSystemProvider.prototype.getContainer = function(containerName, cb) { + cb = cb || utils.createPromiseCallback(); + var self = this; if (!validateName(containerName, cb)) return; var dir = path.join(this.root, containerName); @@ -175,6 +192,8 @@ FileSystemProvider.prototype.getContainer = function(containerName, cb) { } cb && cb(err, container); }); + + return cb.promise; }; // File related functions @@ -252,6 +271,9 @@ FileSystemProvider.prototype.getFiles = function(container, options, cb) { cb = options; options = false; } + + cb = cb || utils.createPromiseCallback(); + var self = this; if (!validateName(container, cb)) return; var dir = path.join(this.root, container); @@ -278,9 +300,13 @@ FileSystemProvider.prototype.getFiles = function(container, options, cb) { } }); }); + + return cb.promise; }; FileSystemProvider.prototype.getFile = function(container, file, cb) { + cb = cb || utils.createPromiseCallback(); + var self = this; if (!validateName(container, cb)) return; if (!validateName(file, cb)) return; @@ -294,6 +320,8 @@ FileSystemProvider.prototype.getFile = function(container, file, cb) { } cb && cb(err, f); }); + + return cb.promise; }; FileSystemProvider.prototype.getUrl = function(options) { @@ -303,9 +331,13 @@ FileSystemProvider.prototype.getUrl = function(options) { }; FileSystemProvider.prototype.removeFile = function(container, file, cb) { + cb = cb || utils.createPromiseCallback(); + if (!validateName(container, cb)) return; if (!validateName(file, cb)) return; var filePath = path.join(this.root, container, file); fs.unlink(filePath, cb); + + return cb.promise; }; diff --git a/lib/storage-service.js b/lib/storage-service.js index aae7d7f..4601f79 100644 --- a/lib/storage-service.js +++ b/lib/storage-service.js @@ -6,6 +6,7 @@ var factory = require('./factory'); var handler = require('./storage-handler'); +var utils = require('./utils'); var storage = require('pkgcloud').storage; var debug = require('debug')('loopback:storage:service'); @@ -64,8 +65,11 @@ function map(obj) { * @callback {Function} callback Callback function * @param {Object|String} err Error string or object * @param {Object[]} containers An array of container metadata objects + * @promise */ StorageService.prototype.getContainers = function(cb) { + cb = cb || utils.createPromiseCallback(); + this.client.getContainers(function(err, containers) { if (err) { cb(err, containers); @@ -75,6 +79,8 @@ StorageService.prototype.getContainers = function(cb) { })); } }); + + return cb.promise; }; /** @@ -85,19 +91,24 @@ StorageService.prototype.getContainers = function(cb) { * @callback {Function} cb Callback function * @param {Object|String} err Error string or object * @param {Object} container Container metadata object + * @promise */ StorageService.prototype.createContainer = function(options, cb) { options = options || {}; + cb = cb || utils.createPromiseCallback(); + if ('object' === typeof options && !(options instanceof storage.Container)) { options.Name = options.name; // Amazon expects Name var Container = factory.getProvider(this.provider).storage.Container; options = new Container(this.client, options); } debug('Creating container with options %o', options); - return this.client.createContainer(options, function(err, container) { + this.client.createContainer(options, function(err, container) { return cb(err, map(container)); }); + + return cb.promise; }; /** @@ -105,9 +116,13 @@ StorageService.prototype.createContainer = function(options, cb) { * @param {String} container Container name. * @callback {Function} callback Callback function. * @param {Object|String} err Error string or object + * @promise */ StorageService.prototype.destroyContainer = function(container, cb) { - return this.client.destroyContainer(container, cb); + cb = cb || utils.createPromiseCallback(); + + this.client.destroyContainer(container, cb); + return cb.promise; }; /** @@ -116,15 +131,20 @@ StorageService.prototype.destroyContainer = function(container, cb) { * @callback {Function} callback Callback function. * @param {Object|String} err Error string or object * @param {Object} container Container metadata object + * @promise */ StorageService.prototype.getContainer = function(container, cb) { - return this.client.getContainer(container, function(err, container) { + cb = cb || utils.createPromiseCallback(); + + this.client.getContainer(container, function(err, container) { if (err && err.code === 'ENOENT') { err.statusCode = err.status = 404; return cb(err); } return cb(err, map(container)); }); + + return cb.promise; }; /** @@ -178,6 +198,7 @@ StorageService.prototype.downloadStream = function(container, file, options) { * @callback {Function} cb Callback function * @param {Object|String} err Error string or object * @param {Object[]} files An array of file metadata objects + * @promise */ StorageService.prototype.getFiles = function(container, options, cb) { if (typeof options === 'function' && !cb) { @@ -185,7 +206,10 @@ StorageService.prototype.getFiles = function(container, options, cb) { cb = options; options = {}; } - return this.client.getFiles(container, options, function(err, files) { + + cb = cb || utils.createPromiseCallback(); + + this.client.getFiles(container, options, function(err, files) { if (err) { cb(err, files); } else { @@ -194,6 +218,8 @@ StorageService.prototype.getFiles = function(container, options, cb) { })); } }); + + return cb.promise; }; /** @@ -203,15 +229,20 @@ StorageService.prototype.getFiles = function(container, options, cb) { * @callback {Function} cb Callback function * @param {Object|String} err Error string or object * @param {Object} file File metadata object + * @promise */ StorageService.prototype.getFile = function(container, file, cb) { - return this.client.getFile(container, file, function(err, f) { + cb = cb || utils.createPromiseCallback(); + + this.client.getFile(container, file, function(err, f) { if (err && err.code === 'ENOENT') { err.statusCode = err.status = 404; return cb(err); } return cb(err, map(f)); }); + + return cb.promise; }; /** @@ -220,9 +251,13 @@ StorageService.prototype.getFile = function(container, file, cb) { * @param {String} file File name * @callback {Function} cb Callback function * @param {Object|String} err Error string or object + * @promise */ StorageService.prototype.removeFile = function(container, file, cb) { - return this.client.removeFile(container, file, cb); + cb = cb || utils.createPromiseCallback(); + + this.client.removeFile(container, file, cb); + return cb.promise; }; /** @@ -232,6 +267,7 @@ StorageService.prototype.removeFile = function(container, file, cb) { * @param {Response} res Response object * @param {Object} [options] Options for upload * @param {Function} cb Callback function + * @promise */ StorageService.prototype.upload = function(container, req, res, options, cb) { debug('Configuring upload with options %o', options); @@ -247,6 +283,9 @@ StorageService.prototype.upload = function(container, req, res, options, cb) { cb = options; options = {}; } + + cb = cb || utils.createPromiseCallback(); + if (this.getFilename && !options.getFilename) { options.getFilename = this.getFilename; } @@ -269,7 +308,9 @@ StorageService.prototype.upload = function(container, req, res, options, cb) { options.container = container; } debug('Upload configured with options %o', options); - return handler.upload(this.client, req, res, options, cb); + + handler.upload(this.client, req, res, options, cb); + return cb.promise; }; /** @@ -279,9 +320,13 @@ StorageService.prototype.upload = function(container, req, res, options, cb) { * @param {Request} req HTTP request * @param {Response} res HTTP response * @param {Function} cb Callback function + * @promise */ StorageService.prototype.download = function(container, file, req, res, cb) { - return handler.download(this.client, req, res, container, file, cb); + cb = cb || utils.createPromiseCallback(); + + handler.download(this.client, req, res, container, file, cb); + return cb.promise; }; StorageService.modelName = 'storage'; diff --git a/lib/utils.js b/lib/utils.js new file mode 100644 index 0000000..ff2275c --- /dev/null +++ b/lib/utils.js @@ -0,0 +1,15 @@ +'use strict'; + +exports.createPromiseCallback = createPromiseCallback; + +function createPromiseCallback() { + var cb; + var promise = new Promise(function(resolve, reject) { + cb = function(err, data) { + if (err) return reject(err); + return resolve(data); + }; + }); + cb.promise = promise; + return cb; +} diff --git a/test/fs.test.js b/test/fs.test.js index 767d6bf..be9aa10 100644 --- a/test/fs.test.js +++ b/test/fs.test.js @@ -45,11 +45,20 @@ describe('FileSystem based storage provider', function() { it('should return an empty list of containers', function(done) { client.getContainers(function(err, containers) { assert(!err); - assert.equal(0, containers.length); + assert.equal(containers.length, 0); done(err, containers); }); }); + it('should return an empty list of containers - promise', function(done) { + client.getContainers() + .then(function(containers) { + assert.equal(containers.length, 0); + done(); + }) + .catch(done); + }); + it('should create a new container', function(done) { client.createContainer({name: 'c1'}, function(err, container) { assert(!err); @@ -58,6 +67,15 @@ describe('FileSystem based storage provider', function() { }); }); + it('should create a new container - promise', function(done) { + client.createContainer({name: 'c3'}) + .then(function(container) { + verifyMetadata(container, 'c3'); + done(); + }) + .catch(done); + }); + it('should get a container c1', function(done) { client.getContainer('c1', function(err, container) { assert(!err); @@ -66,6 +84,15 @@ describe('FileSystem based storage provider', function() { }); }); + it('should get a container c1 - promise', function(done) { + client.getContainer('c1') + .then(function(container) { + verifyMetadata(container, 'c1'); + done(); + }) + .catch(done); + }); + it('should not get a container c2', function(done) { client.getContainer('c2', function(err, container) { assert(err); @@ -73,10 +100,18 @@ describe('FileSystem based storage provider', function() { }); }); + it('should destroy a container c3 - promise', function(done) { + client.destroyContainer('c3') + .then(function(container) { + done(null, container); + }) + .catch(done); + }); + it('should return one container', function(done) { client.getContainers(function(err, containers) { assert(!err); - assert.equal(1, containers.length); + assert.equal(containers.length, 1); done(err, containers); }); }); @@ -167,11 +202,20 @@ describe('FileSystem based storage provider', function() { it('should get files for a container', function(done) { client.getFiles('c1', function(err, files) { assert(!err); - assert.equal(1, files.length); + assert.equal(files.length, 1); done(err, files); }); }); + it('should get files for a container - promise', function(done) { + client.getFiles('c1') + .then(function(files) { + assert.equal(files.length, 1); + done(); + }) + .catch(done); + }); + it('should get a file', function(done) { client.getFile('c1', 'f1.txt', function(err, f) { assert(!err); @@ -181,6 +225,16 @@ describe('FileSystem based storage provider', function() { }); }); + it('should get a file - promise', function(done) { + client.getFile('c1', 'f1.txt') + .then(function(f) { + assert.ok(f); + verifyMetadata(f, 'f1.txt'); + done(); + }) + .catch(done); + }); + it('should remove a file', function(done) { client.removeFile('c1', 'f1.txt', function(err) { assert(!err); @@ -188,29 +242,67 @@ describe('FileSystem based storage provider', function() { }); }); + it('should remove a file - promise', function(done) { + createFile('c1', 'f1.txt').then(function() { + return client.removeFile('c1', 'f1.txt') + .then(function() { + done(); + }); + }) + .catch(done); + }); + it('should get no files from a container', function(done) { client.getFiles('c1', function(err, files) { assert(!err); - assert.equal(0, files.length); + assert.equal(files.length, 0); done(err, files); }); }); + it('should get no files from a container - promise', function(done) { + client.getFiles('c1') + .then(function(files) { + assert.equal(files.length, 0); + done(); + }) + .catch(done); + }); + it('should not get a file from a container', function(done) { client.getFile('c1', 'f2.txt', function(err, f) { assert(err); - assert.equal('ENOENT', err.code); + assert.equal(err.code, 'ENOENT'); assert(!f); done(); }); }); + it('should not get a file from a container - promise', function(done) { + client.getFile('c1', 'f2.txt') + .then(function() { + throw new Error('should not be throw'); + }) + .catch(function(err) { + assert.equal(err.code, 'ENOENT'); + done(); + }); + }); + it('should destroy a container c1', function(done) { client.destroyContainer('c1', function(err, container) { - // console.error(err); assert(!err); done(err, container); }); }); + + function createFile(container, file) { + return new Promise(function(resolve, reject) { + var writer = client.upload({container: container, remote: file}); + fs.createReadStream(path.join(__dirname, 'files/f1.txt')).pipe(writer); + writer.on('finish', resolve); + writer.on('error', reject); + }); + } }); }); diff --git a/test/storage-service.test.js b/test/storage-service.test.js index 0c312dd..17ba691 100644 --- a/test/storage-service.test.js +++ b/test/storage-service.test.js @@ -19,11 +19,20 @@ describe('Storage service', function() { it('should return an empty list of containers', function(done) { storageService.getContainers(function(err, containers) { assert(!err); - assert.equal(0, containers.length); + assert.equal(containers.length, 0); done(err, containers); }); }); + it('should return an empty list of containers - promise', function(done) { + storageService.getContainers() + .then(function(containers) { + assert.equal(containers.length, 0); + done(); + }) + .catch(done); + }); + it('should create a new container', function(done) { storageService.createContainer({name: 'c1'}, function(err, container) { assert(!err); @@ -32,6 +41,15 @@ describe('Storage service', function() { }); }); + it('should create a new container - promise', function(done) { + storageService.createContainer({name: 'c3'}) + .then(function(container) { + assert(container.getMetadata()); + done(); + }) + .catch(done); + }); + it('should get a container c1', function(done) { storageService.getContainer('c1', function(err, container) { assert(!err); @@ -40,6 +58,15 @@ describe('Storage service', function() { }); }); + it('should get a container c1 - promise', function(done) { + storageService.getContainer('c1') + .then(function(container) { + assert(container.getMetadata()); + done(); + }) + .catch(done); + }); + it('should not get a container c2', function(done) { storageService.getContainer('c2', function(err, container) { assert(err); @@ -47,10 +74,18 @@ describe('Storage service', function() { }); }); + it('should destroy a container c3 - promise', function(done) { + storageService.destroyContainer('c3') + .then(function(container) { + done(null, container); + }) + .catch(done); + }); + it('should return one container', function(done) { storageService.getContainers(function(err, containers) { assert(!err); - assert.equal(1, containers.length); + assert.equal(containers.length, 1); done(err, containers); }); }); @@ -104,11 +139,20 @@ describe('Storage service', function() { it('should get files for a container', function(done) { storageService.getFiles('c1', function(err, files) { assert(!err); - assert.equal(1, files.length); + assert.equal(files.length, 1); done(err, files); }); }); + it('should get files for a container - promise', function(done) { + storageService.getFiles('c1') + .then(function(files) { + assert.equal(files.length, 1); + done(); + }) + .catch(done); + }); + it('should get a file', function(done) { storageService.getFile('c1', 'f1.txt', function(err, f) { assert(!err); @@ -118,6 +162,16 @@ describe('Storage service', function() { }); }); + it('should get a file - promise', function(done) { + storageService.getFile('c1', 'f1.txt') + .then(function(f) { + assert.ok(f); + assert(f.getMetadata()); + done(); + }) + .catch(done); + }); + it('should remove a file', function(done) { storageService.removeFile('c1', 'f1.txt', function(err) { assert(!err); @@ -125,10 +179,21 @@ describe('Storage service', function() { }); }); + it('should remove a file - promise', function(done) { + createFile('c1', 'f1.txt') + .then(function() { + return storageService.removeFile('c1', 'f1.txt') + .then(function() { + done(); + }); + }) + .catch(done); + }); + it('should get no files from a container', function(done) { storageService.getFiles('c1', function(err, files) { assert(!err); - assert.equal(0, files.length); + assert.equal(files.length, 0); done(err, files); }); }); @@ -136,19 +201,39 @@ describe('Storage service', function() { it('should not get a file from a container', function(done) { storageService.getFile('c1', 'f1.txt', function(err, f) { assert(err); - assert.equal('ENOENT', err.code); - assert.equal(404, err.status); + assert.equal(err.code, 'ENOENT'); + assert.equal(err.status, 404); assert(!f); done(); }); }); + it('should not get a file from a container - promise', function(done) { + storageService.getFile('c1', 'f1.txt') + .then(function() { + throw new Error('should not be throw'); + }) + .catch(function(err) { + assert.equal(err.code, 'ENOENT'); + assert.equal(err.status, 404); + done(); + }); + }); + it('should destroy a container c1', function(done) { storageService.destroyContainer('c1', function(err, container) { - // console.error(err); assert(!err); done(err, container); }); }); + + function createFile(container, file) { + return new Promise(function(resolve, reject) { + var writer = storageService.uploadStream(container, file); + fs.createReadStream(path.join(__dirname, 'files/f1.txt')).pipe(writer); + writer.on('finish', resolve); + writer.on('error', reject); + }); + } }); });