From 7c2cdd35907eb4e4a0d464c86a291a1ea017ca54 Mon Sep 17 00:00:00 2001 From: Lance Ball Date: Wed, 4 Aug 2021 12:04:36 -0400 Subject: [PATCH] src!: remove support for 0.3 events It has been nearly two years since 1.0 became final. This change removes support for 0.3 events in the interest of simplifying the project a little. Signed-off-by: Lance Ball --- package-lock.json | 6 +- src/event/cloudevent.ts | 21 +-- src/event/interfaces.ts | 136 ------------------ src/event/schemas.ts | 73 ---------- src/event/spec.ts | 34 +---- src/index.ts | 4 +- src/message/http/index.ts | 6 +- test/integration/cloud_event_test.ts | 88 +----------- test/integration/spec_03_tests.ts | 197 --------------------------- 9 files changed, 19 insertions(+), 546 deletions(-) delete mode 100644 test/integration/spec_03_tests.ts diff --git a/package-lock.json b/package-lock.json index c0c0a482..782a7230 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7159,9 +7159,9 @@ "dev": true }, "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, "path-type": { diff --git a/src/event/cloudevent.ts b/src/event/cloudevent.ts index 2a952179..870d8660 100644 --- a/src/event/cloudevent.ts +++ b/src/event/cloudevent.ts @@ -6,14 +6,7 @@ import { v4 as uuidv4 } from "uuid"; import { Emitter } from ".."; -import { - CloudEventV03, - CloudEventV03Attributes, - CloudEventV03OptionalAttributes, - CloudEventV1, - CloudEventV1Attributes, - CloudEventV1OptionalAttributes, -} from "./interfaces"; +import { CloudEventV1, CloudEventV1Attributes, CloudEventV1OptionalAttributes } from "./interfaces"; import { validateCloudEvent } from "./spec"; import { ValidationError, isBinary, asBase64, isValidType } from "./validation"; @@ -30,7 +23,7 @@ export const enum Version { * interoperability across services, platforms and systems. * @see https://github.com/cloudevents/spec/blob/v1.0/spec.md */ -export class CloudEvent implements CloudEventV1, CloudEventV03 { +export class CloudEvent implements CloudEventV1 { id: string; type: string; source: string; @@ -58,7 +51,7 @@ export class CloudEvent implements CloudEventV1, CloudEventV03 { * @param {object} event the event properties * @param {boolean?} strict whether to perform event validation when creating the object - default: true */ - constructor(event: CloudEventV1 | CloudEventV1Attributes | CloudEventV03 | CloudEventV03Attributes, strict = true) { + constructor(event: CloudEventV1 | CloudEventV1Attributes, strict = true) { // copy the incoming event so that we can delete properties as we go // everything left after we have deleted know properties becomes an extension const properties = { ...event }; @@ -197,13 +190,7 @@ See: https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system`); * @return {CloudEvent} returns a new CloudEvent */ public cloneWith( - options: - | CloudEventV1 - | CloudEventV1Attributes - | CloudEventV1OptionalAttributes - | CloudEventV03 - | CloudEventV03Attributes - | CloudEventV03OptionalAttributes, + options: CloudEventV1 | CloudEventV1Attributes | CloudEventV1OptionalAttributes, strict = true, ): CloudEvent { return new CloudEvent(Object.assign({}, this.toJSON(), options) as CloudEvent, strict); diff --git a/src/event/interfaces.ts b/src/event/interfaces.ts index 8fa02010..039d7242 100644 --- a/src/event/interfaces.ts +++ b/src/event/interfaces.ts @@ -140,139 +140,3 @@ export interface CloudEventV1OptionalAttributes { */ [key: string]: unknown; } - -/** - * The object interface for CloudEvents 0.3. - * @see https://github.com/cloudevents/spec/blob/v0.3/spec.md - */ - -export interface CloudEventV03 extends CloudEventV03Attributes { - // REQUIRED Attributes - /** - * [REQUIRED] Identifies the event. Producers MUST ensure that `source` + `id` - * is unique for each distinct event. If a duplicate event is re-sent (e.g. due - * to a network error) it MAY have the same `id`. Consumers MAY assume that - * Events with identical `source` and `id` are duplicates. - * @required Non-empty string. Unique within producer. - * @example An event counter maintained by the producer - * @example A UUID - */ - id: string; - /** - * [REQUIRED] The version of the CloudEvents specification which the event - * uses. This enables the interpretation of the context. Compliant event - * producers MUST use a value of `1.0` when referring to this version of the - * specification. - * @required MUST be a non-empty string. - */ - specversion: string; -} - -export interface CloudEventV03Attributes extends CloudEventV03OptionalAttributes { - /** - * [REQUIRED] Identifies the context in which an event happened. Often this - * will include information such as the type of the event source, the - * organization publishing the event or the process that produced the event. The - * exact syntax and semantics behind the data encoded in the URI is defined by - * the event producer. - * Producers MUST ensure that `source` + `id` is unique for each distinct event. - * An application MAY assign a unique `source` to each distinct producer, which - * makes it easy to produce unique IDs since no other producer will have the same - * source. The application MAY use UUIDs, URNs, DNS authorities or an - * application-specific scheme to create unique `source` identifiers. - * A source MAY include more than one producer. In that case the producers MUST - * collaborate to ensure that `source` + `id` is unique for each distinct event. - * @required Non-empty URI-reference - */ - source: string; - /** - * [REQUIRED] This attribute contains a value describing the type of event - * related to the originating occurrence. Often this attribute is used for - * routing, observability, policy enforcement, etc. The format of this is - * producer defined and might include information such as the version of the - * `type` - see - * [Versioning of Attributes in the Primer](primer.md#versioning-of-attributes) - * for more information. - * @required MUST be a non-empty string - * @should SHOULD be prefixed with a reverse-DNS name. The prefixed domain dictates the - * organization which defines the semantics of this event type. - * @example com.github.pull.create - * @example com.example.object.delete.v2 - */ - type: string; -} - -export interface CloudEventV03OptionalAttributes { - /** - * The following fields are optional. - */ - - /** - * [OPTIONAL] Describes the content encoding for the data attribute for when the - * data field MUST be encoded as a string, like with structured transport binding - * modes using the JSON event format, but the datacontenttype indicates a non-string - * media type. When the data field's effective data type is not String, this attribute - * MUST NOT be set and MUST be ignored when set. - */ - datacontentencoding?: string; - - /** - * [OPTIONAL] Content type of `data` value. This attribute enables `data` to - * carry any type of content, whereby format and encoding might differ from that - * of the chosen event format. For example, an event rendered using the - * [JSON envelope](./json-format.md#3-envelope) format might carry an XML payload - * in `data`, and the consumer is informed by this attribute being set to - * "application/xml". The rules for how `data` content is rendered for different - * `datacontenttype` values are defined in the event format specifications; for - * example, the JSON event format defines the relationship in - * [section 3.1](./json-format.md#31-handling-of-data). - */ - datacontenttype?: string; - /** - * [OPTIONAL] A link to the schema that the data attribute adheres to. - * Incompatible changes to the schema SHOULD be reflected by a different URL. - * If present, MUST be a non-empty URI. - */ - schemaurl?: string; - /** - * [OPTIONAL] This describes the subject of the event in the context of the - * event producer (identified by `source`). In publish-subscribe scenarios, a - * subscriber will typically subscribe to events emitted by a `source`, but the - * `source` identifier alone might not be sufficient as a qualifier for any - * specific event if the `source` context has internal sub-structure. - * - * Identifying the subject of the event in context metadata (opposed to only in - * the `data` payload) is particularly helpful in generic subscription filtering - * scenarios where middleware is unable to interpret the `data` content. In the - * above example, the subscriber might only be interested in blobs with names - * ending with '.jpg' or '.jpeg' and the `subject` attribute allows for - * constructing a simple and efficient string-suffix filter for that subset of - * events. - * - * If present, MUST be a non-empty string. - * @example "https://example.com/storage/tenant/container" - * @example "mynewfile.jpg" - */ - subject?: string; - /** - * [OPTIONAL] Timestamp of when the occurrence happened. If the time of the - * occurrence cannot be determined then this attribute MAY be set to some other - * time (such as the current time) by the CloudEvents producer, however all - * producers for the same `source` MUST be consistent in this respect. In other - * words, either they all use the actual time of the occurrence or they all use - * the same algorithm to determine the value used. - * @example "2020-08-08T14:48:09.769Z" - */ - time?: string; - /** - * [OPTIONAL] The event payload. This specification does not place any restriction - * on the type of this information. It is encoded into a media format which is - * specified by the datacontenttype attribute (e.g. application/json), and adheres - * to the dataschema format when those respective attributes are present. - */ - data?: Record | string | number | boolean | null | unknown; - /** - * [OPTIONAL] CloudEvents extension attributes. - */ - [key: string]: unknown; -} diff --git a/src/event/schemas.ts b/src/event/schemas.ts index 4b7bd1d4..27cfd118 100644 --- a/src/event/schemas.ts +++ b/src/event/schemas.ts @@ -83,76 +83,3 @@ export const schemaV1 = { }, type: "object", }; - -export const schemaV03 = { - $ref: "#/definitions/event", - definitions: { - specversion: { - const: "0.3", - }, - datacontenttype: { - type: "string", - }, - data: { - type: ["object", "string", "array", "number", "boolean", "null"], - }, - 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", - }, - source: { - $ref: "#/definitions/source", - }, - }, - required: ["specversion", "id", "type", "source"], - type: "object", - }, - id: { - type: "string", - minLength: 1, - }, - time: { - format: "js-date-time", - type: "string", - }, - schemaurl: { - type: "string", - format: "uri-reference", - }, - subject: { - type: "string", - minLength: 1, - }, - type: { - type: "string", - minLength: 1, - }, - source: { - format: "uri-reference", - type: "string", - }, - }, - type: "object", -}; diff --git a/src/event/spec.ts b/src/event/spec.ts index 1d308bb3..cf1ed447 100644 --- a/src/event/spec.ts +++ b/src/event/spec.ts @@ -3,15 +3,14 @@ SPDX-License-Identifier: Apache-2.0 */ -import Ajv from "ajv"; -import { ValidationError, isBase64 } from "./validation"; +import Ajv, { Options } from "ajv"; +import { ValidationError } from "./validation"; -import { CloudEventV1, CloudEventV03 } from "./interfaces"; -import { schemaV03, schemaV1 } from "./schemas"; +import { CloudEventV1 } from "./interfaces"; +import { schemaV1 } from "./schemas"; import { Version } from "./cloudevent"; -import CONSTANTS from "../constants"; -const ajv = new Ajv({ extendRefs: true }); +const ajv = new Ajv({ extendRefs: true } as Options); // handle date-time format specially because a user could pass // Date().toString(), which is not spec compliant date-time format @@ -21,18 +20,12 @@ ajv.addFormat("js-date-time", function (dateTimeString) { }); const isValidAgainstSchemaV1 = ajv.compile(schemaV1); -const isValidAgainstSchemaV03 = ajv.compile(schemaV03); -export function validateCloudEvent(event: CloudEventV03 | CloudEventV1): boolean { +export function validateCloudEvent(event: CloudEventV1): boolean { if (event.specversion === Version.V1) { if (!isValidAgainstSchemaV1(event)) { throw new ValidationError("invalid payload", isValidAgainstSchemaV1.errors); } - } else if (event.specversion === Version.V03) { - if (!isValidAgainstSchemaV03(event)) { - throw new ValidationError("invalid payload", isValidAgainstSchemaV03.errors); - } - checkDataContentEncoding(event); } else { return false; } @@ -44,18 +37,3 @@ export function validateCloudEvent(event: CloudEventV03 | CloudEventV1): boolean } return true; } - -function checkDataContentEncoding(event: CloudEventV03): boolean { - if (event.datacontentencoding) { - // we only support base64 - const encoding = event.datacontentencoding.toLocaleLowerCase(); - if (encoding !== CONSTANTS.ENCODING_BASE64) { - throw new ValidationError("invalid payload", [`Unsupported content encoding: ${encoding}`]); - } else { - if (!isBase64(event.data)) { - throw new ValidationError("invalid payload", [`Invalid content encoding of data: ${event.data}`]); - } - } - } - return true; -} diff --git a/src/index.ts b/src/index.ts index 5257f6dc..6648255d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,7 +5,7 @@ import { CloudEvent, Version } from "./event/cloudevent"; import { ValidationError } from "./event/validation"; -import { CloudEventV03, CloudEventV03Attributes, CloudEventV1, CloudEventV1Attributes } from "./event/interfaces"; +import { CloudEventV1, CloudEventV1Attributes } from "./event/interfaces"; import { Options, TransportFunction, EmitterFunction, emitterFor, Emitter } from "./transport/emitter"; import { Headers, Mode, Binding, HTTP, Message, Serializer, Deserializer } from "./message"; @@ -15,8 +15,6 @@ import CONSTANTS from "./constants"; export { // From event CloudEvent, - CloudEventV03, - CloudEventV03Attributes, CloudEventV1, CloudEventV1Attributes, Version, diff --git a/src/message/http/index.ts b/src/message/http/index.ts index 3712fa44..05e80376 100644 --- a/src/message/http/index.ts +++ b/src/message/http/index.ts @@ -3,7 +3,7 @@ SPDX-License-Identifier: Apache-2.0 */ -import { CloudEvent, CloudEventV03, CloudEventV1, CONSTANTS, Mode, Version } from "../.."; +import { CloudEvent, CloudEventV1, CONSTANTS, Mode, Version } from "../.."; import { Message, Headers } from ".."; import { @@ -187,7 +187,7 @@ function parseBinary(message: Message, version: Version): CloudEvent { delete eventObj.datacontentencoding; } - return new CloudEvent({ ...eventObj, data: body } as CloudEventV1 | CloudEventV03, false); + return new CloudEvent({ ...eventObj, data: body } as CloudEventV1, false); } /** @@ -240,5 +240,5 @@ function parseStructured(message: Message, version: Version): CloudEvent { delete eventObj.data_base64; delete eventObj.datacontentencoding; } - return new CloudEvent(eventObj as CloudEventV1 | CloudEventV03, false); + return new CloudEvent(eventObj as CloudEventV1, false); } diff --git a/test/integration/cloud_event_test.ts b/test/integration/cloud_event_test.ts index efede825..1c7ee422 100644 --- a/test/integration/cloud_event_test.ts +++ b/test/integration/cloud_event_test.ts @@ -8,7 +8,7 @@ import fs from "fs"; import { expect } from "chai"; import { CloudEvent, ValidationError, Version } from "../../src"; -import { CloudEventV03, CloudEventV1 } from "../../src/event/interfaces"; +import { CloudEventV1 } from "../../src/event/interfaces"; import { asBase64 } from "../../src/event/validation"; const type = "org.cncf.cloudevents.example"; @@ -204,93 +204,9 @@ describe("A 1.0 CloudEvent", () => { it("correctly formats a CloudEvent as JSON", () => { const ce = new CloudEvent({ ...fixture }); const json = ce.toString(); - const obj = JSON.parse((json as unknown) as string); + const obj = JSON.parse(json as string); expect(obj.type).to.equal(type); expect(obj.source).to.equal(source); expect(obj.specversion).to.equal(Version.V1); }); }); - -describe("A 0.3 CloudEvent", () => { - const v03fixture: CloudEventV03 = { ...fixture }; - v03fixture.specversion = Version.V03; - - it("has retreivable source and type attributes", () => { - const ce = new CloudEvent(v03fixture); - expect(ce.source).to.equal("http://unit.test"); - expect(ce.type).to.equal("org.cncf.cloudevents.example"); - }); - - it("generates an ID if one is not provided in the constructor", () => { - const ce = new CloudEvent({ source, type, specversion: Version.V03 }); - expect(ce.id).to.not.be.empty; - expect(ce.specversion).to.equal(Version.V03); - }); - - it("generates a timestamp by default", () => { - const ce = new CloudEvent(v03fixture); - expect(ce.time).to.not.be.empty; - }); - - it("can be constructed with a timestamp", () => { - const time = new Date().toISOString(); - const ce = new CloudEvent({ time, ...v03fixture }); - expect(ce.time).to.equal(time); - }); - - it("can be constructed with a datacontenttype", () => { - const ce = new CloudEvent({ datacontenttype: "application/json", ...v03fixture }); - expect(ce.datacontenttype).to.equal("application/json"); - }); - - it("can be constructed with a datacontentencoding", () => { - const ce = new CloudEvent({ datacontentencoding: "Base64", ...v03fixture, data: "SSB3YXMgZnVubnkg8J+Ygg==" }); - expect(ce.datacontentencoding).to.equal("Base64"); - }); - - it("can be constructed with a schemaurl", () => { - const ce = new CloudEvent({ schemaurl: "http://my.schema", ...v03fixture }); - expect(ce.schemaurl).to.equal("http://my.schema"); - }); - - it("can be constructed with a subject", () => { - const ce = new CloudEvent({ subject: "science", ...v03fixture }); - expect(ce.subject).to.equal("science"); - }); - - // Handle 1.0 attribute - should this really throw? - it("throws a TypeError when constructed with a dataschema", () => { - expect(() => { - new CloudEvent({ dataschema: "http://throw.com", ...v03fixture }); - }).to.throw(TypeError, "cannot set dataschema on version 0.3 event"); - }); - - it("can be constructed with data", () => { - const ce = new CloudEvent({ - ...v03fixture, - data: { lunch: "tacos" }, - }); - expect(ce.data).to.deep.equal({ lunch: "tacos" }); - }); - - it("throws TypeError if the CloudEvent does not conform to the schema", () => { - try { - new CloudEvent({ - ...v03fixture, - source: (null as unknown) as string, - }); - } catch (err) { - expect(err).to.be.instanceOf(ValidationError); - expect(err.message).to.include("invalid payload"); - } - }); - - it("correctly formats a CloudEvent as JSON", () => { - const ce = new CloudEvent({ ...v03fixture }); - const json = ce.toString(); - const obj = JSON.parse((json as unknown) as string); - expect(obj.type).to.equal(type); - expect(obj.source).to.equal(source); - expect(obj.specversion).to.equal(Version.V03); - }); -}); diff --git a/test/integration/spec_03_tests.ts b/test/integration/spec_03_tests.ts deleted file mode 100644 index c4f25c3e..00000000 --- a/test/integration/spec_03_tests.ts +++ /dev/null @@ -1,197 +0,0 @@ -/* - Copyright 2021 The CloudEvents Authors - SPDX-License-Identifier: Apache-2.0 -*/ - -import "mocha"; -import { expect } from "chai"; -import { CloudEvent, Version, ValidationError, Mode } from "../../src"; -import Constants from "../../src/constants"; - -const id = "97699ec2-a8d9-47c1-bfa0-ff7aa526f838"; -const type = "com.github.pull.create"; -const source = "urn:event:from:myapi/resourse/123"; -const time = new Date().toISOString(); -const schemaurl = "http://example.com/registry/myschema.json"; -const data = { - much: "wow", -}; -const subject = "subject-x0"; - -let cloudevent = new CloudEvent({ - specversion: Version.V03, - id, - source, - type, - subject, - time, - data, - schemaurl, - datacontenttype: Constants.MIME_JSON, -}); - -describe("CloudEvents Spec v0.3", () => { - describe("REQUIRED Attributes", () => { - it("Should have 'id'", () => { - expect(cloudevent.id).to.equal(id); - }); - - it("Should have 'source'", () => { - expect(cloudevent.source).to.equal(source); - }); - - it("Should have 'specversion'", () => { - expect(cloudevent.specversion).to.equal(Version.V03); - }); - - it("Should have 'type'", () => { - expect(cloudevent.type).to.equal(type); - }); - }); - - describe("OPTIONAL Attributes", () => { - it("Should have 'datacontentencoding'", () => { - cloudevent = cloudevent.cloneWith({ - datacontentencoding: Constants.ENCODING_BASE64, - data: "SSB3YXMgZnVubnkg8J+Ygg==", - }); - expect(cloudevent.datacontentencoding).to.equal(Constants.ENCODING_BASE64); - - cloudevent = cloudevent.cloneWith({ datacontentencoding: undefined, data: data }); - }); - - it("Should have 'datacontenttype'", () => { - expect(cloudevent.datacontenttype).to.equal(Constants.MIME_JSON); - }); - - it("Should have 'schemaurl'", () => { - expect(cloudevent.schemaurl).to.equal(schemaurl); - }); - - it("Should have 'subject'", () => { - expect(cloudevent.subject).to.equal(subject); - }); - - it("Should have 'time'", () => { - expect(cloudevent.time).to.equal(time); - }); - - it("Should have 'data'", () => { - expect(cloudevent.data).to.deep.equal(data); - }); - - it("Should have the 'extension1'", () => { - cloudevent = cloudevent.cloneWith({ extension1: "value1" }); - expect(cloudevent.extension1).to.equal("value1"); - }); - }); - - describe("The Constraints check", () => { - describe("'id'", () => { - it("should throw an error when trying to remove", () => { - expect(() => { - delete (cloudevent as any).id; - }).to.throw(TypeError); - }); - - it("defaut ID create when an empty string", () => { - cloudevent = cloudevent.cloneWith({ id: "" }); - expect(cloudevent.id.length).to.be.greaterThan(0); - }); - }); - - describe("'source'", () => { - it("should throw an error when trying to remove", () => { - expect(() => { - delete (cloudevent as any).source; - }).to.throw(TypeError); - }); - }); - - describe("'specversion'", () => { - it("should throw an error when trying to remove", () => { - expect(() => { - delete (cloudevent as any).specversion; - }).to.throw(TypeError); - }); - }); - - describe("'type'", () => { - it("should throw an error when trying to remove", () => { - expect(() => { - delete (cloudevent as any).type; - }).to.throw(TypeError); - }); - - it("should throw an error when is an empty string", () => { - expect(() => { - cloudevent.cloneWith({ type: "" }); - }).to.throw(ValidationError, "invalid payload"); - }); - - it("must be a non-empty string", () => { - cloudevent.cloneWith({ type: type }); - expect(cloudevent.type).to.equal(type); - }); - }); - - describe("'datacontentencoding'", () => { - it("should throw an error when is a unsupported encoding", () => { - expect(() => { - cloudevent.cloneWith({ data: "Y2xvdWRldmVudHMK", datacontentencoding: Mode.BINARY }); - }).to.throw(ValidationError, "invalid payload"); - - cloudevent.cloneWith({ data: data, datacontentencoding: undefined }); - }); - - it("should throw an error when 'data' does not carry base64", () => { - expect(() => { - cloudevent.cloneWith({ - data: "no base 64 value", - datacontentencoding: Constants.ENCODING_BASE64, - datacontenttype: "text/plain", - }); - }).to.throw(ValidationError, "invalid payload"); - - cloudevent.cloneWith({ - data: data, - datacontentencoding: undefined, - }); - }); - - it("should accept when 'data' is a string", () => { - cloudevent.cloneWith({ data: "Y2xvdWRldmVudHMK", datacontentencoding: Constants.ENCODING_BASE64 }); - expect(cloudevent.validate()).to.be.true; - cloudevent.cloneWith({ data: data, datacontentencoding: undefined }); - }); - }); - - describe("'data'", () => { - it("should maintain the type of data when no data content type", () => { - cloudevent = cloudevent.cloneWith({ datacontenttype: undefined }); - cloudevent.data = JSON.stringify(data); - - expect(typeof cloudevent.data).to.equal("string"); - }); - }); - - describe("'subject'", () => { - it("should throw an error when is an empty string", () => { - expect(() => { - cloudevent.cloneWith({ subject: "" }); - }).to.throw(ValidationError); - }); - }); - - describe("'time'", () => { - it("must adhere to the format specified in RFC 3339", () => { - const d = new Date(); - cloudevent = cloudevent.cloneWith({ time: d.toString() }); - // ensure that we always get back the same thing we passed in - expect(cloudevent.time).to.equal(d.toString()); - // ensure that when stringified, the timestamp is in RFC3339 format - expect(JSON.parse(JSON.stringify(cloudevent)).time).to.equal(new Date(d.toString()).toISOString()); - }); - }); - }); -});