loopback-component-storage/test/upload-download.test.js

519 lines
15 KiB
JavaScript
Raw Normal View History

2019-05-07 13:41:29 +00:00
// Copyright IBM Corp. 2014,2018. All Rights Reserved.
2016-05-03 23:18:18 +00:00
// Node module: loopback-component-storage
// This file is licensed under the Artistic License 2.0.
// License text available at https://opensource.org/licenses/Artistic-2.0
2019-05-07 13:41:29 +00:00
2016-10-18 22:48:59 +00:00
'use strict';
2016-05-03 23:18:18 +00:00
2014-01-14 18:26:09 +00:00
var request = require('supertest');
var loopback = require('loopback');
var assert = require('assert');
2016-10-25 14:03:05 +00:00
var semver = require('semver');
2014-01-14 18:26:09 +00:00
var app = loopback();
var path = require('path');
2016-10-19 16:01:05 +00:00
// configure errorHandler to show full error message
app.set('remoting', {errorHandler: {debug: true, log: false}});
2017-03-09 16:22:03 +00:00
// custom route with renamer
app.post('/custom/upload', function(req, res, next) {
var options = {
container: 'album1',
getFilename: function(file, req, res) {
return file.field + '_' + file.name;
},
};
ds.connector.upload(req, res, options, function(err, result) {
if (!err) {
res.setHeader('Content-Type', 'application/json');
res.status(200).send({result: result});
} else {
res.status(500).send(err);
}
});
});
2016-10-19 16:01:05 +00:00
// custom route with renamer
app.post('/custom/uploadWithContainer', function(req, res, next) {
var options = {
getFilename: function(file, req, res) {
return file.field + '_' + file.name;
},
};
ds.connector.upload('album1', req, res, options, function(err, result) {
if (!err) {
res.setHeader('Content-Type', 'application/json');
res.status(200).send({result: result});
} else {
res.status(500).send(err);
}
});
});
2014-01-14 18:26:09 +00:00
// expose a rest api
app.use(loopback.rest());
var dsImage = loopback.createDataSource({
connector: require('../lib/storage-connector'),
provider: 'filesystem',
root: path.join(__dirname, 'images'),
getFilename: function(fileInfo) {
return 'image-' + fileInfo.name;
},
acl: 'public-read',
allowedContentTypes: ['image/png', 'image/jpeg'],
2016-10-18 22:06:55 +00:00
maxFileSize: 5 * 1024 * 1024,
});
var ImageContainer = dsImage.createModel('imageContainer');
app.model(ImageContainer);
2014-01-14 18:26:09 +00:00
var ds = loopback.createDataSource({
connector: require('../lib/storage-connector'),
provider: 'filesystem',
2016-10-18 22:06:55 +00:00
root: path.join(__dirname, 'images'),
2014-01-14 18:26:09 +00:00
});
2015-09-30 03:46:17 +00:00
var Container = ds.createModel('container', {}, {base: 'Model'});
2014-01-14 18:26:09 +00:00
app.model(Container);
/*!
* Verify that the JSON response has the correct metadata properties.
* Please note the metadata vary by storage providers. This test assumes
* the 'filesystem' provider.
*
* @param {String} containerOrFile The container/file object
* @param {String} [name] The name to be checked if not undefined
*/
function verifyMetadata(containerOrFile, name) {
assert(containerOrFile);
// Name
if (name) {
assert.equal(containerOrFile.name, name);
}
// No sensitive information
assert(containerOrFile.uid === undefined);
assert(containerOrFile.gid === undefined);
// Timestamps
assert(containerOrFile.atime);
assert(containerOrFile.ctime);
assert(containerOrFile.mtime);
// Size
assert.equal(typeof containerOrFile.size, 'number');
}
2016-10-18 22:06:55 +00:00
describe('storage service', function() {
2014-01-14 18:26:09 +00:00
var server = null;
2016-10-18 22:06:55 +00:00
before(function(done) {
server = app.listen(0, function() {
2014-01-14 18:26:09 +00:00
done();
});
});
2016-10-18 22:06:55 +00:00
after(function() {
2014-01-14 18:26:09 +00:00
server.close();
});
2016-10-18 22:06:55 +00:00
it('should create a container', function(done) {
request('http://localhost:' + app.get('port'))
2014-02-03 18:58:37 +00:00
.post('/containers')
.send({name: 'test-container'})
.set('Accept', 'application/json')
.set('Content-Type', 'application/json')
.expect('Content-Type', /json/)
2016-10-18 22:06:55 +00:00
.expect(200, function(err, res) {
verifyMetadata(res.body, 'test-container');
2014-02-03 18:58:37 +00:00
done();
});
});
2016-10-18 22:06:55 +00:00
it('should get a container', function(done) {
request('http://localhost:' + app.get('port'))
2014-02-03 18:58:37 +00:00
.get('/containers/test-container')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
2016-10-18 22:06:55 +00:00
.expect(200, function(err, res) {
verifyMetadata(res.body, 'test-container');
2014-02-03 18:58:37 +00:00
done();
});
});
2016-10-18 22:06:55 +00:00
it('should list containers', function(done) {
request('http://localhost:' + app.get('port'))
2014-02-03 18:58:37 +00:00
.get('/containers')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
2016-10-18 22:06:55 +00:00
.expect(200, function(err, res) {
2014-02-03 18:58:37 +00:00
assert(Array.isArray(res.body));
assert.equal(res.body.length, 2);
res.body.forEach(function(c) {
verifyMetadata(c);
});
2014-02-03 18:58:37 +00:00
done();
});
});
2016-10-18 22:06:55 +00:00
it('should delete a container', function(done) {
request('http://localhost:' + app.get('port'))
2014-02-03 18:58:37 +00:00
.del('/containers/test-container')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
2016-10-18 22:06:55 +00:00
.expect(200, function(err, res) {
2014-02-03 18:58:37 +00:00
done();
});
});
2016-10-18 22:06:55 +00:00
it('should list containers after delete', function(done) {
request('http://localhost:' + app.get('port'))
2014-02-03 18:58:37 +00:00
.get('/containers')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
2016-10-18 22:06:55 +00:00
.expect(200, function(err, res) {
2014-02-03 18:58:37 +00:00
assert(Array.isArray(res.body));
assert.equal(res.body.length, 1);
done();
});
});
2016-10-18 22:06:55 +00:00
it('should list files', function(done) {
request('http://localhost:' + app.get('port'))
2014-02-03 18:58:37 +00:00
.get('/containers/album1/files')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
2016-10-18 22:06:55 +00:00
.expect(200, function(err, res) {
2014-02-03 18:58:37 +00:00
assert(Array.isArray(res.body));
res.body.forEach(function(f) {
verifyMetadata(f);
});
2014-02-03 18:58:37 +00:00
done();
});
});
2016-10-18 22:06:55 +00:00
it('uploads files', function(done) {
request('http://localhost:' + app.get('port'))
2014-01-14 18:26:09 +00:00
.post('/containers/album1/upload')
.attach('image', path.join(__dirname, './fixtures/test.jpg'))
2014-01-14 18:26:09 +00:00
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
2016-10-18 22:06:55 +00:00
.expect(200, function(err, res) {
assert.deepEqual(res.body, {
result: {
files: {
image: [
{
container: 'album1',
name: 'test.jpg',
type: 'image/jpeg',
field: 'image',
size: 60475,
},
],
},
fields: {},
},
});
2014-01-14 18:26:09 +00:00
done();
});
});
it('fails to upload using dotdot file path (1)', function(done) {
2017-02-08 03:21:18 +00:00
request('http://localhost:' + app.get('port'))
.post('/containers/%2e%2e/upload')
.expect(200, function(err, res) {
assert(err);
done();
});
});
it('fails to upload using dotdot file path (2)', function(done) {
2017-02-08 03:21:18 +00:00
request('http://localhost:' + app.get('port'))
.post('%2e%2e/containers/upload')
.expect(200, function(err, res) {
assert(err);
done();
});
});
it('fails to upload using dotdot file path (3)', function(done) {
2017-02-08 03:21:18 +00:00
request('http://localhost:' + app.get('port'))
.post('%2e%2e')
.expect(200, function(err, res) {
assert(err);
done();
});
});
it('fails to upload using dotdot file path (4)', function(done) {
2017-02-08 03:21:18 +00:00
request('http://localhost:' + app.get('port'))
.post('/containers/upload/%2e%2e')
.expect(200, function(err, res) {
assert(err);
done();
});
});
2016-10-18 22:06:55 +00:00
it('uploads files with renamer', function(done) {
request('http://localhost:' + app.get('port'))
.post('/imageContainers/album1/upload')
.attach('image', path.join(__dirname, './fixtures/test.jpg'))
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
2016-10-18 22:06:55 +00:00
.expect(200, function(err, res) {
assert.deepEqual(res.body, {
result: {
files: {
image: [
{
container: 'album1',
name: 'image-test.jpg',
originalFilename: 'test.jpg',
type: 'image/jpeg',
field: 'image',
acl: 'public-read',
size: 60475,
},
],
},
fields: {},
},
});
done();
});
});
it('uploads file wrong content type', function(done) {
request('http://localhost:' + app.get('port'))
.post('/imageContainers/album1/upload')
.attach('image', path.join(__dirname, './fixtures/app.js'))
.set('Accept', 'application/json')
.set('Connection', 'keep-alive')
.expect('Content-Type', /json/)
.expect(500, function(err, res) {
assert(res.body.error.message.indexOf('is not allowed') !== -1);
done(err);
});
});
2016-10-18 22:06:55 +00:00
it('uploads file too large', function(done) {
request('http://localhost:' + app.get('port'))
.post('/imageContainers/album1/upload')
.attach('image', path.join(__dirname, './fixtures/largeImage.jpg'))
.set('Accept', 'application/json')
.set('Connection', 'keep-alive')
.expect('Content-Type', /json/)
2016-10-18 22:06:55 +00:00
.expect(200, function(err, res) {
assert(err);
assert(res.body.error.message.indexOf('maxFileSize exceeded') !== -1);
done();
});
});
2016-10-25 14:03:05 +00:00
it('returns error when no file is provided to upload', function(done) {
if (semver.gt(process.versions.node, '4.0.0')) {
request('http://localhost:' + app.get('port'))
.post('/imageContainers/album1/upload')
.set('Accept', 'application/json')
.set('Connection', 'keep-alive')
.expect('Content-Type', /json/)
.expect(400, function(err, res) {
var indexOfMsg = res.body.error.message
.toLowerCase()
.indexOf('no file');
assert.notEqual(
indexOfMsg,
-1,
'Error message does not contain "no file"'
);
2016-10-25 14:03:05 +00:00
done(err);
});
} else {
request('http://localhost:' + app.get('port'))
.post('/imageContainers/album1/upload')
.set('Accept', 'application/json')
.set('Connection', 'keep-alive')
.expect('Content-Type', /json/)
.expect(500, function(err, res) {
assert.equal(
res.body.error.message,
'bad content-type header, no content-type'
);
2016-10-25 14:03:05 +00:00
done(err);
});
}
});
2016-10-18 22:06:55 +00:00
it('should get file by name', function(done) {
request('http://localhost:' + app.get('port'))
2014-02-03 18:58:37 +00:00
.get('/containers/album1/files/test.jpg')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
2016-10-18 22:06:55 +00:00
.expect(200, function(err, res) {
verifyMetadata(res.body, 'test.jpg');
2014-02-03 18:58:37 +00:00
done();
});
});
2016-10-18 22:06:55 +00:00
it('should get file by renamed file name', function(done) {
request('http://localhost:' + app.get('port'))
.get('/imageContainers/album1/files/image-test.jpg')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
2016-10-18 22:06:55 +00:00
.expect(200, function(err, res) {
verifyMetadata(res.body, 'image-test.jpg');
done();
});
});
2016-10-18 22:06:55 +00:00
it('downloads files', function(done) {
request('http://localhost:' + app.get('port'))
2014-01-14 18:26:09 +00:00
.get('/containers/album1/download/test.jpg')
.expect('Content-Type', 'image/jpeg')
2016-10-18 22:06:55 +00:00
.expect(200, function(err, res) {
if (err) done(err);
2014-01-14 18:26:09 +00:00
done();
});
});
it('should run a function before a download is started by a client', function(done) {
var hookCalled = false;
var Container = app.models.Container;
Container.beforeRemote('download', function(ctx, unused, cb) {
hookCalled = true;
cb();
});
request('http://localhost:' + app.get('port'))
.get('/containers/album1/download/test.jpg')
.expect('Content-Type', 'image/jpeg')
.expect(200, function(err, res) {
if (err) done(err);
assert(hookCalled, 'beforeRemote hook was not called');
done();
});
});
it('should run a function after a download is started by a client', function(done) {
var hookCalled = false;
var Container = app.models.Container;
Container.afterRemote('download', function(ctx, unused, cb) {
hookCalled = true;
cb();
});
request('http://localhost:' + app.get('port'))
.get('/containers/album1/download/test.jpg')
.expect('Content-Type', 'image/jpeg')
.expect(200, function(err, res) {
if (err) done(err);
assert(hookCalled, 'afterRemote hook was not called');
done();
});
});
it('should run a function after a download failed', function(done) {
var hookCalled = false;
var Container = app.models.Container;
Container.afterRemoteError('download', function(ctx, cb) {
hookCalled = true;
cb();
});
request('http://localhost:' + app.get('port'))
.get('/containers/album1/download/does-not-exist')
.expect(404, function(err, res) {
if (err) return done(err);
assert(hookCalled, 'afterRemoteEror hook was not called');
done();
});
});
2016-10-18 22:06:55 +00:00
it('should delete a file', function(done) {
request('http://localhost:' + app.get('port'))
2014-02-03 18:58:37 +00:00
.del('/containers/album1/files/test.jpg')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
2016-10-18 22:06:55 +00:00
.expect(200, function(err, res) {
2014-02-03 18:58:37 +00:00
done();
});
});
2016-10-18 22:06:55 +00:00
it('reports errors if it fails to find the file to download', function(done) {
request('http://localhost:' + app.get('port'))
2014-01-14 18:26:09 +00:00
.get('/containers/album1/download/test_not_exist.jpg')
.expect('Content-Type', /json/)
2016-10-18 22:06:55 +00:00
.expect(500, function(err, res) {
2014-01-14 18:26:09 +00:00
assert(res.body.error);
done();
});
});
it(
'should upload a file with custom route accessing directly to the ' +
'storage connector with renamer',
function(done) {
request('http://localhost:' + app.get('port'))
.post('/custom/upload')
.attach('customimagefield', path.join(__dirname, './fixtures/test.jpg'))
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200, function(err, res) {
assert.deepEqual(res.body, {
result: {
files: {
customimagefield: [
{
container: 'album1',
name: 'customimagefield_test.jpg',
originalFilename: 'test.jpg',
type: 'image/jpeg',
field: 'customimagefield',
size: 60475,
},
],
},
fields: {},
},
});
done();
});
}
);
it('should upload a file with container param', function(done) {
request('http://localhost:' + app.get('port'))
.post('/custom/uploadWithContainer')
.attach('customimagefield1', path.join(__dirname, './fixtures/test.jpg'))
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200, function(err, res) {
assert.deepEqual(res.body, {
result: {
files: {
customimagefield1: [
{
container: 'album1',
name: 'customimagefield1_test.jpg',
originalFilename: 'test.jpg',
type: 'image/jpeg',
field: 'customimagefield1',
size: 60475,
},
],
},
fields: {},
},
});
done();
});
});
2014-01-14 18:26:09 +00:00
});