Merge pull request #99 from mozilla/testing

Testing
This commit is contained in:
Danny Coates 2017-06-20 10:45:32 -07:00 committed by GitHub
commit 2effdf2b95
9 changed files with 1528 additions and 1063 deletions

View file

@ -2,6 +2,7 @@ env:
browser: true browser: true
es6: true es6: true
jquery: true jquery: true
mocha: true
node: true node: true
extends: extends:

4
circle.yml Normal file
View file

@ -0,0 +1,4 @@
machine:
node:
version: 8.0.0

2216
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -27,8 +27,11 @@
"eslint-plugin-node": "5.0.0", "eslint-plugin-node": "5.0.0",
"eslint-plugin-security": "1.3.0", "eslint-plugin-security": "1.3.0",
"htmllint-cli": "0.0.6", "htmllint-cli": "0.0.6",
"mocha": "^3.4.2",
"npm-run-all": "4.0.2", "npm-run-all": "4.0.2",
"prettier": "1.4.4", "prettier": "1.4.4",
"proxyquire": "^1.8.0",
"sinon": "^2.3.5",
"stylelint": "7.11.0", "stylelint": "7.11.0",
"stylelint-config-standard": "16.0.0", "stylelint-config-standard": "16.0.0",
"watchify": "^3.9.0" "watchify": "^3.9.0"
@ -46,6 +49,6 @@
"lint:html": "htmllint 'views/*.handlebars'", "lint:html": "htmllint 'views/*.handlebars'",
"lint:js": "eslint .", "lint:js": "eslint .",
"start": "watchify frontend/src/main.js -o public/bundle.js -d | cross-env NODE_ENV=production node server/portal_server.js", "start": "watchify frontend/src/main.js -o public/bundle.js -d | cross-env NODE_ENV=production node server/portal_server.js",
"test": "echo \"Error: no test specified\" && exit 1" "test": "mocha"
} }
} }

View file

@ -23,7 +23,7 @@ const conf = convict({
env: 'P2P_LISTEN_PORT' env: 'P2P_LISTEN_PORT'
}, },
env: { env: {
format: ['production', 'development'], format: ['production', 'development', 'test'],
default: 'development', default: 'development',
env: 'NODE_ENV' env: 'NODE_ENV'
} }

View file

@ -74,6 +74,8 @@ app.get('/assets/download/:id', (req, res) => {
if (!err) { if (!err) {
log.info('Deleted:', id); log.info('Deleted:', id);
} }
}).catch(err => {
log.info('DeleteError:', id);
}); });
}); });
@ -89,7 +91,7 @@ app.post('/delete/:id', (req, res) => {
const id = req.params.id; const id = req.params.id;
if (!validateID(id)) { if (!validateID(id)) {
res.send(404); res.sendStatus(404);
return; return;
} }
@ -101,7 +103,7 @@ app.post('/delete/:id', (req, res) => {
storage storage
.delete(id, delete_token) .delete(id, delete_token)
.then(err => { .then(() => {
if (!err) { if (!err) {
log.info('Deleted:', id); log.info('Deleted:', id);
res.sendStatus(200); res.sendStatus(200);
@ -112,7 +114,7 @@ app.post('/delete/:id', (req, res) => {
app.post('/upload/:id', (req, res, next) => { app.post('/upload/:id', (req, res, next) => {
if (!validateID(req.params.id)) { if (!validateID(req.params.id)) {
res.send(404); res.sendStatus(404);
return; return;
} }

View file

@ -19,7 +19,7 @@ const redis_client = redis.createClient({
}); });
redis_client.on('error', err => { redis_client.on('error', err => {
log.info('Redis: ', err); log.info('Redis:', err);
}); });
if (notLocalHost) { if (notLocalHost) {
@ -94,7 +94,10 @@ function localSet(id, file, filename, url) {
}); });
}); });
fstream.on('error', () => reject()); fstream.on('error', () => {
log.error('localSet:', 'Failed upload of ' + id);
reject();
});
}); });
} }
@ -140,7 +143,12 @@ function awsGet(id) {
Key: id Key: id
}; };
return s3.getObject(params).createReadStream(); try {
return s3.getObject(params).createReadStream();
} catch(err) {
log.info('GetFailed', 'Get Object from s3 failed.');
return null;
}
} }
function awsSet(id, file, filename, url) { function awsSet(id, file, filename, url) {
@ -203,7 +211,7 @@ function awsDelete(id, delete_token) {
}; };
s3.deleteObject(params, function(err, _data) { s3.deleteObject(params, function(err, _data) {
resolve(err); err ? reject(err) : resolve(err);
}); });
} }
}); });
@ -219,7 +227,7 @@ function awsForceDelete(id) {
}; };
s3.deleteObject(params, function(err, _data) { s3.deleteObject(params, function(err, _data) {
resolve(err); err ? reject(err) : resolve(err);
}); });
}); });
} }

165
test/aws.storage.test.js Normal file
View file

@ -0,0 +1,165 @@
const assert = require('assert');
const sinon = require('sinon');
const proxyquire = require('proxyquire');
const crypto = require('crypto');
const conf = require('../server/config.js');
conf.notLocalHost = true;
let redisStub = {};
let exists = sinon.stub();
let hget = sinon.stub();
let hmset = sinon.stub();
let expire = sinon.spy();
let del = sinon.stub();
redisStub.createClient = function() {
return {
on: sinon.spy(),
exists: exists,
hget: hget,
hmset: hmset,
expire: expire,
del: del
}
}
let fsStub = {};
fsStub.statSync = sinon.stub();
fsStub.createReadStream = sinon.stub();
fsStub.createWriteStream = sinon.stub();
fsStub.unlinkSync = sinon.stub();
let logStub = {};
logStub.info = sinon.stub();
logStub.error = sinon.stub();
let s3Stub = {};
s3Stub.headObject = sinon.stub();
s3Stub.getObject = sinon.stub();
s3Stub.upload = sinon.stub();
s3Stub.deleteObject = sinon.stub();
let awsStub = {
S3: function() {
return s3Stub;
}
}
const storage = proxyquire('../server/storage', {
'redis': redisStub,
'fs': fsStub,
'./log.js': function() { return logStub },
'aws-sdk': awsStub
});
describe('Testing Length using aws', function() {
it('Filesize returns properly if id exists', function() {
s3Stub.headObject.callsArgWith(1, null, {ContentLength: 1});
return storage.length('123')
.then(reply => assert.equal(reply, 1))
.catch(err => assert.fail())
})
it('Filesize fails if the id does not exist', function() {
s3Stub.headObject.callsArgWith(1, new Error(), null);
return storage.length('123')
.then(reply => assert.fail())
.catch(err => assert(1))
})
});
describe('Testing Get using aws', function() {
it('Should not error out when the file exists', function() {
let spy = sinon.spy();
s3Stub.getObject.returns({
createReadStream: spy
});
storage.get('123');
assert(spy.calledOnce);
})
it('Should error when the file does not exist', function() {
let err = function() { throw new Error(); }
let spy = sinon.spy(err);
s3Stub.getObject.returns({
createReadStream: spy
});
assert.equal(storage.get('123'), null);
assert(spy.threw());
})
});
describe('Testing Set using aws', function() {
beforeEach(function() {
expire.reset();
})
after(function() {
crypto.randomBytes.restore();
})
it('Should pass when the file is successfully uploaded and no bitly key', function() {
conf.bitly_key = null;
const buf = new Buffer(10);
sinon.stub(crypto, 'randomBytes').returns(buf);
s3Stub.upload.callsArgWith(1, null, {});
return storage.set('123', {}, 'Filename.moz', 'url.com')
.then(reply => {
assert.equal(reply.uuid, buf.toString('hex'));
assert.equal(reply.url, 'url.com');
assert.notEqual(reply.uuid, null);
assert(expire.calledOnce);
assert(expire.calledWith('123', 86400000));
})
.catch(err => assert.fail());
})
it('Should fail if there was an error during uploading', function() {
s3Stub.upload.callsArgWith(1, new Error(), null);
return storage.set('123', {}, 'Filename.moz', 'url.com')
.then(reply => assert.fail())
.catch(err => assert(1));
})
});
describe('Testing Delete from aws', function() {
it('Returns successfully if the id is deleted off aws', function() {
hget.callsArgWith(2, null, 'delete_token');
s3Stub.deleteObject.callsArgWith(1, null, {});
return storage.delete('file_id', 'delete_token')
.then(reply => assert(1), err => assert.fail())
})
it('Delete fails if id exists locally but does not in aws', function() {
hget.callsArgWith(2, null, 'delete_token');
s3Stub.deleteObject.callsArgWith(1, new Error(), {});
return storage.delete('file_id', 'delete_token')
.then(reply => assert.fail(), err => assert(1))
})
it('Delete fails if the delete token does not match', function() {
hget.callsArgWith(2, null, {});
return storage.delete('Filename.moz', 'delete_token')
.then(reply => assert.fail())
.catch(reply => assert(1))
})
});
describe('Testing Forced Delete from aws', function() {
it('Deletes properly if id exists', function() {
s3Stub.deleteObject.callsArgWith(1, null, {});
return storage.forceDelete('file_id', 'delete_token')
.then(reply => assert(1), err => assert.fail());
})
it('Deletes fails if id does not exist', function() {
s3Stub.deleteObject.callsArgWith(1, new Error(), {});
return storage.forceDelete('file_id')
.then(reply => assert.fail(), err => assert(1))
})
})

172
test/local.storage.test.js Normal file
View file

@ -0,0 +1,172 @@
const assert = require('assert');
const sinon = require('sinon');
const proxyquire = require('proxyquire');
const conf = require('../server/config.js')
conf.notLocalHost = false;
let redisStub = {};
let exists = sinon.stub();
let hget = sinon.stub();
let hmset = sinon.stub();
let expire = sinon.stub();
let del = sinon.stub();
redisStub.createClient = function() {
return {
on: sinon.spy(),
exists: exists,
hget: hget,
hmset: hmset,
expire: expire,
del: del
}
}
let fsStub = {};
fsStub.statSync = sinon.stub();
fsStub.createReadStream = sinon.stub();
fsStub.createWriteStream = sinon.stub();
fsStub.unlinkSync = sinon.stub();
let logStub = {};
logStub.info = sinon.stub();
logStub.error = sinon.stub();
const storage = proxyquire('../server/storage', {
'redis': redisStub,
'fs': fsStub,
'./log.js': function() { return logStub }
});
describe('Testing Exists from local filesystem', function() {
it('Exists returns true when file exists', function() {
exists.callsArgWith(1, null, 1);
return storage.exists('test')
.then((reply) => assert(reply));
})
it('Exists returns false when file does not exist', function() {
exists.callsArgWith(1, null, 0);
return storage.exists('test')
.then((reply) => assert(!reply));
})
});
describe('Testing Filename from local filesystem', function() {
it('Filename returns properly if id exists', function() {
hget.callsArgWith(2, null, 'Filename.moz');
return storage.filename('test')
.then(reply => assert(1))
.catch(reply => assert.fail())
})
it('Filename fails if id does not exist', function() {
hget.callsArgWith(2, null, 'Filename.moz');
return storage.filename('test')
.then(reply => assert.fail())
.catch(reply => assert(1))
})
})
describe('Testing Length from local filesystem', function() {
it('Filesize returns properly if id exists', function() {
fsStub.statSync.returns({size: 10});
return storage.length('Filename.moz')
.then(reply => assert(1))
.catch(reply => assert.fail())
})
it('Filesize fails if the id does not exist', function() {
fsStub.statSync.returns(null);
return storage.length('Filename.moz')
.then(reply => assert.fail())
.catch(reply => assert(1))
})
})
describe('Testing Get from local filesystem', function() {
it('Get returns properly if id exists', function() {
fsStub.createReadStream.returns(1);
if (storage.get('Filename.moz')) {
assert(1)
} else {
assert.fail();
}
})
it('Get fails if the id does not exist', function() {
fsStub.createReadStream.returns(null);
if (storage.get('Filename.moz')) {
assert.fail();
} else {
assert(1);
}
})
})
describe('Testing Set to local filesystem', function() {
it('Successfully writes the file to the local filesystem', function() {
let stub = sinon.stub();
stub.withArgs('close', sinon.match.any).callsArgWithAsync(1)
stub.withArgs('error', sinon.match.any).returns(1);
fsStub.createWriteStream.returns({ on: stub })
return storage.set('test', { pipe: sinon.stub() }, 'Filename.moz', 'moz.la')
.then(reply => {
assert(reply.uuid);
assert.equal(reply.url, 'moz.la');
})
.catch(reply => assert.fail())
})
it('Fails when the file is not properly written to the local filesystem', function() {
let stub = sinon.stub();
stub.withArgs('error', sinon.match.any).callsArgWithAsync(1)
stub.withArgs('close', sinon.match.any).returns(1);
fsStub.createWriteStream.returns({ on: stub })
return storage.set('test', {pipe: sinon.stub()}, 'Filename.moz', 'moz.la')
.then(reply => assert.fail())
.catch(reply => assert(1))
})
})
describe('Testing Delete from local filesystem', function() {
it('Deletes properly if id exists', function() {
hget.callsArgWith(2, null, '123');
fsStub.unlinkSync.returns(1);
return storage.delete('Filename.moz', '123')
.then(reply => assert(reply))
.catch(reply => assert.fail())
})
it('Delete fails if id does not exist', function() {
hget.callsArgWith(2, null, null);
return storage.delete('Filename.moz', '123')
.then(reply => assert.fail())
.catch(reply => assert(1))
})
it('Delete fails if the delete token does not match', function() {
hget.callsArgWith(2, null, null);
return storage.delete('Filename.moz', '123')
.then(reply => assert.fail())
.catch(reply => assert(1))
})
})
describe('Testing Forced Delete from local filesystem', function() {
it('Deletes properly if id exists', function() {
fsStub.unlinkSync.returns(1);
return storage.forceDelete('Filename.moz')
.then(reply => assert(reply))
})
it('Deletes fails if id does not exist, but no reject is called', function() {
fsStub.unlinkSync.returns(0);
return storage.forceDelete('Filename.moz')
.then(reply => assert(!reply))
})
})