Skip to content

Commit

Permalink
Added validation and testing for said validation
Browse files Browse the repository at this point in the history
  • Loading branch information
supernomad committed Jun 20, 2015
1 parent 31ae96d commit 7f28cf5
Show file tree
Hide file tree
Showing 6 changed files with 302 additions and 12 deletions.
4 changes: 2 additions & 2 deletions libs/helpers/errorHelper.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
function genericErrorHandler(error, debug = false) {
function genericErrorHandler(error, debug) {
if(error) {
if(debug) console.error(error);
throw error;
throw new Error(JSON.stringify(error));
}
}

Expand Down
15 changes: 10 additions & 5 deletions libs/models/errorModels.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
function genericError(code, error, message) {
function GenericError(code, error, message) {
self.Code = code;
self.Error = error;
self.Message = message;
}

function missingCacheItem() {
this = new genericError(404, "Missing Upload", "The upload specified could not be found, please check the supplied id and try again.");
this = new GenericError(404, "Missing Upload Error", "The upload specified could not be found, please check the supplied id and try again.");
}

function serverError() {
this = new genericError(500, "Internal Server Error", "There has been an internal server error, so things are basically blowing up in our datacenter. We will get back to you in a minute but go ahead and try again.");
this = new GenericError(500, "Internal Server Error", "There has been an internal server error, so things are basically blowing up in our datacenter. We will get back to you in a minute but go ahead and try again.");
}

function validationError(msg) {
this = new GenericError(400, "Validation Error", msg);
}

module.exports = {
GenericError: genericError,
GenericError: GenericError,
MissingCacheItem: missingCacheItem,
ServerError: serverError
ServerError: serverError,
ValidationError: validationError
};
44 changes: 44 additions & 0 deletions libs/validators/chunked-upload-validators.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
var typeHelper = require('./../helpers/typeHelper');

var valid = "valid";

function validateUploadRequest(uploadRequest, maxSize) {
if(!typeHelper.isObject(uploadRequest)) {
return "Upload request object was not recieved.";
} else if (!uploadRequest.hasOwnProperty('fileName') || !typeHelper.isString(uploadRequest.fileName)) {
return "Upload fileName missing.";
} else if (!uploadRequest.hasOwnProperty('fileSize') || !typeHelper.isNumber(uploadRequest.fileSize)) {
return "Upload fileSize missing.";
} else if (uploadRequest.fileSize <= 0) {
return "Upload fileSize must be greater than 0 bytes.";
} else if (maxSize > 0 && uploadRequest.fileSize > maxSize) {
return "Upload fileSize is greater than the maximum size of " + maxSize + " bytes.";
} else if (!uploadRequest.hasOwnProperty('chunkSize') || !typeHelper.isNumber(uploadRequest.chunkSize)) {
return "Upload chunkSize missing.";
} else if (uploadRequest.chunkSize <= 0) {
return "Upload chunkSize must be greater than 0 bytes.";
} else if (!uploadRequest.hasOwnProperty('count') || !typeHelper.isNumber(uploadRequest.count)) {
return "Upload count missing.";
} else if (uploadRequest.count !== (uploadRequest.fileSize / uploadRequest.chunkSize | 0) + (uploadRequest.fileSize % uploadRequest.chunkSize > 0 ? 1 : 0)) {
return "Upload count does not match computed value, check upload file size and chunkSize.";
} else if (!uploadRequest.hasOwnProperty('destination') || !typeHelper.isString(uploadRequest.destination)) {
return "Upload destination missing.";
} else {
return valid;
}
};

function validateChunkRequest(req) {
if(!req.files || Object.keys(req.files).length <= 0) {
return "The chunk upload request must be of Content-Type: 'multipart/form-data', and there must be one file appended within the form.";
}
else {
return valid;
}
};

module.exports = {
valid: valid,
validateUploadRequest: validateUploadRequest,
validateChunkRequest: validateChunkRequest
};
25 changes: 20 additions & 5 deletions routes/chunked-upload-routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ var apiModels = require('./../libs/models/apiModels'),
guidHelper = require('./../libs/helpers/guidHelper'),
errorHelper = require('./../libs/helpers/errorHelper'),
typeHelper = require('./../libs/helpers/typeHelper'),
stringHelper = require('./../libs/helpers/stringHelper');
stringHelper = require('./../libs/helpers/stringHelper'),
validator = require('./../libs/validators/chunked-upload-validators');

var debug = false,
routePrefix = "/chunked/upload",
Expand All @@ -14,6 +15,10 @@ var debug = false,

var routes = {
"get": new apiModels.RouteHandler(routePrefix + "/:uploadId", function (req, res) {
if (!guidHelper.isGuid(req.params.uploadId)){
throw new errorModels.ValidationError("The supplied uploadId is not a valid v4 GUID");
}

dataCache.restore(req.params.uploadId, function name(error, upload) {
errorHelper.genericErrorHandler(error, debug);
if(typeHelper.doesExist(upload)){
Expand All @@ -24,7 +29,10 @@ var routes = {
});
}),
"post": new apiModels.RouteHandler(routePrefix, function (req, res) {
// TODO: add validation of the request parameters
var valid = validator.validateUploadRequest(req.body);
if(valid !== validator.valid) {
throw new errorModels.ValidationError(valid);
}

var upload = new apiModels.Upload(req.body);
upload.configure(guidHelper.newGuid());
Expand All @@ -44,10 +52,19 @@ var routes = {
});
}),
"put": new apiModels.RouteHandler(routePrefix + "/:uploadId/:index", function (req, res) {
// TODO: add validation of the request parameters
var valid = validator.validateChunkRequest(req);
if(valid !== validator.valid) {
throw new errorModels.ValidationError(valid);
} else if (!guidHelper.isGuid(req.params.uploadId)){
throw new errorModels.ValidationError("The supplied uploadId is not a valid v4 GUID");
}

}),
"delete": new apiModels.RouteHandler(routePrefix + "/:uploadId", function (req, res) {
if (!guidHelper.isGuid(req.params.uploadId)){
throw new errorModels.ValidationError("The supplied uploadId is not a valid v4 GUID");
}

dataCache.restore(req.params.uploadId, function name(error, upload) {
errorHelper.genericErrorHandler(error, debug);
if(typeHelper.doesExist(upload)){
Expand All @@ -66,8 +83,6 @@ var routes = {
throw new errorModels.MissingCacheItem();
}
});


}),
"error": new apiModels.ErrorHandler(function (error, req, res, next) {

Expand Down
193 changes: 193 additions & 0 deletions test/chunked-upload-validators-tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
/* global describe, it */
var should = require('should'),
validators = require('./../libs/validators/chunked-upload-validators.js');

describe("chunked-upload-validators.js", function () {
describe("#valid", function () {
it('should return the signifier of a valid call', function() {
var valid = validators.valid;
should.exist(valid);
valid.should.be.a.String;
valid.should.equal("valid");
});
});

describe("#validateUploadRequest", function () {
it('should return the signifier of a valid call for a valid uploadRequest', function() {
var valid = validators.validateUploadRequest({
fileName: "woot.txt",
fileSize: 1024,
chunkSize: 1024,
count: 1,
destination: "/i/am/a/path/to/a/destination"
}, 1024);
should.exist(valid);
valid.should.be.a.String;
valid.should.equal("valid");
});

it('should NOT return the signifier of a valid call when passed a non-object value', function() {
var valid = validators.validateUploadRequest(null, 1024);
should.exist(valid);
valid.should.be.a.String;
valid.should.equal("Upload request object was not recieved.");

valid = validators.validateUploadRequest(undefined, 1024);
should.exist(valid);
valid.should.be.a.String;
valid.should.equal("Upload request object was not recieved.");

valid = validators.validateUploadRequest("I am a string", 1024);
should.exist(valid);
valid.should.be.a.String;
valid.should.equal("Upload request object was not recieved.");

valid = validators.validateUploadRequest(false, 1024);
should.exist(valid);
valid.should.be.a.String;
valid.should.equal("Upload request object was not recieved.");

valid = validators.validateUploadRequest(0, 1024);
should.exist(valid);
valid.should.be.a.String;
valid.should.equal("Upload request object was not recieved.");
});

it('should NOT return the signifier of a valid call for an uploadRequest with a fileSize <= 0', function() {
var valid = validators.validateUploadRequest({
fileName: "woot.txt",
fileSize: 0,
chunkSize: 1024,
count: 1,
destination: "/i/am/a/path/to/a/destination"
}, 1024);
should.exist(valid);
valid.should.be.a.String;
valid.should.equal("Upload fileSize must be greater than 0 bytes.");
});

it('should NOT return the signifier of a valid call for an uploadRequest with a fileSize > maxSize', function() {
var valid = validators.validateUploadRequest({
fileName: "woot.txt",
fileSize: 1024,
chunkSize: 1024,
count: 1,
destination: "/i/am/a/path/to/a/destination"
}, 512);
should.exist(valid);
valid.should.be.a.String;
valid.should.equal("Upload fileSize is greater than the maximum size of 512 bytes.");
});

it('should NOT return the signifier of a valid call for an uploadRequest with a chunkSize <= 0', function() {
var valid = validators.validateUploadRequest({
fileName: "woot.txt",
fileSize: 1024,
chunkSize: 0,
count: 1,
destination: "/i/am/a/path/to/a/destination"
}, 1024);
should.exist(valid);
valid.should.be.a.String;
valid.should.equal("Upload chunkSize must be greater than 0 bytes.");
});

it('should NOT return the signifier of a valid call for an uploadRequest with a count that does not match the fileSize / chunkSize + (fileSize % chunkSize > 0 ? 1 : 0)', function() {
var valid = validators.validateUploadRequest({
fileName: "woot.txt",
fileSize: 1024,
chunkSize: 1024,
count: 2,
destination: "/i/am/a/path/to/a/destination"
}, 1024);
should.exist(valid);
valid.should.be.a.String;
valid.should.equal("Upload count does not match computed value, check upload file size and chunkSize.");
});

it('should NOT return the signifier of a valid call for an uploadRequest with improper parameter typing', function() {
var valid = validators.validateUploadRequest({
fileName: "woot.txt",
fileSize: "1024",
chunkSize: 1024,
count: 1,
destination: "/i/am/a/path/to/a/destination"
}, 1024);
should.exist(valid);
valid.should.be.a.String;
valid.should.equal("Upload fileSize missing.");

valid = validators.validateUploadRequest({
fileName: "woot.txt",
fileSize: 1024,
chunkSize: "1024",
count: 1,
destination: "/i/am/a/path/to/a/destination"
}, 1024);
should.exist(valid);
valid.should.be.a.String;
valid.should.equal("Upload chunkSize missing.");

valid = validators.validateUploadRequest({
fileName: "woot.txt",
fileSize: 1024,
chunkSize: 1024,
count: "1",
destination: "/i/am/a/path/to/a/destination"
}, 1024);
should.exist(valid);
valid.should.be.a.String;
valid.should.equal("Upload count missing.");

valid = validators.validateUploadRequest({
fileName: true,
fileSize: 1024,
chunkSize: 1024,
count: 1,
destination: "/i/am/a/path/to/a/destination"
}, 1024);
should.exist(valid);
valid.should.be.a.String;
valid.should.equal("Upload fileName missing.");

valid = validators.validateUploadRequest({
fileName: "woot.txt",
fileSize: 1024,
chunkSize: 1024,
count: 1,
destination: null
}, 1024);
should.exist(valid);
valid.should.be.a.String;
valid.should.equal("Upload destination missing.");
});
});

describe('#validateChunkRequest', function() {
it('should return the signifier of a valid call for a valid chunkRequest', function() {
var valid = validators.validateChunkRequest({
files: {
fileIdentifier: {}
}
});
should.exist(valid);
valid.should.be.a.String;
valid.should.equal("valid");
});

it('should NOT return the signifier of a valid call for a chunkRequest without files', function() {
var valid = validators.validateChunkRequest({

});
should.exist(valid);
valid.should.be.a.String;
valid.should.equal("The chunk upload request must be of Content-Type: 'multipart/form-data', and there must be one file appended within the form.");
valid = validators.validateChunkRequest({
files: {}
});
should.exist(valid);
valid.should.be.a.String;
valid.should.equal("The chunk upload request must be of Content-Type: 'multipart/form-data', and there must be one file appended within the form.");
});
});
});
33 changes: 33 additions & 0 deletions test/errorHelper-tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* global describe, it */
var should = require('should'),
errorHelper = require('./../libs/helpers/errorHelper');

describe('errorHelper.js', function() {
describe('#genericErrorHandler', function() {
it('should throw an error if passed a valid object', function() {
(function () {
errorHelper.genericErrorHandler("Error");
errorHelper.genericErrorHandler({});
errorHelper.genericErrorHandler(1);
errorHelper.genericErrorHandler(-1);
errorHelper.genericErrorHandler(true);
}).should.throw();
});

it('should not throw an error if passed a non valid object', function() {
(function () {
errorHelper.genericErrorHandler("");
errorHelper.genericErrorHandler(0);
errorHelper.genericErrorHandler(false);
errorHelper.genericErrorHandler(null);
errorHelper.genericErrorHandler(undefined);
}).should.not.throw();
});

it('should write the error to console.error if passed a trueish as the second argument', function() {
(function () {
errorHelper.genericErrorHandler("Error", true);
}).should.throw();
});
});
});

0 comments on commit 7f28cf5

Please sign in to comment.