feat: add ValidationError type extending TypeError (#151)

This change adds a `ValidationError` type that extends `TypeError`. Any time a `CloudEvent` cannot be received and created with the given input, this error will be thrown. Tests have all
been updated to check for the error type.

Signed-off-by: Lance Ball <lball@redhat.com>
This commit is contained in:
Lance Ball 2020-05-13 13:27:18 -04:00 committed by GitHub
parent b5a6673ace
commit 09b0c76826
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 155 additions and 189 deletions

View File

@ -2,6 +2,7 @@ const V03Binary = require("./receiver_binary_0_3.js");
const V03Structured = require("./receiver_structured_0_3.js");
const V1Binary = require("./receiver_binary_1.js");
const V1Structured = require("./receiver_structured_1.js");
const ValidationError = require("../../validation_error.js");
const {
SPEC_V03,
SPEC_V1,
@ -63,7 +64,7 @@ function getMode(headers) {
if (headers[BINARY_HEADERS_1.ID]) {
return "binary";
}
throw new TypeError("no cloud event detected");
throw new ValidationError("no cloud event detected");
}
function getVersion(mode, headers, body) {

View File

@ -2,6 +2,7 @@ const { HEADER_CONTENT_TYPE, MIME_JSON, DEFAULT_SPEC_VERSION_HEADER } =
require("./constants.js");
const Commons = require("./commons.js");
const CloudEvent = require("../../cloudevent.js");
const ValidationError = require("../../validation_error.js");
const {
isDefinedOrThrow,
@ -10,15 +11,12 @@ const {
function validateArgs(payload, attributes) {
Array.of(payload)
.filter((p) => isDefinedOrThrow(p,
{ message: "payload is null or undefined" }))
.filter((p) => isStringOrObjectOrThrow(p,
{ message: "payload must be an object or a string" }))
.filter((p) => isDefinedOrThrow(p, new ValidationError("payload is null or undefined")))
.filter((p) => isStringOrObjectOrThrow(p, new ValidationError("payload must be an object or a string")))
.shift();
Array.of(attributes)
.filter((a) => isDefinedOrThrow(a,
{ message: "attributes is null or undefined" }))
.filter((a) => isDefinedOrThrow(a, new ValidationError("attributes is null or undefined")))
.shift();
}
@ -58,22 +56,18 @@ BinaryHTTPReceiver.prototype.check = function(payload, headers) {
const contentTypeHeader = sanityHeaders[HEADER_CONTENT_TYPE];
const noContentType = !this.allowedContentTypes.includes(contentTypeHeader);
if (contentTypeHeader && noContentType) {
const err = new TypeError("invalid content type");
err.errors = [sanityHeaders[HEADER_CONTENT_TYPE]];
throw err;
throw new ValidationError("invalid content type", [sanityHeaders[HEADER_CONTENT_TYPE]]);
}
this.requiredHeaders
.filter((required) => !sanityHeaders[required])
.forEach((required) => {
throw new TypeError(`header '${required}' not found`);
throw new ValidationError(`header '${required}' not found`);
});
if (sanityHeaders[DEFAULT_SPEC_VERSION_HEADER] !==
this.specversion) {
const err = new TypeError("invalid spec version");
err.errors = [sanityHeaders[DEFAULT_SPEC_VERSION_HEADER]];
throw err;
throw new ValidationError("invalid spec version", [sanityHeaders[DEFAULT_SPEC_VERSION_HEADER]]);
}
// No erros! Its contains the minimum required attributes

View File

@ -1,5 +1,6 @@
const Constants = require("./constants.js");
const Spec = require("../../specs/spec_0_3.js");
const ValidationError = require("../../validation_error.js");
const JSONParser = require("../../formats/json/parser.js");
const Base64Parser = require("../../formats/base64.js");
@ -85,9 +86,7 @@ function checkDecorator(payload, headers) {
.filter((header) => !allowedEncodings.includes(headers[header]))
.forEach((header) => {
// TODO: using forEach here seems off
const err = new TypeError("unsupported datacontentencoding");
err.errors = [headers[header]];
throw err;
throw new ValidationError("unsupported datacontentencoding");
});
}

View File

@ -1,6 +1,7 @@
const Constants = require("./constants.js");
const Commons = require("./commons.js");
const CloudEvent = require("../../cloudevent.js");
const ValidationError = require("../../validation_error.js");
const {
isDefinedOrThrow,
@ -9,15 +10,12 @@ const {
function validateArgs(payload, attributes) {
Array.of(payload)
.filter((p) => isDefinedOrThrow(p,
{ message: "payload is null or undefined" }))
.filter((p) => isStringOrObjectOrThrow(p,
{ message: "payload must be an object or string" }))
.filter((p) => isDefinedOrThrow(p, new ValidationError("payload is null or undefined")))
.filter((p) => isStringOrObjectOrThrow(p, new ValidationError("payload must be an object or string")))
.shift();
Array.of(attributes)
.filter((a) => isDefinedOrThrow(a,
{ message: "attributes is null or undefined" }))
.filter((a) => isDefinedOrThrow(a, new ValidationError("attributes is null or undefined")))
.shift();
}
@ -41,9 +39,7 @@ StructuredHTTPReceiver.prototype.check = function(payload, headers) {
// Validation Level 1
if (!this.allowedContentTypes
.includes(sanityHeaders[Constants.HEADER_CONTENT_TYPE])) {
const err = new TypeError("invalid content type");
err.errors = [sanityHeaders[Constants.HEADER_CONTENT_TYPE]];
throw err;
throw new ValidationError("invalid content type", [sanityHeaders[Constants.HEADER_CONTENT_TYPE]]);
}
// No erros! Its contains the minimum required attributes

View File

@ -6,6 +6,7 @@ const {
MIME_OCTET_STREAM
} = require("./constants.js");
const Commons = require("./commons.js");
const ValidationError = require("../../validation_error.js");
const STRUCTURED = "structured";
const BINARY = "binary";
@ -29,18 +30,18 @@ function resolveBindingName(payload, headers) {
if (allowedStructuredContentTypes.includes(contentType)) {
return STRUCTURED;
}
throwTypeError("structured+type not allowed", contentType);
throwValidationError("structured+type not allowed", contentType);
} else {
// Binary
if (allowedBinaryContentTypes.includes(contentType)) {
return BINARY;
}
throwTypeError("content type not allowed", contentType);
throwValidationError("content type not allowed", contentType);
}
}
function throwTypeError(msg, contentType) {
const err = new TypeError(msg);
function throwValidationError(msg, contentType) {
const err = new ValidationError(msg);
err.errors = [contentType];
throw err;
}
@ -52,16 +53,16 @@ class Unmarshaller {
unmarshall(payload, headers) {
if (!payload) {
throw new TypeError("payload is null or undefined");
throw new ValidationError("payload is null or undefined");
}
if (!headers) {
throw new TypeError("headers is null or undefined");
throw new ValidationError("headers is null or undefined");
}
// Validation level 1
const sanityHeaders = Commons.sanityAndClone(headers);
if (!sanityHeaders[HEADER_CONTENT_TYPE]) {
throw new TypeError("content-type header not found");
throw new ValidationError("content-type header not found");
}
// Resolve the binding

View File

@ -7,12 +7,12 @@ const Formatter = require("./formats/json/formatter.js");
class CloudEvent {
/**
* Creates a new CloudEvent instance
* @param {Spec} [UserSpec] A CloudEvent version specification
* @param {Formatter} [UserFormatter] Converts the event into a readable string
* @param {Spec} [userSpec] A CloudEvent version specification
* @param {Formatter} [userFormatter] Converts the event into a readable string
*/
constructor(UserSpec, UserFormatter) {
this.spec = (UserSpec) ? new UserSpec(CloudEvent) : new Spec(CloudEvent);
this.formatter = (UserFormatter) ? new UserFormatter() : new Formatter();
constructor(userSpec, userFormatter) {
this.spec = userSpec ? new userSpec(CloudEvent) : new Spec(CloudEvent);
this.formatter = userFormatter ? new userFormatter() : new Formatter();
// The map of extensions
this.extensions = {};

View File

@ -3,11 +3,10 @@ const {
isDefinedOrThrow,
isStringOrObjectOrThrow
} = require("../../utils/fun.js");
const ValidationError = require("../../validation_error.js");
const invalidPayloadTypeError =
new Error("invalid payload type, allowed are: string or object");
const nullOrUndefinedPayload =
new Error("null or undefined payload");
const invalidPayloadTypeError = new ValidationError("invalid payload type, allowed are: string or object");
const nullOrUndefinedPayload = new ValidationError("null or undefined payload");
const asJSON = (v) => (isString(v) ? JSON.parse(v) : v);

View File

@ -1,5 +1,6 @@
const { v4: uuidv4 } = require("uuid");
const Ajv = require("ajv");
const ValidationError = require("../validation_error.js");
const {
isBase64,
@ -168,9 +169,7 @@ Spec03.prototype.check = function(ce) {
const toCheck = (!ce ? this.payload : ce);
if (!isValidAgainstSchema(toCheck)) {
const err = new TypeError("invalid payload");
err.errors = isValidAgainstSchema.errors;
throw err;
throw new ValidationError("invalid payload", [isValidAgainstSchema.errors]);
}
Array.of(toCheck)
@ -178,11 +177,7 @@ Spec03.prototype.check = function(ce) {
.map((tc) => tc.datacontentencoding.toLocaleLowerCase("en-US"))
.filter((dce) => !Object.keys(SUPPORTED_CONTENT_ENCODING).includes(dce))
.forEach((dce) => {
const err = new TypeError("invalid payload");
err.errors = [
`Unsupported content encoding: ${dce}`
];
throw err;
throw new ValidationError("invalid payload", [`Unsupported content encoding: ${dce}`]);
});
Array.of(toCheck)
@ -200,11 +195,7 @@ Spec03.prototype.check = function(ce) {
.filter((tc) => !SUPPORTED_CONTENT_ENCODING[tc.datacontentencoding]
.check(tc.data))
.forEach((tc) => {
const err = new TypeError("invalid payload");
err.errors = [
`Invalid content encoding of data: ${tc.data}`
];
throw err;
throw new ValidationError("invalid payload", [`Invalid content encoding of data: ${tc.data}`]);
});
};
@ -304,7 +295,7 @@ Spec03.prototype.addExtension = function(key, value) {
if (!Object.prototype.hasOwnProperty.call(RESERVED_ATTRIBUTES, key)) {
this.payload[key] = value;
} else {
throw new TypeError(`Reserved attribute name: '${key}'`);
throw new ValidationError(`Reserved attribute name: '${key}'`);
}
return this;
};

View File

@ -1,5 +1,6 @@
const { v4: uuidv4 } = require("uuid");
const Ajv = require("ajv");
const ValidationError = require("../validation_error.js");
const {
asData,
@ -191,9 +192,7 @@ Spec1.prototype.check = function(ce) {
const toCheck = (!ce ? this.payload : ce);
if (!isValidAgainstSchema(toCheck)) {
const err = new TypeError("invalid payload");
err.errors = isValidAgainstSchema.errors;
throw err;
throw new ValidationError("invalid payload", [isValidAgainstSchema.errors]);
}
};
@ -284,10 +283,10 @@ Spec1.prototype.addExtension = function(key, value) {
if (isValidType(value)) {
this.payload[key] = value;
} else {
throw new TypeError("Invalid type of extension value");
throw new ValidationError("Invalid type of extension value");
}
} else {
throw new TypeError(`Reserved attribute name: '${key}'`);
throw new ValidationError(`Reserved attribute name: '${key}'`);
}
return this;
};

18
lib/validation_error.js Normal file
View File

@ -0,0 +1,18 @@
/**
* A Error class that will be thrown when a CloudEvent
* cannot be properly validated against a the specification.
*/
class ValidationError extends TypeError {
/**
* Constructs a new {ValidationError} with the message
* and array of additional errors.
* @param {string} message the error message
* @param {[string]|[ErrorObject]} [errors] any additional errors related to validation
*/
constructor(message, errors) {
super(message);
this.errors = errors ? errors : [];
}
}
module.exports = ValidationError;

View File

@ -8,6 +8,7 @@ const {
BINARY_HEADERS_03,
BINARY_HEADERS_1
} = require("../../../lib/bindings/http/constants.js");
const ValidationError = require("../../../lib/validation_error.js");
const receiver = new HTTPReceiver();
const id = "1234";
@ -30,7 +31,7 @@ describe("HTTP Transport Binding Receiver for CloudEvents", () => {
};
expect(receiver.accept.bind(receiver, {}, payload))
.to.throw("no cloud event detected");
.to.throw(ValidationError, "no cloud event detected");
});
});

View File

@ -1,7 +1,7 @@
const expect = require("chai").expect;
const HTTPBinaryReceiver =
require("../../../lib/bindings/http/receiver_binary_0_3.js");
const HTTPBinaryReceiver = require("../../../lib/bindings/http/receiver_binary_0_3.js");
const ValidationError = require("../../../lib/validation_error.js");
const {
BINARY_HEADERS_03,
SPEC_V03,
@ -19,7 +19,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v0.3", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("payload is null or undefined");
.to.throw(ValidationError, "payload is null or undefined");
});
it("Throw error when attributes arg is null or undefined", () => {
@ -29,7 +29,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v0.3", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("attributes is null or undefined");
.to.throw(ValidationError, "attributes is null or undefined");
});
it("Throw error when payload is not an object or string", () => {
@ -39,7 +39,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v0.3", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("payload must be an object or a string");
.to.throw(ValidationError, "payload must be an object or a string");
});
it("Throw error when headers has no 'ce-type'", () => {
@ -54,7 +54,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v0.3", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("header 'ce-type' not found");
.to.throw(ValidationError, "header 'ce-type' not found");
});
it("Throw error when headers has no 'ce-specversion'", () => {
@ -69,7 +69,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v0.3", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("header 'ce-specversion' not found");
.to.throw(ValidationError, "header 'ce-specversion' not found");
});
it("Throw error when headers has no 'ce-source'", () => {
@ -84,7 +84,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v0.3", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("header 'ce-source' not found");
.to.throw(ValidationError, "header 'ce-source' not found");
});
it("Throw error when headers has no 'ce-id'", () => {
@ -99,7 +99,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v0.3", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("header 'ce-id' not found");
.to.throw(ValidationError, "header 'ce-id' not found");
});
it("Throw error when spec is not 0.3", () => {
@ -115,7 +115,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v0.3", () => {
// act and assert
expect(receiver.parse.bind(receiver, payload, attributes))
.to.throw("invalid spec version");
.to.throw(ValidationError, "invalid spec version");
});
it("Throw error when the content-type is invalid", () => {
@ -131,7 +131,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v0.3", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("invalid content type");
.to.throw(ValidationError, "invalid content type");
});
it("No error when all required headers are in place", () => {

View File

@ -5,6 +5,7 @@ const {
SPEC_V1,
HEADER_CONTENT_TYPE
} = require("../../../lib/bindings/http/constants.js");
const ValidationError = require("../../../lib/validation_error.js");
const HTTPBinaryReceiver =
require("../../../lib/bindings/http/receiver_binary_1.js");
@ -20,7 +21,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("payload is null or undefined");
.to.throw(ValidationError, "payload is null or undefined");
});
it("Throw error when attributes arg is null or undefined", () => {
@ -30,7 +31,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("attributes is null or undefined");
.to.throw(ValidationError, "attributes is null or undefined");
});
it("Throw error when payload is not an object or string", () => {
@ -40,7 +41,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("payload must be an object or a string");
.to.throw(ValidationError, "payload must be an object or a string");
});
it("Throw error when headers has no 'ce-type'", () => {
@ -55,7 +56,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("header 'ce-type' not found");
.to.throw(ValidationError, "header 'ce-type' not found");
});
it("Throw error when headers has no 'ce-specversion'", () => {
@ -70,7 +71,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("header 'ce-specversion' not found");
.to.throw(ValidationError, "header 'ce-specversion' not found");
});
it("Throw error when headers has no 'ce-source'", () => {
@ -85,7 +86,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("header 'ce-source' not found");
.to.throw(ValidationError, "header 'ce-source' not found");
});
it("Throw error when headers has no 'ce-id'", () => {
@ -100,7 +101,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("header 'ce-id' not found");
.to.throw(ValidationError, "header 'ce-id' not found");
});
it("Throw error when spec is not 1.0", () => {
@ -116,7 +117,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
// act and assert
expect(receiver.parse.bind(receiver, payload, attributes))
.to.throw("invalid spec version");
.to.throw(ValidationError, "invalid spec version");
});
it("Throw error when the content-type is invalid", () => {
@ -132,7 +133,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("invalid content type");
.to.throw(ValidationError, "invalid content type");
});
it("No error when content-type is unspecified", () => {
@ -186,8 +187,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
const actual = receiver.parse(payload, attributes);
// assert
expect(actual.getType())
.to.equal("type");
expect(actual.getType()).to.equal("type");
});
it("CloudEvent contains 'specversion'", () => {
@ -209,8 +209,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
const actual = receiver.parse(payload, attributes);
// assert
expect(actual.getSpecversion())
.to.equal(SPEC_V1);
expect(actual.getSpecversion()).to.equal(SPEC_V1);
});
it("CloudEvent contains 'source'", () => {
@ -232,8 +231,8 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
const actual = receiver.parse(payload, attributes);
// assert
expect(actual.getSource())
.to.equal("/source");
expect(actual.getSource()).to.equal("/source");
});
it("CloudEvent contains 'id'", () => {
@ -255,8 +254,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
const actual = receiver.parse(payload, attributes);
// assert
expect(actual.getId())
.to.equal("id");
expect(actual.getId()).to.equal("id");
});
it("CloudEvent contains 'time'", () => {
@ -278,8 +276,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
const actual = receiver.parse(payload, attributes);
// assert
expect(actual.getTime())
.to.equal("2019-06-16T11:42:00.000Z");
expect(actual.getTime()).to.equal("2019-06-16T11:42:00.000Z");
});
it("CloudEvent contains 'dataschema'", () => {
@ -301,8 +298,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
const actual = receiver.parse(payload, attributes);
// assert
expect(actual.getDataschema())
.to.equal("http://schema.registry/v1");
expect(actual.getDataschema()).to.equal("http://schema.registry/v1");
});
it("CloudEvent contains 'contenttype' (application/json)", () => {
@ -324,8 +320,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
const actual = receiver.parse(payload, attributes);
// assert
expect(actual.getDataContentType())
.to.equal("application/json");
expect(actual.getDataContentType()).to.equal("application/json");
});
it("CloudEvent contains 'contenttype' (application/octet-stream)", () => {
@ -345,8 +340,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
const actual = receiver.parse(payload, attributes);
// assert
expect(actual.getDataContentType())
.to.equal("application/octet-stream");
expect(actual.getDataContentType()).to.equal("application/octet-stream");
});
it("CloudEvent contains 'data' (application/json)", () => {
@ -368,8 +362,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
const actual = receiver.parse(payload, attributes);
// assert
expect(actual.getData())
.to.deep.equal(payload);
expect(actual.getData()).to.deep.equal(payload);
});
it("CloudEvent contains 'data' (application/octet-stream)", () => {
@ -389,8 +382,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
const actual = receiver.parse(payload, attributes);
// assert
expect(actual.getData())
.to.deep.equal(payload);
expect(actual.getData()).to.deep.equal(payload);
});
it("The content of 'data' is base64 for binary", () => {
@ -417,8 +409,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
const actual = receiver.parse(payload, attributes);
// assert
expect(actual.getData())
.to.deep.equal(expected);
expect(actual.getData()).to.deep.equal(expected);
});
it("No error when all attributes are in place", () => {
@ -440,11 +431,9 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
const actual = receiver.parse(payload, attributes);
// assert
expect(actual)
.to.be.an("object");
expect(actual).to.be.an("object");
expect(actual)
.to.have.property("format");
expect(actual).to.have.property("format");
});
it("Should accept 'extension1'", () => {
@ -469,8 +458,7 @@ describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => {
const actualExtensions = actual.getExtensions();
// assert
expect(actualExtensions.extension1)
.to.equal(extension1);
expect(actualExtensions.extension1).to.equal(extension1);
});
});
});

View File

@ -1,8 +1,7 @@
const expect = require("chai").expect;
const v03 = require("../../../v03/index.js");
const HTTPStructuredReceiver =
require("../../../lib/bindings/http/receiver_structured_0_3.js");
const ValidationError = require("../../../lib/validation_error.js");
const HTTPStructuredReceiver = require("../../../lib/bindings/http/receiver_structured_0_3.js");
const receiver = new HTTPStructuredReceiver();
@ -31,7 +30,7 @@ describe("HTTP Transport Binding Structured Receiver CloudEvents v0.3", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("payload is null or undefined");
.to.throw(ValidationError, "payload is null or undefined");
});
it("Throw error when attributes arg is null or undefined", () => {
@ -41,7 +40,7 @@ describe("HTTP Transport Binding Structured Receiver CloudEvents v0.3", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("attributes is null or undefined");
.to.throw(ValidationError, "attributes is null or undefined");
});
it("Throw error when payload is not an object or string", () => {
@ -51,7 +50,7 @@ describe("HTTP Transport Binding Structured Receiver CloudEvents v0.3", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("payload must be an object or string");
.to.throw(ValidationError, "payload must be an object or string");
});
it("Throw error when the content-type is invalid", () => {
@ -63,7 +62,7 @@ describe("HTTP Transport Binding Structured Receiver CloudEvents v0.3", () => {
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("invalid content type");
.to.throw(ValidationError, "invalid content type");
});
it("Throw error data content encoding is base64, but 'data' is not",
@ -87,7 +86,7 @@ describe("HTTP Transport Binding Structured Receiver CloudEvents v0.3", () => {
// act and assert
expect(receiver.parse.bind(receiver, payload, attributes))
.to.throw("invalid payload");
.to.throw(ValidationError, "invalid payload");
});
it("No error when all required stuff are in place", () => {
@ -135,7 +134,7 @@ describe("HTTP Transport Binding Structured Receiver CloudEvents v0.3", () => {
// act and assert
expect(receiver.parse.bind(receiver, payload, headers))
.to.throw("invalid content type");
.to.throw(ValidationError, "invalid content type");
});
it("Should accept event that follows the spec", () => {

View File

@ -1,11 +1,9 @@
const expect = require("chai").expect;
const v1 = require("../../../v1/index.js");
const { CloudEvent } = require("../../../index.js");
const { asBase64 } = require("../../../lib/utils/fun.js");
const HTTPStructuredReceiver =
require("../../../lib/bindings/http/receiver_structured_1.js");
const ValidationError = require("../../../lib/validation_error.js");
const HTTPStructuredReceiver = require("../../../lib/bindings/http/receiver_structured_1.js");
const receiver = new HTTPStructuredReceiver();
@ -30,7 +28,7 @@ describe("HTTP Transport Binding Structured Receiver for CloudEvents v1.0",
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("payload is null or undefined");
.to.throw(ValidationError, "payload is null or undefined");
});
it("Throw error when attributes arg is null or undefined", () => {
@ -40,7 +38,7 @@ describe("HTTP Transport Binding Structured Receiver for CloudEvents v1.0",
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("attributes is null or undefined");
.to.throw(ValidationError, "attributes is null or undefined");
});
it("Throw error when payload is not an object or string", () => {
@ -50,7 +48,7 @@ describe("HTTP Transport Binding Structured Receiver for CloudEvents v1.0",
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("payload must be an object or string");
.to.throw(ValidationError, "payload must be an object or string");
});
it("Throw error when the content-type is invalid", () => {
@ -62,7 +60,7 @@ describe("HTTP Transport Binding Structured Receiver for CloudEvents v1.0",
// act and assert
expect(receiver.check.bind(receiver, payload, attributes))
.to.throw("invalid content type");
.to.throw(ValidationError, "invalid content type");
});
it("No error when all required stuff are in place", () => {
@ -95,7 +93,7 @@ describe("HTTP Transport Binding Structured Receiver for CloudEvents v1.0",
// act and assert
expect(receiver.parse.bind(receiver, payload, headers))
.to.throw("invalid content type");
.to.throw(ValidationError, "invalid content type");
});
it("Should accept event that follows the spec", () => {

View File

@ -1,4 +1,5 @@
const expect = require("chai").expect;
const ValidationError = require("../../../lib/validation_error.js");
const Unmarshaller = require("../../../lib/bindings/http/unmarshaller_0_3.js");
const { CloudEvent } = require("../../../index.js");
const v03 = require("../../../v03/index.js");
@ -23,18 +24,18 @@ const un = new Unmarshaller();
describe("HTTP Transport Binding Unmarshaller for CloudEvents v0.3", () => {
it("Throw error when payload is null", () => {
expect(() => un.unmarshall(null)).to.throw("payload is null or undefined");
expect(() => un.unmarshall(null)).to.throw(ValidationError, "payload is null or undefined");
});
it("Throw error when headers is null", () => {
expect(() => un.unmarshall({})).to.throw("headers is null or undefined");
expect(() => un.unmarshall({})).to.throw(ValidationError, "headers is null or undefined");
expect(() => un.unmarshall({}, null)).to
.throw("headers is null or undefined");
.throw(ValidationError, "headers is null or undefined");
});
it("Throw error when there is no content-type header", () => {
expect(() => un.unmarshall({}, {})).to
.throw("content-type header not found");
.throw(ValidationError, "content-type header not found");
});
it("Throw error when content-type is not allowed", () => {
@ -42,7 +43,7 @@ describe("HTTP Transport Binding Unmarshaller for CloudEvents v0.3", () => {
"content-type": "text/xml"
};
expect(() => un.unmarshall({}, headers)).to
.throw("content type not allowed");
.throw(ValidationError, "content type not allowed");
});
describe("Structured", () => {
@ -54,7 +55,7 @@ describe("HTTP Transport Binding Unmarshaller for CloudEvents v0.3", () => {
// act and assert
expect(() => un.unmarshall({}, headers)).to
.throw("structured+type not allowed");
.throw(ValidationError, "structured+type not allowed");
});
it("Throw error when the event does not follow the spec 0.3", () => {
@ -67,11 +68,10 @@ describe("HTTP Transport Binding Unmarshaller for CloudEvents v0.3", () => {
"content-type": "application/cloudevents+json"
};
expect(() => un.unmarshall(payload, headers)).to
.throw(TypeError);
expect(() => un.unmarshall(payload, headers)).to.throw(ValidationError);
});
it("Should accept event that follow the spec 0.3", () => {
it("Should accept event TypeErrorthat follow the spec 0.3", () => {
const payload =
new CloudEvent(v03.Spec)
.type(type)
@ -129,7 +129,7 @@ describe("HTTP Transport Binding Unmarshaller for CloudEvents v0.3", () => {
};
expect(() => un.unmarshall(payload, attributes)).to
.throw("content type not allowed");
.throw(ValidationError, "content type not allowed");
});
it("Throw error when the event does not follow the spec 0.3", () => {
@ -148,7 +148,7 @@ describe("HTTP Transport Binding Unmarshaller for CloudEvents v0.3", () => {
};
expect(() => un.unmarshall(payload, attributes)).to
.throw("header 'ce-specversion' not found");
.throw(ValidationError, "header 'ce-specversion' not found");
});
it("No error when all attributes are in place", () => {
@ -186,7 +186,7 @@ describe("HTTP Transport Binding Unmarshaller for CloudEvents v0.3", () => {
};
expect(() => un.unmarshall(payload, attributes)).to
.throw("unsupported datacontentencoding");
.throw(ValidationError, "unsupported datacontentencoding");
});
it("No error when 'ce-datacontentencoding' is base64", () => {

View File

@ -1,5 +1,6 @@
const expect = require("chai").expect;
const Parser = require("../../../lib/formats/json/parser.js");
const ValidationError = require("../../../lib/validation_error.js");
describe("JSON Event Format Parser", () => {
it("Throw error when payload is an integer", () => {
@ -9,7 +10,7 @@ describe("JSON Event Format Parser", () => {
// act and assert
expect(parser.parse.bind(parser, payload))
.to.throw("invalid payload type, allowed are: string or object");
.to.throw(ValidationError, "invalid payload type, allowed are: string or object");
});
it("Throw error when payload is null", () => {
@ -18,8 +19,7 @@ describe("JSON Event Format Parser", () => {
const parser = new Parser();
// act and assert
expect(parser.parse.bind(parser, payload))
.to.throw("null or undefined payload");
expect(parser.parse.bind(parser, payload)).to.throw(ValidationError, "null or undefined payload");
});
it("Throw error when payload is undefined", () => {
@ -27,8 +27,7 @@ describe("JSON Event Format Parser", () => {
const parser = new Parser();
// act and assert
expect(parser.parse.bind(parser))
.to.throw("null or undefined payload");
expect(parser.parse.bind(parser)).to.throw(ValidationError, "null or undefined payload");
});
it("Throw error when payload is a float", () => {
@ -38,7 +37,7 @@ describe("JSON Event Format Parser", () => {
// act and assert
expect(parser.parse.bind(parser, payload))
.to.throw("invalid payload type, allowed are: string or object");
.to.throw(ValidationError, "invalid payload type, allowed are: string or object");
});
it("Throw error when payload is an invalid JSON", () => {
@ -46,9 +45,8 @@ describe("JSON Event Format Parser", () => {
const payload = "gg";
const parser = new Parser();
// act and assert
expect(parser.parse.bind(parser, payload))
.to.throw("Unexpected token g in JSON at position 0");
// TODO: Should the parser catch the SyntaxError and re-throw a ValidationError?
expect(parser.parse.bind(parser, payload)).to.throw(SyntaxError, "Unexpected token g in JSON at position 0");
});
it("Must accept when the payload is a string well formed as JSON", () => {
@ -60,7 +58,6 @@ describe("JSON Event Format Parser", () => {
const actual = parser.parse(payload);
// assert
expect(actual)
.to.be.an("object");
expect(actual).to.be.an("object");
});
});

View File

@ -6,6 +6,7 @@ const {
ENCODING_BASE64,
SPEC_V03
} = require("../lib/bindings/http/constants.js");
const ValidationError = require("../lib/validation_error.js");
const id = "97699ec2-a8d9-47c1-bfa0-ff7aa526f838";
const type = "com.github.pull.create";
@ -83,7 +84,7 @@ describe("CloudEvents Spec v0.3", () => {
it("should throw an error when use a reserved name as extension", () => {
expect(cloudevent.addExtension.bind(cloudevent, "id"))
.to.throw("Reserved attribute name: 'id'");
.to.throw(ValidationError, "Reserved attribute name: 'id'");
});
});
@ -92,16 +93,14 @@ describe("CloudEvents Spec v0.3", () => {
it("should throw an error when is absent", () => {
delete cloudevent.spec.payload.id;
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
.to.throw(ValidationError, "invalid payload");
cloudevent.spec.payload.id = id;
});
it("should throw an erro when is empty", () => {
cloudevent.spec.payload.id = "";
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
.to.throw(ValidationError, "invalid payload");
cloudevent.spec.payload.id = id;
});
});
@ -110,8 +109,7 @@ describe("CloudEvents Spec v0.3", () => {
it("should throw an error when is absent", () => {
delete cloudevent.spec.payload.source;
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
.to.throw(ValidationError, "invalid payload");
cloudevent.spec.payload.source = source;
});
});
@ -120,16 +118,14 @@ describe("CloudEvents Spec v0.3", () => {
it("should throw an error when is absent", () => {
delete cloudevent.spec.payload.specversion;
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
.to.throw(ValidationError, "invalid payload");
cloudevent.spec.payload.specversion = SPEC_V03;
});
it("should throw an error when is empty", () => {
cloudevent.spec.payload.specversion = "";
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
.to.throw(ValidationError, "invalid payload");
cloudevent.spec.payload.specversion = SPEC_V03;
});
});
@ -138,16 +134,14 @@ describe("CloudEvents Spec v0.3", () => {
it("should throw an error when is absent", () => {
delete cloudevent.spec.payload.type;
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
.to.throw(ValidationError, "invalid payload");
cloudevent.spec.payload.type = type;
});
it("should throw an error when is an empty string", () => {
cloudevent.type("");
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
.to.throw(ValidationError, "invalid payload");
cloudevent.type(type);
});
@ -163,8 +157,7 @@ describe("CloudEvents Spec v0.3", () => {
.data("Y2xvdWRldmVudHMK")
.dataContentEncoding("binary");
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
.to.throw(ValidationError, "invalid payload");
delete cloudevent.spec.payload.datacontentencoding;
cloudevent.data(data);
});
@ -177,8 +170,7 @@ describe("CloudEvents Spec v0.3", () => {
.dataContentType("text/plain");
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
.to.throw(ValidationError, "invalid payload");
delete cloudevent.spec.payload.datacontentencoding;
cloudevent.data(data);
@ -216,8 +208,7 @@ describe("CloudEvents Spec v0.3", () => {
it("should throw an error when is an empty string", () => {
cloudevent.subject("");
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
.to.throw(ValidationError, "invalid payload");
cloudevent.subject(type);
});
});

View File

@ -3,6 +3,7 @@ const Spec1 = require("../lib/specs/spec_1.js");
const { CloudEvent } = require("../index.js");
const { v4: uuidv4 } = require("uuid");
const { asBase64 } = require("../lib/utils/fun.js");
const ValidationError = require("../lib/validation_error.js");
const id = uuidv4();
const type = "com.github.pull.create";
@ -106,13 +107,13 @@ describe("CloudEvents Spec v1.0", () => {
it("should throw an error when use a reserved name as extension", () => {
expect(cloudevent.addExtension.bind(cloudevent, "id"))
.to.throw("Reserved attribute name: 'id'");
.to.throw(ValidationError, "Reserved attribute name: 'id'");
});
it("should throw an error when use an invalid type", () => {
expect(cloudevent
.addExtension.bind(cloudevent, "invalid-val", { cool: "nice" }))
.to.throw("Invalid type of extension value");
.to.throw(ValidationError, "Invalid type of extension value");
});
});
@ -122,15 +123,14 @@ describe("CloudEvents Spec v1.0", () => {
delete cloudevent.spec.payload.id;
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
.throw(ValidationError, "invalid payload");
cloudevent.spec.payload.id = id;
});
it("should throw an error when is empty", () => {
cloudevent.spec.payload.id = "";
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
.to.throw(ValidationError, "invalid payload");
cloudevent.spec.payload.id = id;
});
});
@ -139,8 +139,7 @@ describe("CloudEvents Spec v1.0", () => {
it("should throw an error when is absent", () => {
delete cloudevent.spec.payload.source;
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
.to.throw(ValidationError, "invalid payload");
cloudevent.spec.payload.source = source;
});
});
@ -149,16 +148,14 @@ describe("CloudEvents Spec v1.0", () => {
it("should throw an error when is absent", () => {
delete cloudevent.spec.payload.specversion;
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
.to.throw(ValidationError, "invalid payload");
cloudevent.spec.payload.specversion = "1.0";
});
it("should throw an error when is empty", () => {
cloudevent.spec.payload.specversion = "";
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
.to.throw(ValidationError, "invalid payload");
cloudevent.spec.payload.specversion = "1.0";
});
});
@ -167,16 +164,14 @@ describe("CloudEvents Spec v1.0", () => {
it("should throw an error when is absent", () => {
delete cloudevent.spec.payload.type;
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
.to.throw(ValidationError, "invalid payload");
cloudevent.spec.payload.type = type;
});
it("should throw an error when is an empty string", () => {
cloudevent.type("");
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
.to.throw(ValidationError, "invalid payload");
cloudevent.type(type);
});
@ -190,8 +185,7 @@ describe("CloudEvents Spec v1.0", () => {
it("should throw an error when is an empty string", () => {
cloudevent.subject("");
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
.to.throw(ValidationError, "invalid payload");
cloudevent.subject(type);
});
});