Implementing the spec 0.3 attributes

Signed-off-by: Fabio José <fabiojose@gmail.com>
This commit is contained in:
Fabio José 2019-07-28 21:53:34 -03:00
parent 7415e6e9cc
commit b8f1012d1d
3 changed files with 443 additions and 0 deletions

88
ext/spec_0_3.json Normal file
View File

@ -0,0 +1,88 @@
{
"$ref": "#/definitions/event",
"definitions": {
"specversion": {
"type": "string",
"minLength": 1,
"const": "0.3"
},
"datacontenttype": {
"type": "string"
},
"data": {
"type": [
"object",
"string"
]
},
"event": {
"properties": {
"specversion": {
"$ref": "#/definitions/specversion"
},
"datacontenttype": {
"$ref": "#/definitions/datacontenttype"
},
"data": {
"$ref": "#/definitions/data"
},
"id": {
"$ref": "#/definitions/id"
},
"time": {
"$ref": "#/definitions/time"
},
"schemaurl": {
"$ref": "#/definitions/schemaurl"
},
"subject": {
"$ref": "#/definitions/subject"
},
"type": {
"$ref": "#/definitions/type"
},
"extensions": {
"$ref": "#/definitions/extensions"
},
"source": {
"$ref": "#/definitions/source"
}
},
"required": [
"specversion",
"id",
"type",
"source"
],
"type": "object"
},
"id": {
"type": "string",
"minLength": 1
},
"time": {
"format": "date-time",
"type": "string"
},
"schemaurl": {
"type": "string",
"format": "uri-reference"
},
"subject": {
"type": "string",
"minLength": 1
},
"type": {
"type": "string",
"minLength": 1
},
"extensions": {
"type": "object"
},
"source": {
"format": "uri-reference",
"type": "string"
}
},
"type": "object"
}

184
lib/specs/spec_0_3.js Normal file
View File

@ -0,0 +1,184 @@
const uuid = require("uuid/v4");
const empty = require("is-empty");
const Ajv = require("ajv");
// Reserved attributes names
const reserved = {
type: "type",
specversion: "specversion",
source: "source",
id: "id",
time: "time",
schemaurl: "schemaurl",
datacontentencoding: "datacontentencoding",
datacontenttype: "datacontenttype",
subject : "subject",
data: "data"
};
const schema = require("../../ext/spec_0_3.json");
const ajv = new Ajv({
extendRefs: true
});
const validate = ajv.compile(schema);
function Spec03(_caller){
this.payload = {
specversion: "0.3",
id: uuid()
};
/*
* Used to inject compatibility methods or attributes
*/
this.caller = _caller;
/*
* Inject compatibility methods
*/
this.caller.prototype.dataContentEncoding = function(encoding){
this.spec.dataContentEncoding(encoding);
return this;
};
this.caller.prototype.getDataContentEncoding = function(){
return this.spec.getDataContentEncoding();
};
this.caller.prototype.dataContentType = function(contentType){
this.spec.dataContentType(contentType);
return this;
};
this.caller.prototype.getDataContentType = function(){
return this.spec.getDataContentType();
};
this.caller.prototype.subject = function(_subject){
this.spec.subject(_subject);
return this;
};
this.caller.prototype.getSubject = function(){
return this.spec.getSubject();
};
}
/*
* Check the spec constraints
*/
Spec03.prototype.check = function(ce){
var toCheck = ce;
if(!toCheck) {
toCheck = this.payload;
}
var valid = validate(toCheck);
if(!valid) {
throw {message: "invalid payload", errors: validate.errors};
}
};
Spec03.prototype.id = function(_id){
this.payload["id"] = _id;
return this;
};
Spec03.prototype.getId = function() {
return this.payload["id"];
};
Spec03.prototype.source = function(_source){
this.payload["source"] = _source;
return this;
};
Spec03.prototype.getSource = function() {
return this.payload["source"];
};
Spec03.prototype.specversion = function(_specversion){
// does not set! This is right
return this;
};
Spec03.prototype.getSpecversion = function() {
return this.payload["specversion"];
};
Spec03.prototype.type = function(_type){
this.payload["type"] = _type;
return this;
};
Spec03.prototype.getType = function(){
return this.payload["type"];
};
Spec03.prototype.dataContentEncoding = function(encoding) {
this.payload["datacontentencoding"] = encoding;
return this;
};
Spec03.prototype.getDataContentEncoding = function() {
return this.payload["datacontentencoding"];
};
// maps to datacontenttype
Spec03.prototype.contenttype = function(_contenttype){
this.payload["datacontenttype"] = _contenttype;
return this;
};
Spec03.prototype.getContenttype = function() {
return this.payload["datacontenttype"];
};
Spec03.prototype.dataContentType = function(_contenttype){
this.payload["datacontenttype"] = _contenttype;
return this;
};
Spec03.prototype.getDataContentType = function() {
return this.payload["datacontenttype"];
};
Spec03.prototype.schemaurl = function(_schemaurl){
this.payload["schemaurl"] = _schemaurl;
return this;
};
Spec03.prototype.getSchemaurl = function() {
return this.payload["schemaurl"];
};
Spec03.prototype.subject = function(_subject){
this.payload["subject"] = _subject;
return this;
};
Spec03.prototype.getSubject = function() {
return this.payload["subject"];
};
Spec03.prototype.time = function(_time){
this.payload["time"] = _time.toISOString();
return this;
};
Spec03.prototype.getTime = function() {
return this.payload["time"];
};
Spec03.prototype.data = function(_data){
this.payload["data"] = _data;
return this;
};
Spec03.prototype.getData = function() {
return this.payload["data"];
};
Spec03.prototype.addExtension = function(key, value){
if(!reserved.hasOwnProperty(key)){
this.payload[key] = value;
} else {
throw {message: "Reserved attribute name: '" + key + "'"};
}
return this;
};
module.exports = Spec03;

171
test/spec_0_3_tests.js Normal file
View File

@ -0,0 +1,171 @@
const expect = require("chai").expect;
const Spec03 = require("../lib/specs/spec_0_3.js");
const Cloudevent = require("../index.js");
const uuid = require("uuid/v4");
const id = uuid();
const type = "com.github.pull.create";
const source = "urn:event:from:myapi/resourse/123";
const time = new Date();
const schemaurl = "http://example.com/registry/myschema.json";
const dataContentEncoding = "base64";
const dataContentType = "application/json";
const data = {
much : "wow"
};
const extensions = {};
const subject = "subject-x0";
var cloudevent =
new Cloudevent(Spec03)
.id(id)
.source(source)
.type(type)
.dataContentEncoding(dataContentEncoding)
.dataContentType(dataContentType)
.schemaurl(schemaurl)
.subject(subject)
.time(time)
.data(data);
describe("CloudEvents Spec v0.3", () => {
describe("REQUIRED Attributes", () => {
it("Should have 'id'", () => {
expect(cloudevent.getId()).to.equal(id);
});
it("Should have 'source'", () => {
expect(cloudevent.getSource()).to.equal(source);
});
it("Should have 'specversion'", () => {
expect(cloudevent.getSpecversion()).to.equal("0.3");
});
it("Should have 'type'", () => {
expect(cloudevent.getType()).to.equal(type);
});
});
describe("OPTIONAL Attributes", () => {
it("Should have 'datacontentencoding'", () => {
expect(cloudevent.getDataContentEncoding()).to.equal(dataContentEncoding);
});
it("Should have 'datacontenttype'", () => {
expect(cloudevent.getDataContentType()).to.equal(dataContentType);
});
it("contenttype() method should maps to 'datacontenttype'", () => {
cloudevent.contenttype("text/xml");
expect(cloudevent.getDataContentType()).to.equal("text/xml");
cloudevent.contenttype(dataContentType);
});
it("Should have 'schemaurl'", () => {
expect(cloudevent.getSchemaurl()).to.equal(schemaurl);
});
it("Should have 'subject'", () => {
expect(cloudevent.getSubject()).to.equal(subject);
});
it("Should have 'time'", () => {
expect(cloudevent.getTime()).to.equal(time.toISOString());
});
it("Should have 'data'", () => {
expect(cloudevent.getData()).to.deep.equal(data);
});
it("Should have the 'extension1'", () => {
cloudevent.addExtension("extension1", "value1");
expect(cloudevent.spec.payload["extension1"])
.to.equal("value1");
});
it("should throw an error when use a reserved name as extension", () => {
expect(cloudevent.addExtension.bind(cloudevent, "id"))
.to.throw("Reserved attribute name: 'id'");
});
});
describe("The Constraints check", () => {
describe("'id'", () => {
it("should throw an error when is absent", () => {
delete cloudevent.spec.payload.id;
expect(cloudevent.format.bind(cloudevent))
.to
.throw("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");
cloudevent.spec.payload.id = id;
});
});
describe("'source'", () => {
it("should throw an error when is absent", () => {
delete cloudevent.spec.payload.source;
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
cloudevent.spec.payload.source = source;
});
});
describe("'specversion'", () => {
it("should throw an error when is absent", () => {
delete cloudevent.spec.payload.specversion;
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
cloudevent.spec.payload.specversion = "0.3";
});
it("should throw an erro when is empty", () => {
cloudevent.spec.payload.specversion = "";
expect(cloudevent.format.bind(cloudevent))
.to
.throw("invalid payload");
cloudevent.spec.payload.specversion = "0.3";
});
});
describe("'type'", () => {
it("should throw an error when is absent", () => {
delete cloudevent.spec.payload.type;
expect(cloudevent.format.bind(cloudevent))
.to
.throw("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");
cloudevent.type(type);
});
it("must be a non-empty string", () => {
cloudevent.type(type);
expect(cloudevent.spec.payload.type).to.equal(type);
});
});
describe("'datacontentencoding'", () => {
it("should throw an erro when 'data' is not a string", () => {
});
});
});
});