From 645001af0f99574b86b02ffb7ccc343f198bedce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabio=20Jos=C3=A9?= Date: Mon, 4 Nov 2019 09:44:39 -0300 Subject: [PATCH] Http receiver binary for spec 1.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fabio José --- lib/bindings/http/receiver_binary_1.js | 106 +++++ test/bindings/http/receiver_binary_1_tests.js | 428 ++++++++++++++++++ 2 files changed, 534 insertions(+) create mode 100644 lib/bindings/http/receiver_binary_1.js create mode 100644 test/bindings/http/receiver_binary_1_tests.js diff --git a/lib/bindings/http/receiver_binary_1.js b/lib/bindings/http/receiver_binary_1.js new file mode 100644 index 0000000..128b479 --- /dev/null +++ b/lib/bindings/http/receiver_binary_1.js @@ -0,0 +1,106 @@ +const Constants = require("./constants.js"); +const Spec = require("../../specs/spec_1.js"); + +const JSONParser = require("../../formats/json/parser.js"); +const Base64Parser = require("../../formats/base64.js"); + +const BinaryHTTPReceiver = require("./receiver_binary.js"); + +const { + isDefinedOrThrow, + isStringOrObjectOrThrow +} = require("../../utils/fun.js"); + +const parserByType = {}; +parserByType[Constants.MIME_JSON] = new JSONParser(); +parserByType[Constants.MIME_OCTET_STREAM] = { + parse(payload) { return payload; } +}; + +const parsersByEncoding = {}; +parsersByEncoding[null] = parserByType; +parsersByEncoding[undefined] = parserByType; + +// base64 +parsersByEncoding[Constants.ENCODING_BASE64] = {}; +parsersByEncoding[Constants.ENCODING_BASE64][Constants.MIME_JSON] = + new JSONParser(new Base64Parser()); +parsersByEncoding[Constants.ENCODING_BASE64][Constants.MIME_OCTET_STREAM] = { + parse(payload) { return payload; } +}; + +const allowedContentTypes = []; +allowedContentTypes.push(Constants.MIME_JSON); +allowedContentTypes.push(Constants.MIME_OCTET_STREAM); + +const allowedEncodings = []; +allowedEncodings.push(Constants.ENCODING_BASE64); + +const requiredHeaders = []; +requiredHeaders.push(Constants.BINARY_HEADERS_1.TYPE); +requiredHeaders.push(Constants.BINARY_HEADERS_1.SPEC_VERSION); +requiredHeaders.push(Constants.BINARY_HEADERS_1.SOURCE); +requiredHeaders.push(Constants.BINARY_HEADERS_1.ID); + +const setterByHeader = {}; +setterByHeader[Constants.BINARY_HEADERS_1.TYPE] = { + name : "type", + parser : (v) => v +}; +setterByHeader[Constants.BINARY_HEADERS_1.SPEC_VERSION] = { + name : "specversion", + parser : (v) => "1.0" +}; +setterByHeader[Constants.BINARY_HEADERS_1.SOURCE] = { + name : "source", + parser: (v) => v +}; +setterByHeader[Constants.BINARY_HEADERS_1.ID] = { + name : "id", + parser : (v) => v +}; +setterByHeader[Constants.BINARY_HEADERS_1.TIME] = { + name : "time", + parser : (v) => new Date(Date.parse(v)) +}; +setterByHeader[Constants.BINARY_HEADERS_1.DATA_SCHEMA] = { + name: "dataschema", + parser: (v) => v +}; +setterByHeader[Constants.HEADER_CONTENT_TYPE] = { + name: "dataContentType", + parser: (v) => v +}; +setterByHeader[Constants.BINARY_HEADERS_1.SUBJECT] = { + name: "subject", + parser: (v) => v +}; + +function checkDecorator(payload, headers) { +} + +function Receiver(configuration) { + this.receiver = new BinaryHTTPReceiver( + parsersByEncoding, + setterByHeader, + allowedContentTypes, + requiredHeaders, + Spec, + Constants.SPEC_V1, + Constants.BINARY_HEADERS_1.EXTENSIONS_PREFIX, + checkDecorator + ); +} + +Receiver.prototype.check = function(payload, headers) { + this.receiver.check(payload, headers); +}; + +Receiver.prototype.parse = function(payload, headers) { + // firstly specific local checks + this.check(payload, headers); + + return this.receiver.parse(payload, headers); +}; + +module.exports = Receiver; diff --git a/test/bindings/http/receiver_binary_1_tests.js b/test/bindings/http/receiver_binary_1_tests.js new file mode 100644 index 0000000..ff81d76 --- /dev/null +++ b/test/bindings/http/receiver_binary_1_tests.js @@ -0,0 +1,428 @@ +var expect = require("chai").expect; + +var HTTPBinaryReceiver = + require("../../../lib/bindings/http/receiver_binary_1.js"); + +var receiver = new HTTPBinaryReceiver(); + +describe("HTTP Transport Binding Binary Receiver for CloudEvents v1.0", () => { + describe("Check", () => { + it("Throw error when payload arg is null or undefined", () => { + // setup + var payload = null; + var attributes = {}; + + // act and assert + expect(receiver.check.bind(receiver, payload, attributes)) + .to.throw("payload is null or undefined"); + }); + + it("Throw error when attributes arg is null or undefined", () => { + // setup + var payload = {}; + var attributes = null; + + // act and assert + expect(receiver.check.bind(receiver, payload, attributes)) + .to.throw("attributes is null or undefined"); + }); + + it("Throw error when payload is not an object or string", () => { + // setup + var payload = 1.2; + var attributes = {}; + + // act and assert + expect(receiver.check.bind(receiver, payload, attributes)) + .to.throw("payload must be an object or a string"); + }); + + it("Throw error when headers has no 'ce-type'", () => { + // setup + var payload = {}; + var attributes = { + "ce-specversion" : "specversion", + "ce-source" : "source", + "ce-id" : "id", + "Content-Type" : "application/json" + }; + + // act and assert + expect(receiver.check.bind(receiver, payload, attributes)) + .to.throw("header 'ce-type' not found"); + }); + + it("Throw error when headers has no 'ce-specversion'", () => { + // setup + var payload = {}; + var attributes = { + "ce-type" : "type", + "ce-source" : "source", + "ce-id" : "id", + "Content-Type" : "application/json" + }; + + // act and assert + expect(receiver.check.bind(receiver, payload, attributes)) + .to.throw("header 'ce-specversion' not found"); + }); + + it("Throw error when headers has no 'ce-source'", () => { + // setup + var payload = {}; + var attributes = { + "ce-type" : "type", + "ce-specversion" : "specversion", + "ce-id" : "id", + "Content-Type" : "application/json" + }; + + // act and assert + expect(receiver.check.bind(receiver, payload, attributes)) + .to.throw("header 'ce-source' not found"); + }); + + it("Throw error when headers has no 'ce-id'", () => { + // setup + var payload = {}; + var attributes = { + "ce-type" : "type", + "ce-specversion" : "specversion", + "ce-source" : "source", + "Content-Type" : "application/json" + }; + + // act and assert + expect(receiver.check.bind(receiver, payload, attributes)) + .to.throw("header 'ce-id' not found"); + }); + + it("Throw error when spec is not 1.0", () => { + // setup + var payload = {}; + var attributes = { + "ce-type" : "type", + "ce-specversion" : "0.2", + "ce-source" : "source", + "ce-id" : "id", + "Content-Type" : "application/json" + }; + + // act and assert + expect(receiver.parse.bind(receiver, payload, attributes)) + .to.throw("invalid spec version"); + }); + + it("Throw error when the content-type is invalid", () => { + // setup + var payload = {}; + var attributes = { + "ce-type" : "type", + "ce-specversion" : "specversion", + "ce-source" : "source", + "ce-id" : "id", + "Content-Type" : "text/html" + }; + + // act and assert + expect(receiver.check.bind(receiver, payload, attributes)) + .to.throw("invalid content type"); + }); + + it("No error when all required headers are in place", () => { + // setup + var payload = {}; + var attributes = { + "ce-type" : "type", + "ce-specversion" : "1.0", + "ce-source" : "source", + "ce-id" : "id", + "Content-Type" : "application/json" + }; + + // act and assert + expect(receiver.check.bind(receiver, payload, attributes)) + .to.not.throw(); + }); + }); + + describe("Parse", () => { + it("Cloudevent contains 'type'", () => { + // setup + var payload = { + "data" : "dataString" + }; + var attributes = { + "ce-type" : "type", + "ce-specversion" : "1.0", + "ce-source" : "source", + "ce-id" : "id", + "ce-time" : "2019-06-16T11:42:00Z", + "ce-dataschema" : "http://schema.registry/v1", + "Content-Type" : "application/json" + }; + + // act + var actual = receiver.parse(payload, attributes); + + // assert + expect(actual.getType()) + .to.equal("type"); + }); + + it("Cloudevent contains 'specversion'", () => { + // setup + var payload = { + "data" : "dataString" + }; + var attributes = { + "ce-type" : "type", + "ce-specversion" : "1.0", + "ce-source" : "source", + "ce-id" : "id", + "ce-time" : "2019-06-16T11:42:00Z", + "ce-dataschema" : "http://schema.registry/v1", + "Content-Type" : "application/json" + }; + + // act + var actual = receiver.parse(payload, attributes); + + // assert + expect(actual.getSpecversion()) + .to.equal("1.0"); + }); + + it("Cloudevent contains 'source'", () => { + // setup + var payload = { + "data" : "dataString" + }; + var attributes = { + "ce-type" : "type", + "ce-specversion" : "1.0", + "ce-source" : "/source", + "ce-id" : "id", + "ce-time" : "2019-06-16T11:42:00Z", + "ce-dataschema" : "http://schema.registry/v1", + "Content-Type" : "application/json" + }; + + // act + var actual = receiver.parse(payload, attributes); + + // assert + expect(actual.getSource()) + .to.equal("/source"); + }); + + it("Cloudevent contains 'id'", () => { + // setup + var payload = { + "data" : "dataString" + }; + var attributes = { + "ce-type" : "type", + "ce-specversion" : "1.0", + "ce-source" : "/source", + "ce-id" : "id", + "ce-time" : "2019-06-16T11:42:00Z", + "ce-dataschema" : "http://schema.registry/v1", + "Content-Type" : "application/json" + }; + + // act + var actual = receiver.parse(payload, attributes); + + // assert + expect(actual.getId()) + .to.equal("id"); + }); + + it("Cloudevent contains 'time'", () => { + // setup + var payload = { + "data" : "dataString" + }; + var attributes = { + "ce-type" : "type", + "ce-specversion" : "1.0", + "ce-source" : "/source", + "ce-id" : "id", + "ce-time" : "2019-06-16T11:42:00.000Z", + "ce-dataschema" : "http://schema.registry/v1", + "Content-Type" : "application/json" + }; + + // act + var actual = receiver.parse(payload, attributes); + + // assert + expect(actual.getTime()) + .to.equal("2019-06-16T11:42:00.000Z"); + }); + + it("Cloudevent contains 'schemaurl'", () => { + // setup + var payload = { + "data" : "dataString" + }; + var attributes = { + "ce-type" : "type", + "ce-specversion" : "1.0", + "ce-source" : "/source", + "ce-id" : "id", + "ce-time" : "2019-06-16T11:42:00Z", + "ce-dataschema" : "http://schema.registry/v1", + "Content-Type" : "application/json" + }; + + // act + var actual = receiver.parse(payload, attributes); + + // assert + expect(actual.getDataschema()) + .to.equal("http://schema.registry/v1"); + }); + + it("Cloudevent contains 'contenttype' (application/json)", () => { + // setup + var payload = { + "data" : "dataString" + }; + var attributes = { + "ce-type" : "type", + "ce-specversion" : "1.0", + "ce-source" : "/source", + "ce-id" : "id", + "ce-time" : "2019-06-16T11:42:00Z", + "ce-dataschema" : "http://schema.registry/v1", + "Content-Type" : "application/json" + }; + + // act + var actual = receiver.parse(payload, attributes); + + // assert + expect(actual.getDataContentType()) + .to.equal("application/json"); + }); + + it("Cloudevent contains 'contenttype' (application/octet-stream)", () => { + // setup + var payload = "The payload is binary data"; + var attributes = { + "ce-type" : "type", + "ce-specversion" : "1.0", + "ce-source" : "/source", + "ce-id" : "id", + "ce-time" : "2019-06-16T11:42:00Z", + "ce-dataschema" : "http://schema.registry/v1", + "Content-Type" : "application/octet-stream" + }; + + // act + var actual = receiver.parse(payload, attributes); + + // assert + expect(actual.getDataContentType()) + .to.equal("application/octet-stream"); + }); + + it("Cloudevent contains 'data' (application/json)", () => { + // setup + var payload = { + "data" : "dataString" + }; + var attributes = { + "ce-type" : "type", + "ce-specversion" : "1.0", + "ce-source" : "/source", + "ce-id" : "id", + "ce-time" : "2019-06-16T11:42:00Z", + "ce-dataschema" : "http://schema.registry/v1", + "Content-Type" : "application/json" + }; + + // act + var actual = receiver.parse(payload, attributes); + + // assert + expect(actual.getData()) + .to.deep.equal(payload); + }); + + it("Cloudevent contains 'data' (application/octet-stream)", () => { + // setup + var payload = "The payload is binary data"; + var attributes = { + "ce-type" : "type", + "ce-specversion" : "1.0", + "ce-source" : "/source", + "ce-id" : "id", + "ce-time" : "2019-06-16T11:42:00Z", + "ce-dataschema" : "http://schema.registry/v1", + "Content-Type" : "application/octet-stream" + }; + + // act + var actual = receiver.parse(payload, attributes); + + // assert + expect(actual.getData()) + .to.deep.equal(payload); + }); + + it("No error when all attributes are in place", () => { + // setup + var payload = { + "data" : "dataString" + }; + var attributes = { + "ce-type" : "type", + "ce-specversion" : "1.0", + "ce-source" : "source", + "ce-id" : "id", + "ce-time" : "2019-06-16T11:42:00Z", + "ce-dataschema" : "http://schema.registry/v1", + "Content-Type" : "application/json" + }; + + // act + var actual = receiver.parse(payload, attributes); + + // assert + expect(actual) + .to.be.an("object"); + + expect(actual) + .to.have.property("format"); + }); + + it("Should accept 'extension1'", () => { + // setup + var extension1 = "mycuston-ext1"; + var payload = { + "data" : "dataString" + }; + var attributes = { + "ce-type" : "type", + "ce-specversion" : "1.0", + "ce-source" : "source", + "ce-id" : "id", + "ce-time" : "2019-06-16T11:42:00Z", + "ce-dataschema" : "http://schema.registry/v1", + "Content-Type" : "application/json", + "ce-extension1" : extension1 + }; + + // act + var actual = receiver.parse(payload, attributes); + var actualExtensions = actual.getExtensions(); + + // assert + expect(actualExtensions["extension1"]) + .to.equal(extension1); + }); + }); +});