From d80bc12048c1abdc74b621eb50f7263e606622e9 Mon Sep 17 00:00:00 2001 From: Liran Cohen Date: Wed, 19 Jun 2024 15:05:47 -0400 Subject: [PATCH] remove unecessary Event Filters --- .../interface-methods/events-filter.json | 80 +- src/interfaces/events-query.ts | 3 - src/interfaces/events-subscribe.ts | 3 - src/types/events-types.ts | 27 +- src/utils/events.ts | 78 +- tests/handlers/events-query.spec.ts | 8 +- tests/interfaces/events-query.spec.ts | 28 +- tests/scenarios/events-query.spec.ts | 779 +----------------- tests/scenarios/subscriptions.spec.ts | 627 -------------- tests/utils/events.spec.ts | 79 +- 10 files changed, 64 insertions(+), 1648 deletions(-) diff --git a/json-schemas/interface-methods/events-filter.json b/json-schemas/interface-methods/events-filter.json index 4351009cc..79baeb889 100644 --- a/json-schemas/interface-methods/events-filter.json +++ b/json-schemas/interface-methods/events-filter.json @@ -7,7 +7,6 @@ "properties": { "interface": { "enum": [ - "Permissions", "Protocols", "Records" ], @@ -17,8 +16,6 @@ "enum": [ "Configure", "Delete", - "Grant", - "Revoke", "Write" ], "type": "string" @@ -26,31 +23,7 @@ "protocol": { "type": "string" }, - "protocolPath": { - "type": "string" - }, - "recipient": { - "$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/$defs/did" - }, - "contextId": { - "type": "string" - }, - "schema": { - "type": "string" - }, - "recordId": { - "type": "string" - }, - "parentId": { - "type": "string" - }, - "dataFormat": { - "type": "string" - }, - "dataSize": { - "$ref": "https://identity.foundation/dwn/json-schemas/number-range-filter.json" - }, - "dateCreated": { + "messageTimestamp": { "type": "object", "minProperties": 1, "additionalProperties": false, @@ -62,57 +35,6 @@ "$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/$defs/date-time" } } - }, - "datePublished": { - "type": "object", - "minProperties": 1, - "additionalProperties": false, - "properties": { - "from": { - "$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/$defs/date-time" - }, - "to": { - "$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/$defs/date-time" - } - } - }, - "dateUpdated": { - "type": "object", - "minProperties": 1, - "additionalProperties": false, - "properties": { - "from": { - "$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/$defs/date-time" - }, - "to": { - "$ref": "https://identity.foundation/dwn/json-schemas/defs.json#/$defs/date-time" - } - } - } - }, - "dependencies": { - "datePublished": { - "oneOf": [ - { - "properties": { - "published": { - "enum": [ - true - ] - } - }, - "required": [ - "published" - ] - }, - { - "not": { - "required": [ - "published" - ] - } - } - ] } } } \ No newline at end of file diff --git a/src/interfaces/events-query.ts b/src/interfaces/events-query.ts index 9f7fc39f1..09504d27c 100644 --- a/src/interfaces/events-query.ts +++ b/src/interfaces/events-query.ts @@ -27,9 +27,6 @@ export class EventsQuery extends AbstractMessage{ if ('protocol' in filter && filter.protocol !== undefined) { validateProtocolUrlNormalized(filter.protocol); } - if ('schema' in filter && filter.schema !== undefined) { - validateSchemaUrlNormalized(filter.schema); - } } return new EventsQuery(message); diff --git a/src/interfaces/events-subscribe.ts b/src/interfaces/events-subscribe.ts index fe82ace71..ba7de2843 100644 --- a/src/interfaces/events-subscribe.ts +++ b/src/interfaces/events-subscribe.ts @@ -24,9 +24,6 @@ export class EventsSubscribe extends AbstractMessage { if ('protocol' in filter && filter.protocol !== undefined) { validateProtocolUrlNormalized(filter.protocol); } - if ('schema' in filter && filter.schema !== undefined) { - validateSchemaUrlNormalized(filter.schema); - } } Time.validateTimestamp(message.descriptor.messageTimestamp); diff --git a/src/types/events-types.ts b/src/types/events-types.ts index 59dd98a25..14bd3019c 100644 --- a/src/types/events-types.ts +++ b/src/types/events-types.ts @@ -5,36 +5,13 @@ import type { PaginationCursor, RangeCriterion, RangeFilter } from './query-type /** * filters used when filtering for any type of Message across interfaces */ -export type EventsMessageFilter = { +export type EventsFilter = { interface?: string; method?: string; - dateUpdated?: RangeCriterion; -}; - -/** - * We only allow filtering for events by immutable properties, the omitted properties could be different per subsequent writes. - */ -export type EventsRecordsFilter = { - recipient?: string; protocol?: string; - protocolPath?: string; - contextId?: string; - schema?: string; - recordId?: string; - parentId?: string; - dataFormat?: string; - dataSize?: RangeFilter; - dateCreated?: RangeCriterion; - dateUpdated?: RangeCriterion; + messageTimestamp?: RangeCriterion; }; - -/** - * A union type of the different types of filters a user can use when issuing an EventsQuery or EventsSubscribe - * TODO: simplify the EventsFilters to only the necessary in order to reduce complexity https://github.com/TBD54566975/dwn-sdk-js/issues/663 - */ -export type EventsFilter = EventsMessageFilter | EventsRecordsFilter; - export type EventsGetDescriptor = { interface: DwnInterfaceName.Events; method: DwnMethodName.Get; diff --git a/src/utils/events.ts b/src/utils/events.ts index 9fab1eba2..3a420b37d 100644 --- a/src/utils/events.ts +++ b/src/utils/events.ts @@ -1,10 +1,11 @@ +import type { EventsFilter } from '../types/events-types.js'; import type { Filter } from '../types/query-types.js'; -import type { EventsFilter, EventsMessageFilter, EventsRecordsFilter } from '../types/events-types.js'; import { FilterUtility } from '../utils/filter.js'; import { PermissionsProtocol } from '../protocols/permissions.js'; import { Records } from '../utils/records.js'; import { isEmptyObject, removeUndefinedProperties } from './object.js'; +import { normalizeProtocolUrl } from './url.js'; /** @@ -20,13 +21,13 @@ export class Events { // normalize each filter individually by the type of filter it is. for (const filter of filters) { - let eventsFilter: EventsFilter; - if (this.isRecordsFilter(filter)) { - eventsFilter = Records.normalizeFilter(filter); - } else { - // no normalization needed - eventsFilter = filter; - } + // normalize the protocol URL if it exists + const protocol = filter.protocol !== undefined ? normalizeProtocolUrl(filter.protocol) : undefined; + + const eventsFilter = { + ...filter, + protocol, + }; // remove any empty filter properties and do not add if empty removeUndefinedProperties(eventsFilter); @@ -35,7 +36,6 @@ export class Events { } } - return eventsQueryFilters; } @@ -54,46 +54,35 @@ export class Events { // first we check for `EventsRecordsFilter` fields for conversion // otherwise it is `EventsMessageFilter` fields for conversion for (const filter of filters) { - if (this.isRecordsFilter(filter)) { - - // extract the protocol tag filter from the incoming event record filter - // this filters for permission grants, requests and revocations associated with a targeted protocol - // since permissions are their own protocol, we add an additional tag index when writing the permission messages, so we can filter on it here - const protocolTagFilter = this.extractProtocolTagFilters(filter); - if (protocolTagFilter) { - eventsQueryFilters.push(protocolTagFilter); - } - - eventsQueryFilters.push(Records.convertFilter(filter)); - } else { - eventsQueryFilters.push(this.convertFilter(filter)); + // extract the protocol tag filter from the incoming event record filter + // this filters for permission grants, requests and revocations associated with a targeted protocol + // since permissions are their own protocol, we add an additional tag index when writing the permission messages, so we can filter on it here + const protocolTagFilter = this.extractProtocolTagFilters(filter); + if (protocolTagFilter) { + eventsQueryFilters.push(protocolTagFilter); } + + eventsQueryFilters.push(this.convertFilter(filter)); } return eventsQueryFilters; } - private static extractProtocolTagFilters(filter: EventsRecordsFilter): Filter | undefined { - if (filter.protocol !== undefined) { + private static extractProtocolTagFilters(filter: EventsFilter): Filter | undefined { + const { protocol, messageTimestamp } = filter; + if (protocol !== undefined) { const taggedFilter = { protocol: PermissionsProtocol.uri, - ...Records.convertTagsFilter({ protocol: filter.protocol }) + ...Records.convertTagsFilter({ protocol }) } as Filter; - if (filter.dateUpdated != undefined) { - const messageTimestampFilter = filter.dateUpdated ? FilterUtility.convertRangeCriterion(filter.dateUpdated) : undefined; + if (messageTimestamp != undefined) { + const messageTimestampFilter = FilterUtility.convertRangeCriterion(messageTimestamp); if (messageTimestampFilter) { taggedFilter.messageTimestamp = messageTimestampFilter; } } - if (filter.dateCreated !== undefined) { - const dateCreatedFilter = filter.dateCreated ? FilterUtility.convertRangeCriterion(filter.dateCreated) : undefined; - if (dateCreatedFilter) { - taggedFilter.dateCreated = dateCreatedFilter; - } - } - return taggedFilter; } } @@ -101,30 +90,15 @@ export class Events { /** * Converts an external-facing filter model into an internal-facing filer model used by data store. */ - private static convertFilter(filter: EventsMessageFilter): Filter { + private static convertFilter(filter: EventsFilter): Filter { const filterCopy = { ...filter } as Filter; - const { dateUpdated } = filter; - const messageTimestampFilter = dateUpdated ? FilterUtility.convertRangeCriterion(dateUpdated) : undefined; + const { messageTimestamp } = filter; + const messageTimestampFilter = messageTimestamp ? FilterUtility.convertRangeCriterion(messageTimestamp) : undefined; if (messageTimestampFilter) { filterCopy.messageTimestamp = messageTimestampFilter; delete filterCopy.dateUpdated; } return filterCopy as Filter; } - - // we deliberately do not check for `dateUpdated` in this filter. - // if it were the only property that matched, it could be handled by `EventsFilter` - private static isRecordsFilter(filter: EventsFilter): filter is EventsRecordsFilter { - return 'author' in filter || - 'dateCreated' in filter || - 'dataFormat' in filter || - 'dataSize' in filter || - 'parentId' in filter || - 'recordId' in filter || - 'schema' in filter || - 'protocol' in filter || - 'protocolPath' in filter || - 'recipient' in filter; - } } \ No newline at end of file diff --git a/tests/handlers/events-query.spec.ts b/tests/handlers/events-query.spec.ts index e1eb91bde..3fd868d7a 100644 --- a/tests/handlers/events-query.spec.ts +++ b/tests/handlers/events-query.spec.ts @@ -59,7 +59,7 @@ export function testEventsQueryHandler(): void { const { message } = await TestDataGenerator.generateEventsQuery({ author : alice, - filters : [{ schema: 'schema1' }] + filters : [{ protocol: 'http://example.org/protocol/v1' }] }); const eventsQueryHandler = new EventsQueryHandler(didResolver, eventLog); const reply = await eventsQueryHandler.handle({ tenant: bob.did, message }); @@ -73,7 +73,7 @@ export function testEventsQueryHandler(): void { const { message } = await TestDataGenerator.generateEventsQuery({ author : alice, - filters : [{ schema: 'schema1' }] + filters : [{ protocol: 'http://example.org/protocol/v1' }] }); (message['descriptor'] as any)['troll'] = 'hehe'; @@ -89,7 +89,7 @@ export function testEventsQueryHandler(): void { const { message } = await TestDataGenerator.generateEventsQuery({ author : alice, - filters : [{ schema: 'schema1' }], + filters : [{ protocol: 'http://example.org/protocol/v1' }], }); // create with filter to prevent failure on .create() message.descriptor.filters = []; // remove filters const eventsQueryHandler = new EventsQueryHandler(didResolver, eventLog); @@ -104,7 +104,7 @@ export function testEventsQueryHandler(): void { const { message } = await TestDataGenerator.generateEventsQuery({ author : alice, - filters : [{ schema: 'schema1' }], + filters : [{ protocol: 'http://example.org/protocol/v1' }], }); // create with filter to prevent failure on .create() message.descriptor.filters = [{}]; // empty out filter properties const eventsQueryHandler = new EventsQueryHandler(didResolver, eventLog); diff --git a/tests/interfaces/events-query.spec.ts b/tests/interfaces/events-query.spec.ts index c9bd9c94e..ab5ba308b 100644 --- a/tests/interfaces/events-query.spec.ts +++ b/tests/interfaces/events-query.spec.ts @@ -20,7 +20,7 @@ describe('EventsQuery Message', () => { const currentTime = Time.getCurrentTimestamp(); const eventsQuery = await EventsQuery.create({ - filters : [{ schema: 'anything' }], + filters : [{ protocol: 'http://example.org/protocol/v1' }], messageTimestamp : currentTime, signer : Jws.createSigner(alice), }); @@ -43,22 +43,6 @@ describe('EventsQuery Message', () => { expect((message.descriptor.filters[0] as ProtocolsQueryFilter).protocol).to.eq('http://example.com'); }); - it('should auto-normalize schema URL', async () => { - const alice = await TestDataGenerator.generatePersona(); - - const options = { - recipient : alice.did, - signer : Jws.createSigner(alice), - filters : [{ schema: 'example.com/' }], - }; - const eventsQuery = await EventsQuery.create(options); - - const message = eventsQuery.message as EventsQueryMessage; - - expect(message.descriptor.filters.length).to.equal(1); - expect((message.descriptor.filters[0] as RecordsFilter).schema).to.eq('http://example.com'); - }); - it('throws an exception if message has no filters', async () => { const alice = await TestDataGenerator.generatePersona(); const currentTime = Time.getCurrentTimestamp(); @@ -84,7 +68,7 @@ describe('EventsQuery Message', () => { // empty filter gets removed, valid filter remains const eventsQuery = await EventsQuery.create({ - filters : [{ schema: 'schema' },{ }], // one empty filter + filters : [{ protocol: 'http://example.org/protocol/v1' },{ }], // one empty filter messageTimestamp : currentTime, signer : Jws.createSigner(alice), }); @@ -99,7 +83,7 @@ describe('EventsQuery Message', () => { const currentTime = Time.getCurrentTimestamp(); const eventsQuery = await EventsQuery.create({ - filters : [{ schema: 'anything' }], + filters : [{ protocol: 'http://example.org/protocol/v1' }], messageTimestamp : currentTime, signer : Jws.createSigner(alice), }); @@ -117,7 +101,7 @@ describe('EventsQuery Message', () => { const alice = await TestDataGenerator.generatePersona(); const currentTime = Time.getCurrentTimestamp(); const eventsQuery = await EventsQuery.create({ - filters : [{ schema: 'anything' }], + filters : [{ protocol: 'http://example.org/protocol/v1' }], messageTimestamp : currentTime, signer : Jws.createSigner(alice), }); @@ -132,7 +116,7 @@ describe('EventsQuery Message', () => { const alice = await TestDataGenerator.generatePersona(); const currentTime = Time.getCurrentTimestamp(); const eventsQuery = await EventsQuery.create({ - filters : [{ schema: 'anything' }], + filters : [{ protocol: 'http://example.org/protocol/v1' }], messageTimestamp : currentTime, signer : Jws.createSigner(alice), }); @@ -148,7 +132,7 @@ describe('EventsQuery Message', () => { const alice = await TestDataGenerator.generatePersona(); const currentTime = Time.getCurrentTimestamp(); const eventsQuery = await EventsQuery.create({ - filters : [{ schema: 'anything' }], + filters : [{ protocol: 'http://example.org/protocol/v1' }], messageTimestamp : currentTime, signer : Jws.createSigner(alice), }); diff --git a/tests/scenarios/events-query.spec.ts b/tests/scenarios/events-query.spec.ts index 9c47e1fc7..b4631cff8 100644 --- a/tests/scenarios/events-query.spec.ts +++ b/tests/scenarios/events-query.spec.ts @@ -8,14 +8,13 @@ import type { } from '../../src/index.js'; import freeForAll from '../vectors/protocol-definitions/free-for-all.json' assert { type: 'json' }; -import threadProtocol from '../vectors/protocol-definitions/thread-role.json' assert { type: 'json' }; import { expect } from 'chai'; import { TestDataGenerator } from '../utils/test-data-generator.js'; import { TestEventStream } from '../test-event-stream.js'; import { TestStores } from '../test-stores.js'; import { DidKey, UniversalResolver } from '@web5/dids'; -import { Dwn, DwnConstant, DwnInterfaceName, DwnMethodName, Message, Time } from '../../src/index.js'; +import { Dwn, DwnInterfaceName, DwnMethodName, Message, Time } from '../../src/index.js'; export function testEventsQueryScenarios(): void { describe('events query tests', () => { @@ -68,8 +67,8 @@ export function testEventsQueryScenarios(): void { const eventsQueryRecords = await TestDataGenerator.generateEventsQuery({ author : alice, filters : [ - { recordId: record.message.recordId }, // RecordsWrite - { protocol: protocol.message.descriptor.definition.protocol } // ProtocolConfigure + { interface: DwnInterfaceName.Records }, // returns the RecordsWrite + { protocol: protocol.message.descriptor.definition.protocol } // returns the ProtocolConfigure ], }); const recordEventsReply = await dwn.processMessage(alice.did, eventsQueryRecords.message); @@ -200,19 +199,19 @@ export function testEventsQueryScenarios(): void { expect(recordsWriteEventsReplyAfterCursor.entries![0]).to.equal(await Message.getCid(record2Update.message)); }); - it('filters by a dateUpdated (messageTimestamp) range across different message types', async () => { + it('filters by a messageTimestamp range across different message types', async () => { // scenario: // alice creates (2) messages, (RecordsWrite and ProtocolsConfigure) - // each message on the first date of the year (2021, 2022 and 2023 respectively. + // each message on the first date of the year (2021, 2022 respectively. // alice queries for all records beyond the last day of 2021 and should return 1 of the 2 messages (ProtocolConfigure) // alice then creates a RecordsDelete message for the original RecordsWrite // alice queries once again however supplying a cursor of the last message from the prior query, returning the RecordsDelete message. const firstDayOf2021 = Time.createTimestamp({ year: 2021, month: 1, day: 1 }); - const firstDayOf2023 = Time.createTimestamp({ year: 2023, month: 1, day: 1 }); + const firstDayOf2022 = Time.createTimestamp({ year: 2022, month: 1, day: 1 }); const alice = await TestDataGenerator.generateDidKeyPersona(); const write = await TestDataGenerator.generateRecordsWrite({ author: alice, dateCreated: firstDayOf2021, messageTimestamp: firstDayOf2021 }); - const protocol = await TestDataGenerator.generateProtocolsConfigure({ author: alice, messageTimestamp: firstDayOf2023 }); + const protocol = await TestDataGenerator.generateProtocolsConfigure({ author: alice, messageTimestamp: firstDayOf2022 }); // insert data const writeReply = await dwn.processMessage(alice.did, write.message, { dataStream: write.dataStream }); @@ -224,7 +223,7 @@ export function testEventsQueryScenarios(): void { const lastDayOf2021 = Time.createTimestamp({ year: 2021, month: 12, day: 31 }); let eventsQuery1 = await TestDataGenerator.generateEventsQuery({ author : alice, - filters : [{ dateUpdated: { from: lastDayOf2021 } }], + filters : [{ messageTimestamp: { from: lastDayOf2021 } }], }); let reply1 = await dwn.processMessage(alice.did, eventsQuery1.message); expect(reply1.status.code).to.equal(200); @@ -238,7 +237,7 @@ export function testEventsQueryScenarios(): void { eventsQuery1 = await TestDataGenerator.generateEventsQuery({ author : alice, - filters : [{ dateUpdated: { from: lastDayOf2021 } }], + filters : [{ messageTimestamp: { from: lastDayOf2021 } }], cursor : reply1.cursor }); reply1 = await dwn.processMessage(alice.did, eventsQuery1.message); @@ -247,125 +246,6 @@ export function testEventsQueryScenarios(): void { expect(reply1.entries![0]).to.equal(await Message.getCid(delete1.message!)); }); - it('filters by dateCreated', async () => { - // scenario: 4 records, created on first of 2021, 2022, 2023, 2024 respectively, only the first 2 records - const firstDayOf2021 = Time.createTimestamp({ year: 2021, month: 1, day: 1 }); - const firstDayOf2022 = Time.createTimestamp({ year: 2022, month: 1, day: 1 }); - const firstDayOf2023 = Time.createTimestamp({ year: 2023, month: 1, day: 1 }); - const firstDayOf2024 = Time.createTimestamp({ year: 2024, month: 1, day: 1 }); - - const alice = await TestDataGenerator.generateDidKeyPersona(); - const write1 = await TestDataGenerator.generateRecordsWrite({ author: alice, dateCreated: firstDayOf2021, messageTimestamp: firstDayOf2021 }); - const write2 = await TestDataGenerator.generateRecordsWrite({ author: alice, dateCreated: firstDayOf2022, messageTimestamp: firstDayOf2022 }); - const write3 = await TestDataGenerator.generateRecordsWrite({ author: alice, dateCreated: firstDayOf2023, messageTimestamp: firstDayOf2023 }); - const write4 = await TestDataGenerator.generateRecordsWrite({ author: alice, dateCreated: firstDayOf2024, messageTimestamp: firstDayOf2024 }); - - // insert data - const writeReply1 = await dwn.processMessage(alice.did, write1.message, { dataStream: write1.dataStream }); - const writeReply2 = await dwn.processMessage(alice.did, write2.message, { dataStream: write2.dataStream }); - const writeReply3 = await dwn.processMessage(alice.did, write3.message, { dataStream: write3.dataStream }); - const writeReply4 = await dwn.processMessage(alice.did, write4.message, { dataStream: write4.dataStream }); - expect(writeReply1.status.code).to.equal(202); - expect(writeReply2.status.code).to.equal(202); - expect(writeReply3.status.code).to.equal(202); - expect(writeReply4.status.code).to.equal(202); - - // testing `from` range with a limit - const lastDayOf2021 = Time.createTimestamp({ year: 2021, month: 12, day: 31 }); - let fromLastDayOf2021 = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ dateCreated: { from: lastDayOf2021 } }], - }); - let fromLastDayOf2021Reply = await dwn.processMessage(alice.did, fromLastDayOf2021.message); - expect(fromLastDayOf2021Reply.status.code).to.equal(200); - expect(fromLastDayOf2021Reply.entries?.length).to.equal(3); - expect(fromLastDayOf2021Reply.entries![0]).to.equal(await Message.getCid(write2.message!)); - expect(fromLastDayOf2021Reply.entries![1]).to.equal(await Message.getCid(write3.message!)); - expect(fromLastDayOf2021Reply.entries![2]).to.equal(await Message.getCid(write4.message!)); - - // testing `to` range - const lastDayOf2022 = Time.createTimestamp({ year: 2022, month: 12, day: 31 }); - let toLastDayOf2022 = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ dateCreated: { to: lastDayOf2022 } }], - }); - let toLastDayOf2022Reply = await dwn.processMessage(alice.did, toLastDayOf2022.message); - expect(toLastDayOf2022Reply.status.code).to.equal(200); - expect(toLastDayOf2022Reply.entries?.length).to.equal(2); - expect(toLastDayOf2022Reply.entries![0]).to.equal(await Message.getCid(write1.message!)); - expect(toLastDayOf2022Reply.entries![1]).to.equal(await Message.getCid(write2.message!)); - - // testing `from` and `to` range - const lastDayOf2023 = Time.createTimestamp({ year: 2023, month: 12, day: 31 }); - let fromLastDay2022ToLastDay2023 = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ dateCreated: { from: lastDayOf2022, to: lastDayOf2023 } }], - }); - let fromLastDayOf2022ToLastDay2023Reply = await dwn.processMessage(alice.did, fromLastDay2022ToLastDay2023.message); - expect(fromLastDayOf2022ToLastDay2023Reply.status.code).to.equal(200); - expect(fromLastDayOf2022ToLastDay2023Reply.entries?.length).to.equal(1); - expect(fromLastDayOf2022ToLastDay2023Reply.entries![0]).to.equal(await Message.getCid(write3.message!)); - - // testing edge case where value equals `from` and `to` - let fromFirstDay2022ToFirstDay2023 = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ dateCreated: { from: firstDayOf2022, to: firstDayOf2023 } }], - }); - let fromFirstDay2022ToFirstDay2023Reply = await dwn.processMessage(alice.did, fromFirstDay2022ToFirstDay2023.message); - expect(fromFirstDay2022ToFirstDay2023Reply.status.code).to.equal(200); - expect(fromFirstDay2022ToFirstDay2023Reply.entries?.length).to.equal(1); - expect(fromFirstDay2022ToFirstDay2023Reply.entries![0]).to.equal(await Message.getCid(write2.message!)); - - // add an additional records to match against the previous queries - const write5 = await TestDataGenerator.generateRecordsWrite({ author: alice, dateCreated: lastDayOf2022, messageTimestamp: lastDayOf2022 }); - const writeReply5 = await dwn.processMessage(alice.did, write5.message, { dataStream: write5.dataStream }); - expect(writeReply5.status.code).to.equal(202); - const write6 = await TestDataGenerator.generateRecordsWrite({ author: alice, dateCreated: firstDayOf2021, messageTimestamp: firstDayOf2021 }); - const writeReply6 = await dwn.processMessage(alice.did, write6.message, { dataStream: write6.dataStream }); - expect(writeReply6.status.code).to.equal(202); - - fromLastDayOf2021 = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ dateCreated: { from: lastDayOf2021 } }], - cursor : fromLastDayOf2021Reply.cursor - }); - fromLastDayOf2021Reply = await dwn.processMessage(alice.did, fromLastDayOf2021.message); - expect(fromLastDayOf2021Reply.status.code).to.equal(200); - expect(fromLastDayOf2021Reply.entries?.length).to.equal(1); - expect(fromLastDayOf2021Reply.entries![0]).to.equal(await Message.getCid(write5.message!)); - - toLastDayOf2022 = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ dateCreated: { to: lastDayOf2022 } }], - cursor : toLastDayOf2022Reply.cursor, - }); - toLastDayOf2022Reply = await dwn.processMessage(alice.did, toLastDayOf2022.message); - expect(toLastDayOf2022Reply.status.code).to.equal(200); - expect(toLastDayOf2022Reply.entries?.length).to.equal(1); - expect(toLastDayOf2022Reply.entries![0]).to.equal(await Message.getCid(write6.message!)); - - fromLastDay2022ToLastDay2023 = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ dateCreated: { from: lastDayOf2022, to: lastDayOf2023 } }], - cursor : fromLastDayOf2022ToLastDay2023Reply.cursor, - }); - fromLastDayOf2022ToLastDay2023Reply = await dwn.processMessage(alice.did, fromLastDay2022ToLastDay2023.message); - expect(fromLastDayOf2022ToLastDay2023Reply.status.code).to.equal(200); - expect(fromLastDayOf2022ToLastDay2023Reply.entries?.length).to.equal(1); - expect(fromLastDayOf2021Reply.entries![0]).to.equal(await Message.getCid(write5.message!)); - - // testing edge case where value equals `from` and `to` - fromFirstDay2022ToFirstDay2023 = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ dateCreated: { from: firstDayOf2022, to: firstDayOf2023 } }], - cursor : fromFirstDay2022ToFirstDay2023Reply.cursor, - }); - fromFirstDay2022ToFirstDay2023Reply = await dwn.processMessage(alice.did, fromFirstDay2022ToFirstDay2023.message); - expect(fromFirstDay2022ToFirstDay2023Reply.status.code).to.equal(200); - expect(fromFirstDay2022ToFirstDay2023Reply.entries?.length).to.equal(1); - expect(fromLastDayOf2021Reply.entries![0]).to.equal(await Message.getCid(write5.message!)); - }); - it('filters by a protocol across different message types', async () => { // scenario: // alice creates (3) different message types all related to "proto1" (Configure, RecordsWrite, RecordsDelete) @@ -468,646 +348,5 @@ export function testEventsQueryScenarios(): void { expect(proto2EventsReply.entries?.length).equals(1); expect(proto2EventsReply.entries![0]).to.equal(await Message.getCid(deleteProto2Message.message)); }); - - it('filters by protocol, protocolPath & parentId', async () => { - // scenario: get all messages across a protocol & protocolPath combo - // alice installs a protocol and creates a thread - // alice adds bob and carol as participants - // alice, bob, and carol all create messages - // alice filter for 'thread', 'thread/participants' and 'thread/messages' - // alice deletes carol participant message - // alice filters for 'thread/participant' after a cursor - - const alice = await TestDataGenerator.generateDidKeyPersona(); - const bob = await TestDataGenerator.generateDidKeyPersona(); - const carol = await TestDataGenerator.generateDidKeyPersona(); - - // create protocol - const protocolConfigure = await TestDataGenerator.generateProtocolsConfigure({ - author : alice, - protocolDefinition : { ...threadProtocol } - }); - const protocolConfigureReply = await dwn.processMessage(alice.did, protocolConfigure.message); - expect(protocolConfigureReply.status.code).to.equal(202); - const protocol = protocolConfigure.message.descriptor.definition.protocol; - - // alice creates thread - const thread = await TestDataGenerator.generateRecordsWrite({ - author : alice, - protocol : protocol, - protocolPath : 'thread' - }); - const threadReply = await dwn.processMessage(alice.did, thread.message, { dataStream: thread.dataStream }); - expect(threadReply.status.code).to.equal(202); - - // add bob as participant - const bobParticipant = await TestDataGenerator.generateRecordsWrite({ - author : alice, - recipient : bob.did, - parentContextId : thread.message.contextId, - protocol : protocol, - protocolPath : 'thread/participant' - }); - const bobParticipantReply = await dwn.processMessage(alice.did, bobParticipant.message, { dataStream: bobParticipant.dataStream }); - expect(bobParticipantReply.status.code).to.equal(202); - - // add carol as participant - const carolParticipant = await TestDataGenerator.generateRecordsWrite({ - author : alice, - recipient : carol.did, - parentContextId : thread.message.contextId, - protocol : protocol, - protocolPath : 'thread/participant' - }); - const carolParticipantReply = await dwn.processMessage(alice.did, carolParticipant.message, { dataStream: carolParticipant.dataStream }); - expect(carolParticipantReply.status.code).to.equal(202); - - // add a message to protocol1 - const message1 = await TestDataGenerator.generateRecordsWrite({ - author : bob, - recipient : alice.did, - parentContextId : thread.message.contextId, - protocol : protocol, - protocolPath : 'thread/chat', - protocolRole : 'thread/participant', - }); - const message1Reply = await dwn.processMessage(alice.did, message1.message, { dataStream: message1.dataStream }); - expect(message1Reply.status.code).to.equal(202); - - const message2 = await TestDataGenerator.generateRecordsWrite({ - author : bob, - recipient : alice.did, - parentContextId : thread.message.contextId, - protocol : protocol, - protocolPath : 'thread/chat', - protocolRole : 'thread/participant', - }); - const message2Reply = await dwn.processMessage(alice.did, message2.message, { dataStream: message2.dataStream }); - expect(message2Reply.status.code).to.equal(202); - - const message3 = await TestDataGenerator.generateRecordsWrite({ - author : carol, - recipient : alice.did, - parentContextId : thread.message.contextId, - protocol : protocol, - protocolPath : 'thread/chat', - protocolRole : 'thread/participant', - }); - const message3Reply = await dwn.processMessage(alice.did, message3.message, { dataStream: message3.dataStream }); - expect(message3Reply.status.code).to.equal(202); - - // query for thread - const threadQuery = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ protocol: protocol, protocolPath: 'thread' }], - }); - const threadQueryReply = await dwn.processMessage(alice.did, threadQuery.message); - expect(threadQueryReply.status.code).to.equal(200); - expect(threadQueryReply.entries?.length).to.equal(1); - expect(threadQueryReply.entries![0]).to.equal(await Message.getCid(thread.message)); - - // query for participants - let participantsQuery = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ protocol: protocol, protocolPath: 'thread/participant', parentId: thread.message.recordId }], - }); - let participantsQueryReply = await dwn.processMessage(alice.did, participantsQuery.message); - expect(participantsQueryReply.status.code).to.equal(200); - expect(participantsQueryReply.entries?.length).to.equal(2); - expect(participantsQueryReply.entries![0]).to.equal(await Message.getCid(bobParticipant.message)); - expect(participantsQueryReply.entries![1]).to.equal(await Message.getCid(carolParticipant.message)); - - // query for chats - let chatQuery = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ protocol: protocol, protocolPath: 'thread/chat', parentId: thread.message.recordId }], - }); - let chatQueryReply = await dwn.processMessage(alice.did, chatQuery.message); - expect(chatQueryReply.status.code).to.equal(200); - expect(chatQueryReply.entries?.length).to.equal(3); - expect(chatQueryReply.entries![0]).to.equal(await Message.getCid(message1.message)); - expect(chatQueryReply.entries![1]).to.equal(await Message.getCid(message2.message)); - expect(chatQueryReply.entries![2]).to.equal(await Message.getCid(message3.message)); - - // delete carol participant - const deleteCarol = await TestDataGenerator.generateRecordsDelete({ - author : alice, - recordId : carolParticipant.message.recordId - }); - const deleteCarolReply = await dwn.processMessage(alice.did, deleteCarol.message); - expect(deleteCarolReply.status.code).to.equal(202); - - // query for participants past the cursor - participantsQuery = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ protocol: protocol, protocolPath: 'thread/participant', parentId: thread.message.recordId }], - cursor : participantsQueryReply.cursor - }); - participantsQueryReply = await dwn.processMessage(alice.did, participantsQuery.message); - expect(participantsQueryReply.status.code).to.equal(200); - expect(participantsQueryReply.entries?.length).to.equal(1); - expect(participantsQueryReply.entries![0]).to.equal(await Message.getCid(deleteCarol.message)); - - // query for chats beyond the cursor as a control, should have none. - chatQuery = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ protocol: protocol, protocolPath: 'thread/chat', parentId: thread.message.recordId }], - cursor : chatQueryReply.cursor - }); - chatQueryReply = await dwn.processMessage(alice.did, chatQuery.message); - expect(chatQueryReply.status.code).to.equal(200); - expect(chatQueryReply.entries?.length).to.equal(0); - }); - - it('filters by recipient', async () => { - // scenario: alice installs a free-for-all protocol and makes posts with both bob and carol as recipients - // carol and bob also make posts with alice as a recipient - // alice queries for events meant for specific recipients - // alice then makes another message to query for using the pervious as a cursor - - const alice = await TestDataGenerator.generateDidKeyPersona(); - const bob = await TestDataGenerator.generateDidKeyPersona(); - const carol = await TestDataGenerator.generateDidKeyPersona(); - - const protocolConfigure = await TestDataGenerator.generateProtocolsConfigure({ - author : alice, - protocolDefinition : { ...freeForAll } - }); - const protocolConfigureReply = await dwn.processMessage(alice.did, protocolConfigure.message); - expect(protocolConfigureReply.status.code).to.equal(202); - const protocol = protocolConfigure.message.descriptor.definition.protocol; - - const postProperties = { - protocol : protocol, - protocolPath : 'post', - schema : freeForAll.types.post.schema, - dataFormat : freeForAll.types.post.dataFormats[0], - }; - - const messageFromAliceToBob = await TestDataGenerator.generateRecordsWrite({ - ...postProperties, - author : alice, - recipient : bob.did, - }); - const messageFromAliceToBobReply = - await dwn.processMessage(alice.did, messageFromAliceToBob.message, { dataStream: messageFromAliceToBob.dataStream }); - expect(messageFromAliceToBobReply.status.code).to.equal(202); - - const messageFromAliceToCarol = await TestDataGenerator.generateRecordsWrite({ - ...postProperties, - author : alice, - recipient : carol.did, - }); - const messageFromAliceToCarolReply = - await dwn.processMessage(alice.did, messageFromAliceToCarol.message, { dataStream: messageFromAliceToCarol.dataStream }); - expect(messageFromAliceToCarolReply.status.code).to.equal(202); - - const messageFromBobToAlice = await TestDataGenerator.generateRecordsWrite({ - ...postProperties, - author : bob, - recipient : alice.did, - }); - const messageFromBobToAliceReply = - await dwn.processMessage(alice.did, messageFromBobToAlice.message, { dataStream: messageFromBobToAlice.dataStream }); - expect(messageFromBobToAliceReply.status.code).to.equal(202); - - const messageFromCarolToAlice = await TestDataGenerator.generateRecordsWrite({ - ...postProperties, - author : carol, - recipient : alice.did, - }); - const messageFromCarolToAliceReply = - await dwn.processMessage(alice.did, messageFromCarolToAlice.message, { dataStream: messageFromCarolToAlice.dataStream }); - expect(messageFromCarolToAliceReply.status.code).to.equal(202); - - let authorQuery = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ recipient: alice.did }] - }); - let authorQueryReply = await dwn.processMessage(alice.did, authorQuery.message); - expect(authorQueryReply.status.code).to.equal(200); - expect(authorQueryReply.entries?.length).to.equal(2); - expect(authorQueryReply.entries![0]).to.equal(await Message.getCid(messageFromBobToAlice.message)); - expect(authorQueryReply.entries![1]).to.equal(await Message.getCid(messageFromCarolToAlice.message)); - - authorQuery = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ recipient: bob.did }] - }); - authorQueryReply = await dwn.processMessage(alice.did, authorQuery.message); - expect(authorQueryReply.status.code).to.equal(200); - expect(authorQueryReply.entries?.length).to.equal(1); - expect(authorQueryReply.entries![0]).to.equal(await Message.getCid(messageFromAliceToBob.message)); - - - // add another message - const messageFromAliceToBob2 = await TestDataGenerator.generateRecordsWrite({ - ...postProperties, - author : alice, - recipient : bob.did, - }); - const messageFromAliceToBob2Reply = - await dwn.processMessage(alice.did, messageFromAliceToBob2.message, { dataStream: messageFromAliceToBob2.dataStream }); - expect(messageFromAliceToBob2Reply.status.code).to.equal(202); - - authorQuery = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ recipient: bob.did }], - cursor : authorQueryReply.cursor, - }); - - authorQueryReply = await dwn.processMessage(alice.did, authorQuery.message); - expect(authorQueryReply.status.code).to.equal(200); - expect(authorQueryReply.entries?.length).to.equal(1); - expect(authorQueryReply.entries![0]).to.equal(await Message.getCid(messageFromAliceToBob2.message)); - }); - - it('filters by schema', async () => { - const alice = await TestDataGenerator.generateDidKeyPersona(); - - const schema1Message1 = await TestDataGenerator.generateRecordsWrite({ - author : alice, - schema : 'schema1' - }); - const schema1Message1Reply = await dwn.processMessage(alice.did, schema1Message1.message, { dataStream: schema1Message1.dataStream }); - expect(schema1Message1Reply.status.code).to.equal(202); - - const schema2Message1 = await TestDataGenerator.generateRecordsWrite({ - author : alice, - schema : 'schema2' - }); - const schema2Message1Reply = await dwn.processMessage(alice.did, schema2Message1.message, { dataStream: schema2Message1.dataStream }); - expect(schema2Message1Reply.status.code).to.equal(202); - - const schema2Message2 = await TestDataGenerator.generateRecordsWrite({ - author : alice, - schema : 'schema2' - }); - const schema2Message2Reply = await dwn.processMessage(alice.did, schema2Message2.message, { dataStream: schema2Message2.dataStream }); - expect(schema2Message2Reply.status.code).to.equal(202); - - let schema1Query = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ schema: 'schema1' }], - }); - let schema1QueryReply = await dwn.processMessage(alice.did, schema1Query.message); - expect(schema1QueryReply.status.code).to.equal(200); - expect(schema1QueryReply.entries?.length).to.equal(1); - expect(schema1QueryReply.entries![0]).to.equal(await Message.getCid(schema1Message1.message)); - - let schema2Query = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ schema: 'schema2' }], - }); - let schema2QueryReply = await dwn.processMessage(alice.did, schema2Query.message); - expect(schema2QueryReply.status.code).to.equal(200); - expect(schema2QueryReply.entries?.length).to.equal(2); - expect(schema2QueryReply.entries![0]).to.equal(await Message.getCid(schema2Message1.message)); - expect(schema2QueryReply.entries![1]).to.equal(await Message.getCid(schema2Message2.message)); - - const schema1Message2 = await TestDataGenerator.generateRecordsWrite({ - author : alice, - schema : 'schema1' - }); - const schema1Message2Reply = await dwn.processMessage(alice.did, schema1Message2.message, { dataStream: schema1Message2.dataStream }); - expect(schema1Message2Reply.status.code).to.equal(202); - - schema1Query = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ schema: 'schema1' }], - cursor : schema1QueryReply.cursor, - }); - schema1QueryReply = await dwn.processMessage(alice.did, schema1Query.message); - expect(schema1QueryReply.status.code).to.equal(200); - expect(schema1QueryReply.entries?.length).to.equal(1); - expect(schema1QueryReply.entries![0]).to.equal(await Message.getCid(schema1Message2.message)); - - schema2Query = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ schema: 'schema2' }], - cursor : schema2QueryReply.cursor, - }); - schema2QueryReply = await dwn.processMessage(alice.did, schema2Query.message); - expect(schema2QueryReply.status.code).to.equal(200); - expect(schema2QueryReply.entries?.length).to.equal(0); - }); - - it('filters by recordId', async () => { - const alice = await TestDataGenerator.generateDidKeyPersona(); - - // a write as a control, will not show up in query - const controlWrite = await TestDataGenerator.generateRecordsWrite({ - author : alice, - schema : 'schema1' - }); - const write2Reply = await dwn.processMessage(alice.did, controlWrite.message, { dataStream: controlWrite.dataStream }); - expect(write2Reply.status.code).to.equal(202); - - const write = await TestDataGenerator.generateRecordsWrite({ - author : alice, - schema : 'schema1' - }); - const write1Reply = await dwn.processMessage(alice.did, write.message, { dataStream: write.dataStream }); - expect(write1Reply.status.code).to.equal(202); - - const update = await TestDataGenerator.generateFromRecordsWrite({ - author : alice, - existingWrite : write.recordsWrite, - }); - const updateReply = await dwn.processMessage(alice.did, update.message, { dataStream: update.dataStream }); - expect(updateReply.status.code).to.equal(202); - - let recordQuery = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ recordId: write.message.recordId }], - }); - let recordQueryReply = await dwn.processMessage(alice.did, recordQuery.message); - expect(recordQueryReply.status.code).to.equal(200); - expect(recordQueryReply.entries?.length).to.equal(2); - expect(recordQueryReply.entries![0]).to.equal(await Message.getCid(write.message)); - expect(recordQueryReply.entries![1]).to.equal(await Message.getCid(update.message)); - - const deleteRecord = await TestDataGenerator.generateRecordsDelete({ - author : alice, - recordId : write.message.recordId, - }); - const deleteRecordReply = await dwn.processMessage(alice.did, deleteRecord.message); - expect(deleteRecordReply.status.code).to.equal(202); - - recordQuery = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ recordId: write.message.recordId }], - cursor : recordQueryReply.cursor, - }); - recordQueryReply = await dwn.processMessage(alice.did, recordQuery.message); - expect(recordQueryReply.status.code).to.equal(200); - expect(recordQueryReply.entries?.length).to.equal(1); - expect(recordQueryReply.entries![0]).to.equal(await Message.getCid(deleteRecord.message)); - }); - - it('filters by dataFormat', async () => { - // scenario: alice stores different file types and needs events relating to `image/jpeg` - // alice creates 3 files, one of them `image/jpeg` - // alice queries for `image/jpeg` retrieving the one message - // alice adds another image to query for using the prior image as a cursor - - const alice = await TestDataGenerator.generateDidKeyPersona(); - - const textFile = await TestDataGenerator.generateRecordsWrite({ - author : alice, - dataFormat : 'application/text' - }); - const textFileReply = await dwn.processMessage(alice.did, textFile.message, { dataStream: textFile.dataStream }); - expect(textFileReply.status.code).to.equal(202); - - const jsonData = await TestDataGenerator.generateRecordsWrite({ - author : alice, - dataFormat : 'application/json' - }); - const jsonDataReply = await dwn.processMessage(alice.did, jsonData.message, { dataStream: jsonData.dataStream }); - expect(jsonDataReply.status.code).to.equal(202); - - const imageData = await TestDataGenerator.generateRecordsWrite({ - author : alice, - dataFormat : 'image/jpeg' - }); - const imageDataReply = await dwn.processMessage(alice.did, imageData.message, { dataStream: imageData.dataStream }); - expect(imageDataReply.status.code).to.equal(202); - - //get image data - let imageQuery = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ - dataFormat: 'image/jpeg' - }] - }); - let imageQueryReply = await dwn.processMessage(alice.did, imageQuery.message); - expect(imageQueryReply.status.code).to.equal(200); - expect(imageQueryReply.entries?.length).to.equal(1); - expect(imageQueryReply.entries![0]).to.equal(await Message.getCid(imageData.message)); - - // add another image - const imageData2 = await TestDataGenerator.generateRecordsWrite({ - author : alice, - dataFormat : 'image/jpeg' - }); - const imageData2Reply = await dwn.processMessage(alice.did, imageData2.message, { dataStream: imageData2.dataStream }); - expect(imageData2Reply.status.code).to.equal(202); - - imageQuery = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ - dataFormat: 'image/jpeg' - }], - cursor: imageQueryReply.cursor, - }); - imageQueryReply = await dwn.processMessage(alice.did, imageQuery.message); - expect(imageQueryReply.status.code).to.equal(200); - expect(imageQueryReply.entries?.length).to.equal(1); - expect(imageQueryReply.entries![0]).to.equal(await Message.getCid(imageData2.message)); - });; - - it('filters by dataSize', async () => { - // scenario: - // alice inserts both small and large data - // alice requests events for messages with data size under a threshold - - const alice = await TestDataGenerator.generateDidKeyPersona(); - - const smallSize1 = await TestDataGenerator.generateRecordsWrite({ - author: alice, - }); - const smallSize1Reply = await dwn.processMessage(alice.did, smallSize1.message, { dataStream: smallSize1.dataStream }); - expect(smallSize1Reply.status.code).to.equal(202); - - const largeSize = await TestDataGenerator.generateRecordsWrite({ - author : alice, - data : TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded + 1) - }); - const largeSizeReply = await dwn.processMessage(alice.did, largeSize.message, { dataStream: largeSize.dataStream }); - expect(largeSizeReply.status.code).to.equal(202); - - const smallSize2 = await TestDataGenerator.generateRecordsWrite({ - author: alice, - }); - const smallSize2Reply = await dwn.processMessage(alice.did, smallSize2.message, { dataStream: smallSize2.dataStream }); - expect(smallSize2Reply.status.code).to.equal(202); - - //get large sizes - let largeSizeQuery = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ - dataSize: { gte: DwnConstant.maxDataSizeAllowedToBeEncoded + 1 } - }] - }); - let largeSizeQueryReply = await dwn.processMessage(alice.did, largeSizeQuery.message); - expect(largeSizeQueryReply.status.code).to.equal(200); - expect(largeSizeQueryReply.entries?.length).to.equal(1); - expect(largeSizeQueryReply.entries![0]).to.equal(await Message.getCid(largeSize.message)); - - const largeSize2 = await TestDataGenerator.generateRecordsWrite({ - author : alice, - data : TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded + 1) - }); - const largeSize2Reply = await dwn.processMessage(alice.did, largeSize2.message, { dataStream: largeSize2.dataStream }); - expect(largeSize2Reply.status.code).to.equal(202); - - largeSizeQuery = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ - dataSize: { gte: DwnConstant.maxDataSizeAllowedToBeEncoded + 1 } - }], - cursor: largeSizeQueryReply.cursor, - }); - largeSizeQueryReply = await dwn.processMessage(alice.did, largeSizeQuery.message); - expect(largeSizeQueryReply.status.code).to.equal(200); - expect(largeSizeQueryReply.entries?.length).to.equal(1); - expect(largeSizeQueryReply.entries![0]).to.equal(await Message.getCid(largeSize2.message)); - }); - - it('filters by contextId', async () => { - // scenario: - // alice configures a chat protocols and creates 2 chat threads - // alice invites bob as participant in thread1 and carol in thread2 - // alice writes messages to both bob and carol in their respective threads - // alice queries for events related to thread1 (gets the configure, bob participant, and chats to bob) - // alice writes more messages to both bob and carol in their respective threads - // alice queries for events beyond the latest from the last query, retrieving the additional messages to bob - - const alice = await TestDataGenerator.generateDidKeyPersona(); - const bob = await TestDataGenerator.generateDidKeyPersona(); - const carol = await TestDataGenerator.generateDidKeyPersona(); - - const protocolConfigure = await TestDataGenerator.generateProtocolsConfigure({ - author : alice, - protocolDefinition : { ...threadProtocol } - }); - const protocolConfigureReply = await dwn.processMessage(alice.did, protocolConfigure.message); - expect(protocolConfigureReply.status.code).to.equal(202); - const protocol = protocolConfigure.message.descriptor.definition.protocol; - - // alice creates 2 threads - const thread1 = await TestDataGenerator.generateRecordsWrite({ - author : alice, - protocol : protocol, - protocolPath : 'thread', - }); - const thread1Reply = await dwn.processMessage(alice.did, thread1.message, { dataStream: thread1.dataStream }); - expect(thread1Reply.status.code).to.equal(202); - - const thread2 = await TestDataGenerator.generateRecordsWrite({ - author : alice, - protocol : protocol, - protocolPath : 'thread', - }); - const thread2Reply = await dwn.processMessage(alice.did, thread2.message, { dataStream: thread2.dataStream }); - expect(thread2Reply.status.code).to.equal(202); - - // alice adds bob as a participant to thread 1 - const bobParticipant = await TestDataGenerator.generateRecordsWrite({ - author : alice, - recipient : bob.did, - parentContextId : thread1.message.contextId, - protocol : protocol, - protocolPath : 'thread/participant' - }); - const bobParticipantReply = await dwn.processMessage(alice.did, bobParticipant.message, { dataStream: bobParticipant.dataStream }); - expect(bobParticipantReply.status.code).to.equal(202); - - // alice adds carol as a participant to thread 1 - const carolParticipant = await TestDataGenerator.generateRecordsWrite({ - author : alice, - recipient : carol.did, - parentContextId : thread2.message.contextId, - protocol : protocol, - protocolPath : 'thread/participant' - }); - const carolParticipantReply = await dwn.processMessage(alice.did, carolParticipant.message, { dataStream: carolParticipant.dataStream }); - expect(carolParticipantReply.status.code).to.equal(202); - - // alice writes a message to bob on thread 1 - const thread1Chat1 = await TestDataGenerator.generateRecordsWrite({ - author : alice, - recipient : bob.did, - parentContextId : thread1.message.contextId, - protocol : protocol, - protocolPath : 'thread/chat', - }); - const thread1Chat1Reply = await dwn.processMessage(alice.did, thread1Chat1.message, { dataStream: thread1Chat1.dataStream }); - expect(thread1Chat1Reply.status.code).to.equal(202); - - // alice writes a message to carol on thread 2 - const thread2Chat1 = await TestDataGenerator.generateRecordsWrite({ - author : alice, - recipient : carol.did, - parentContextId : thread2.message.contextId, - protocol : protocol, - protocolPath : 'thread/chat', - }); - const thread2Chat1Reply = await dwn.processMessage(alice.did, thread2Chat1.message, { dataStream: thread2Chat1.dataStream }); - expect(thread2Chat1Reply.status.code).to.equal(202); - - // alice writes another message to bob on thread 1 - const thread1Chat2 = await TestDataGenerator.generateRecordsWrite({ - author : alice, - recipient : bob.did, - parentContextId : thread1.message.contextId, - protocol : protocol, - protocolPath : 'thread/chat', - }); - const chatMessage2Reply = await dwn.processMessage(alice.did, thread1Chat2.message, { dataStream: thread1Chat2.dataStream }); - expect(chatMessage2Reply.status.code).to.equal(202); - - // alice queries events for thread1 - let threadContextQuery = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ - protocol : protocol, - contextId : thread1.message.contextId, - }], - }); - let threadContextQueryReply = await dwn.processMessage(alice.did, threadContextQuery.message); - expect(threadContextQueryReply.status.code).to.equal(200); - expect(threadContextQueryReply.entries?.length).to.equal(4); - expect(threadContextQueryReply.entries![0]).to.equal(await Message.getCid(thread1.message)); - expect(threadContextQueryReply.entries![1]).to.equal(await Message.getCid(bobParticipant.message)); - expect(threadContextQueryReply.entries![2]).to.equal(await Message.getCid(thread1Chat1.message)); - expect(threadContextQueryReply.entries![3]).to.equal(await Message.getCid(thread1Chat2.message)); - - // alice adds more chats to both threads - const thread1Chat3 = await TestDataGenerator.generateRecordsWrite({ - author : alice, - recipient : bob.did, - parentContextId : thread1.message.contextId, - protocol : protocol, - protocolPath : 'thread/chat', - }); - const thread1Chat3Reply = await dwn.processMessage(alice.did, thread1Chat3.message, { dataStream: thread1Chat3.dataStream }); - expect(thread1Chat3Reply.status.code).to.equal(202); - - const thread2Chat2 = await TestDataGenerator.generateRecordsWrite({ - author : alice, - recipient : carol.did, - parentContextId : thread2.message.contextId, - protocol : protocol, - protocolPath : 'thread/chat', - }); - const thread2Chat2Reply = await dwn.processMessage(alice.did, thread2Chat2.message, { dataStream: thread2Chat2.dataStream }); - expect(thread2Chat2Reply.status.code).to.equal(202); - - // query beyond a cursor - threadContextQuery = await TestDataGenerator.generateEventsQuery({ - author : alice, - filters : [{ - protocol : protocol, - contextId : thread1.message.contextId, - }], - cursor: threadContextQueryReply.cursor, - }); - threadContextQueryReply = await dwn.processMessage(alice.did, threadContextQuery.message); - expect(threadContextQueryReply.status.code).to.equal(200); - expect(threadContextQueryReply.entries?.length).to.equal(1); - expect(threadContextQueryReply.entries![0]).to.equal(await Message.getCid(thread1Chat3.message)); - }); }); }; \ No newline at end of file diff --git a/tests/scenarios/subscriptions.spec.ts b/tests/scenarios/subscriptions.spec.ts index 462e6f45f..d6e2547dc 100644 --- a/tests/scenarios/subscriptions.spec.ts +++ b/tests/scenarios/subscriptions.spec.ts @@ -421,632 +421,6 @@ export function testSubscriptionScenarios(): void { }); }); - it('filters by protocol & contextId across multiple protocolPaths', async () => { - // scenario: subscribe to multiple protocolPaths for a given protocol and parentId - // alice installs a protocol and creates a thread - // alice subscribes to with 3 filters: the thread itself, the thread/participants as well as thread thread/chats - // alice adds bob and carol as participants to the thread - // alice, bob, and carol all create messages - // alice deletes carol participant message - // alice checks that the correct messages were omitted - - const alice = await TestDataGenerator.generateDidKeyPersona(); - const bob = await TestDataGenerator.generateDidKeyPersona(); - const carol = await TestDataGenerator.generateDidKeyPersona(); - - // create protocol - const protocolConfigure = await TestDataGenerator.generateProtocolsConfigure({ - author : alice, - protocolDefinition : { ...threadProtocol } - }); - const protocolConfigureReply = await dwn.processMessage(alice.did, protocolConfigure.message); - expect(protocolConfigureReply.status.code).to.equal(202); - const protocol = protocolConfigure.message.descriptor.definition.protocol; - - // alice creates thread - const thread = await TestDataGenerator.generateRecordsWrite({ - author : alice, - protocol : protocol, - protocolPath : 'thread' - }); - const threadReply = await dwn.processMessage(alice.did, thread.message, { dataStream: thread.dataStream }); - expect(threadReply.status.code).to.equal(202); - - // subscribe to this thread's events - const messages:string[] = []; - const subscriptionHandler = async (event: MessageEvent):Promise => { - const { message } = event; - messages.push(await Message.getCid(message)); - }; - - const threadSubscription = await TestDataGenerator.generateEventsSubscribe({ - author : alice, - filters : [ - { protocol: protocol, protocolPath: 'thread', contextId: thread.message.contextId }, // thread updates - { protocol: protocol, protocolPath: 'thread/participant', contextId: thread.message.contextId }, // participant updates - { protocol: protocol, protocolPath: 'thread/chat', contextId: thread.message.contextId } // chat updates - ], - }); - const threadSubscriptionReply = await dwn.processMessage(alice.did, threadSubscription.message, { - subscriptionHandler - }); - expect(threadSubscriptionReply.status.code).to.equal(200); - expect(threadSubscriptionReply.subscription).to.exist; - - // add another thread as a control, will not show up in handled events - // NOTE: we purposely create this thread early in the test to ensure an external pub/sub system can have ample time to process the message - const additionalThread = await TestDataGenerator.generateRecordsWrite({ - author : alice, - protocol : protocol, - protocolPath : 'thread' - }); - const additionalThreadReply = await dwn.processMessage(alice.did, additionalThread.message, { dataStream: additionalThread.dataStream }); - expect(additionalThreadReply.status.code).to.equal(202); - - // add bob as participant - const bobParticipant = await TestDataGenerator.generateRecordsWrite({ - author : alice, - recipient : bob.did, - parentContextId : thread.message.contextId, - protocol : protocol, - protocolPath : 'thread/participant' - }); - const bobParticipantReply = await dwn.processMessage(alice.did, bobParticipant.message, { dataStream: bobParticipant.dataStream }); - expect(bobParticipantReply.status.code).to.equal(202); - - // add carol as participant - const carolParticipant = await TestDataGenerator.generateRecordsWrite({ - author : alice, - recipient : carol.did, - parentContextId : thread.message.contextId, - protocol : protocol, - protocolPath : 'thread/participant' - }); - const carolParticipantReply = await dwn.processMessage(alice.did, carolParticipant.message, { dataStream: carolParticipant.dataStream }); - expect(carolParticipantReply.status.code).to.equal(202); - - // poll until we have the 2 participant messages - await Poller.pollUntilSuccessOrTimeout(async () => { - // the messages array should have the two participant messages - expect(messages.length).to.equal(2); - expect(messages).to.have.members([ - await Message.getCid(bobParticipant.message), - await Message.getCid(carolParticipant.message), - ]); - }); - - // bob adds two chat messages - const message1FromBob = await TestDataGenerator.generateRecordsWrite({ - author : bob, - recipient : alice.did, - parentContextId : thread.message.contextId, - protocol : protocol, - protocolPath : 'thread/chat', - protocolRole : 'thread/participant', - }); - const message1FromBobReply = await dwn.processMessage(alice.did, message1FromBob.message, { dataStream: message1FromBob.dataStream }); - expect(message1FromBobReply.status.code).to.equal(202); - - const message2FromBob = await TestDataGenerator.generateRecordsWrite({ - author : bob, - recipient : alice.did, - parentContextId : thread.message.contextId, - protocol : protocol, - protocolPath : 'thread/chat', - protocolRole : 'thread/participant', - }); - const message2FromBobReply = await dwn.processMessage(alice.did, message2FromBob.message, { dataStream: message2FromBob.dataStream }); - expect(message2FromBobReply.status.code).to.equal(202); - - const messageFromCarol = await TestDataGenerator.generateRecordsWrite({ - author : carol, - recipient : alice.did, - parentContextId : thread.message.contextId, - protocol : protocol, - protocolPath : 'thread/chat', - protocolRole : 'thread/participant', - }); - const messageFromCarolReply = await dwn.processMessage(alice.did, messageFromCarol.message, { dataStream: messageFromCarol.dataStream }); - expect(messageFromCarolReply.status.code).to.equal(202); - - await Poller.pollUntilSuccessOrTimeout(async () => { - // should have the 3 chat messages - expect(messages.length).to.equal(5); - expect(messages).to.include.members([ - await Message.getCid(message1FromBob.message), - await Message.getCid(message2FromBob.message), - await Message.getCid(messageFromCarol.message), - ]); - }); - - // delete carol participant - const deleteCarol = await TestDataGenerator.generateRecordsDelete({ - author : alice, - recordId : carolParticipant.message.recordId - }); - const deleteCarolReply = await dwn.processMessage(alice.did, deleteCarol.message); - expect(deleteCarolReply.status.code).to.equal(202); - - await Poller.pollUntilSuccessOrTimeout(async () => { - // should have the delete of carol as a participant - expect(messages.length).to.equal(6); - expect(messages).to.include.members([ - await Message.getCid(deleteCarol.message) - ]); - - // although we know the control thread is not in the messages array due to the counts - // we explicitly check that it is not in the array as a defensive measure - // NOTE: we purposely check down here to give the message ample time to be processed - expect(messages).to.not.include(await Message.getCid(additionalThread.message)); - }); - }); - - it('filters by schema', async () => { - //SCENARIO: - // alice creates 2 subscriptions, one for schema1 and one for schema2 - // alice creates a record each for schema1 and schema2 - // alice checks that the appropriate messages were received by their respective handlers - // alice updates the record for schema1 - // alice deletes the record for schema2 - // alice checks that the appropriate messages were received by their respective handlers - - const alice = await TestDataGenerator.generateDidKeyPersona(); - - // we will add messageCids to these arrays as they are received by their handler to check against later - const schema1Messages:string[] = []; - const schema2Messages:string[] = []; - - // we add a handler to the subscription and add the messageCid to the appropriate array - const schema1Handler = async (event: MessageEvent):Promise => { - const { message } = event; - const messageCid = await Message.getCid(message); - schema1Messages.push(messageCid); - }; - - // subscribe to schema1 messages - const schema1Subscription = await TestDataGenerator.generateEventsSubscribe({ author: alice, filters: [{ schema: 'http://schema1' }] }); - const schema1SubscriptionReply = await dwn.processMessage(alice.did, schema1Subscription.message, { subscriptionHandler: schema1Handler }); - expect(schema1SubscriptionReply.status.code).to.equal(200); - expect(schema1SubscriptionReply.subscription?.id).to.equal(await Message.getCid(schema1Subscription.message)); - - // we add a handler to the subscription and add the messageCid to the appropriate array - const schema2Handler = async (event: MessageEvent):Promise => { - const { message } = event; - const messageCid = await Message.getCid(message); - schema2Messages.push(messageCid); - }; - - // subscribe to schema2 messages - const schema2Subscription = await TestDataGenerator.generateEventsSubscribe({ author: alice, filters: [{ schema: 'http://schema2' }] }); - const schema2SubscriptionReply = await dwn.processMessage(alice.did, schema2Subscription.message, { subscriptionHandler: schema2Handler }); - expect(schema2SubscriptionReply.status.code).to.equal(200); - expect(schema2SubscriptionReply.subscription?.id).to.equal(await Message.getCid(schema2Subscription.message)); - - // create some random record, will not show up in records subscription - const write1Random = await TestDataGenerator.generateRecordsWrite({ author: alice }); - const write1RandomResponse = await dwn.processMessage(alice.did, write1Random.message, { dataStream: write1Random.dataStream }); - expect(write1RandomResponse.status.code).to.equal(202); - - // create a record for schema1 - const write1schema1 = await TestDataGenerator.generateRecordsWrite({ author: alice, schema: 'http://schema1' }); - const write1Response = await dwn.processMessage(alice.did, write1schema1.message, { dataStream: write1schema1.dataStream }); - expect(write1Response.status.code).equals(202); - - // create a record for schema2 - const write1schema2 = await TestDataGenerator.generateRecordsWrite({ author: alice, schema: 'http://schema2' }); - const write1Proto2Response = await dwn.processMessage(alice.did, write1schema2.message, { dataStream: write1schema2.dataStream }); - expect(write1Proto2Response.status.code).equals(202); - - // poll until the messages are received by the handlers - await Poller.pollUntilSuccessOrTimeout(async () => { - // schema1 messages from handler has the new message representing the write. - expect(schema1Messages.length).to.equal(1, 'schema1'); - expect(schema1Messages).to.include(await Message.getCid(write1schema1.message)); - - // schema2 messages from handler has the new message representing the write. - expect(schema2Messages.length).to.equal(1, 'schema2'); - expect(schema2Messages).to.include(await Message.getCid(write1schema2.message)); - }); - - // create update the record for schema1 - const update1schema1 = await TestDataGenerator.generateFromRecordsWrite({ author: alice, existingWrite: write1schema1.recordsWrite }); - const update1Response = await dwn.processMessage(alice.did, update1schema1.message, { dataStream: update1schema1.dataStream }); - expect(update1Response.status.code).equals(202); - - // delete the record for schema2 - const deleteschema2 = await TestDataGenerator.generateRecordsDelete({ author: alice, recordId: write1schema2.message.recordId }); - const deleteSchema2Response = await dwn.processMessage(alice.did, deleteschema2.message); - expect(deleteSchema2Response.status.code).equals(202); - - await Poller.pollUntilSuccessOrTimeout(async () => { - // schema1 messages from handler has the new message representing the update. - expect(schema1Messages.length).to.equal(2, 'schema1'); - expect(schema1Messages).to.include(await Message.getCid(update1schema1.message)); - - // schema2 messages from handler has the new message representing the delete. - expect(schema2Messages.length).to.equal(2, 'schema2'); - expect(schema2Messages).to.include(await Message.getCid(deleteschema2.message)); - }); - }); - - it('filters by recordId', async () => { - // alice creates a 2 record and don't process them yet. - // alice creates a subscription for only one of the recordIds - // alice now process both records - // alice updates the record that was subscribed to - // check that the subscription handler has both the write and update messages - // delete both records - // check that the subscription handler has the delete message for the subscribed recordId - - const alice = await TestDataGenerator.generateDidKeyPersona(); - - // create 2 records - const write1 = await TestDataGenerator.generateRecordsWrite({ - author : alice, - schema : 'schema1' - }); - - const write2 = await TestDataGenerator.generateRecordsWrite({ - author : alice, - schema : 'schema1' - }); - - // create a subscription and capture the messages associated with the recordId for write1 - const messages: string[] = []; - const subscriptionHandler = async (event: MessageEvent):Promise => { - const { message } = event; - messages.push(await Message.getCid(message)); - }; - - const recordIdSubscribe = await TestDataGenerator.generateEventsSubscribe({ - author : alice, - filters : [{ recordId: write1.message.recordId }] - }); - const recordIdSubscribeReply = await dwn.processMessage(alice.did, recordIdSubscribe.message, { - subscriptionHandler - }); - expect(recordIdSubscribeReply.status.code).to.equal(200); - - // process both records - const write1Reply = await dwn.processMessage(alice.did, write1.message, { dataStream: write1.dataStream }); - expect(write1Reply.status.code).to.equal(202); - const write2Reply = await dwn.processMessage(alice.did, write2.message, { dataStream: write2.dataStream }); - expect(write2Reply.status.code).to.equal(202); - - // update the subscribed record - const update = await TestDataGenerator.generateFromRecordsWrite({ - author : alice, - existingWrite : write1.recordsWrite, - }); - const updateReply = await dwn.processMessage(alice.did, update.message, { dataStream: update.dataStream }); - expect(updateReply.status.code).to.equal(202); - - // check that the subscription handler has both the write and update messages - await Poller.pollUntilSuccessOrTimeout(async () => { - expect(messages.length).to.equal(2); - expect(messages).to.have.members([ - await Message.getCid(write1.message), - await Message.getCid(update.message) - ]); - }); - - // delete both records - const deleteWrite1 = await TestDataGenerator.generateRecordsDelete({ - author : alice, - recordId : write1.message.recordId, - }); - const deleteWrite1Reply = await dwn.processMessage(alice.did, deleteWrite1.message); - expect(deleteWrite1Reply.status.code).to.equal(202); - - const deleteWrite2 = await TestDataGenerator.generateRecordsDelete({ - author : alice, - recordId : write2.message.recordId, - }); - const deleteWrite2Reply = await dwn.processMessage(alice.did, deleteWrite2.message); - expect(deleteWrite2Reply.status.code).to.equal(202); - - // check that the subscription handler has the delete message for the subscribed recordId - await Poller.pollUntilSuccessOrTimeout(async () => { - expect(messages.length).to.equal(3); // write1, update, delete - expect(messages).to.include(await Message.getCid(deleteWrite1.message)); - - // confirm that messages for write2 is not in the messages array - expect(messages).to.not.include(await Message.getCid(write2.message)); - expect(messages).to.not.include(await Message.getCid(deleteWrite2.message)); - }); - }); - - it('filters by recipient', async () => { - // scenario: - // alice subscribes to messages with herself as the recipient - // bob and carol sends a messages to alice - // alice sends a message to bob - // bob and carol send a messages to each other - // alice checks that the receivedMessages array only contains the messages from bob and carol to alice - - const alice = await TestDataGenerator.generateDidKeyPersona(); - const bob = await TestDataGenerator.generateDidKeyPersona(); - const carol = await TestDataGenerator.generateDidKeyPersona(); - - // alice installs a freeForAll protocol - const protocolConfigure = await TestDataGenerator.generateProtocolsConfigure({ - author : alice, - protocolDefinition : { ...freeForAll } - }); - const protocolConfigureReply = await dwn.processMessage(alice.did, protocolConfigure.message); - expect(protocolConfigureReply.status.code).to.equal(202); - const protocol = protocolConfigure.message.descriptor.definition.protocol; - - // create a control handler to capture ALL messages in the protocol - // this will be used to confirm that the messages are not received by alice - // we do this to test that messages are not received by one handler but have had enough time to be processed - // in some external pub/sub system it may take time for the message to be processed - const allMessages:string[] = []; - const allHandler = async (event: MessageEvent): Promise => { - const { message } = event; - allMessages.push(await Message.getCid(message)); - }; - const allSubscription = await TestDataGenerator.generateEventsSubscribe({ - author : alice, - filters : [{ protocol: protocol }] - }); - const allSubscriptionReply = await dwn.processMessage(alice.did, allSubscription.message, { subscriptionHandler: allHandler }); - expect(allSubscriptionReply.status.code).to.equal(200); - - // alice subscribes to messages with herself as the recipient on her own DWN - const aliceMessages:string[] = []; - const handler = async (event: MessageEvent): Promise => { - const { message } = event; - const messageCid = await Message.getCid(message); - aliceMessages.push(messageCid); - }; - - const recipientSubscription = await TestDataGenerator.generateEventsSubscribe({ - author : alice, - filters : [{ recipient: alice.did }] - }); - const authorQueryReply = await dwn.processMessage(alice.did, recipientSubscription.message, { subscriptionHandler: handler }); - expect(authorQueryReply.status.code).to.equal(200); - - - // common properties for the post messages - const postProperties = { - protocol : protocol, - protocolPath : 'post', - schema : freeForAll.types.post.schema, - dataFormat : freeForAll.types.post.dataFormats[0], - }; - - // bob sends a message to alice - const messageFromBobToAlice = await TestDataGenerator.generateRecordsWrite({ - ...postProperties, - author : bob, - recipient : alice.did, - }); - const messageFromBobToAliceReply = - await dwn.processMessage(alice.did, messageFromBobToAlice.message, { dataStream: messageFromBobToAlice.dataStream }); - expect(messageFromBobToAliceReply.status.code).to.equal(202); - - // carol sends a message to alice - const messageFromCarolToAlice = await TestDataGenerator.generateRecordsWrite({ - ...postProperties, - author : carol, - recipient : alice.did, - }); - const messageFromCarolToAliceReply = - await dwn.processMessage(alice.did, messageFromCarolToAlice.message, { dataStream: messageFromCarolToAlice.dataStream }); - expect(messageFromCarolToAliceReply.status.code).to.equal(202); - - // alice sends a message to bob, this will not show up in the aliceMessages array, but will in the allMessages array - const messageFromAliceToBob = await TestDataGenerator.generateRecordsWrite({ - ...postProperties, - author : alice, - recipient : bob.did, - }); - const messageFromAliceToBobReply = - await dwn.processMessage(alice.did, messageFromAliceToBob.message, { dataStream: messageFromAliceToBob.dataStream }); - expect(messageFromAliceToBobReply.status.code).to.equal(202); - - // bob sends a message to carol, this will not show up in the aliceMessages array, but will in the allMessages array - const messageFromBobToCarol = await TestDataGenerator.generateRecordsWrite({ - ...postProperties, - author : bob, - recipient : carol.did, - }); - const messageFromBobToCarolReply = - await dwn.processMessage(alice.did, messageFromBobToCarol.message, { dataStream: messageFromBobToCarol.dataStream }); - expect(messageFromBobToCarolReply.status.code).to.equal(202); - - // poll until the messages are received by the handlers - await Poller.pollUntilSuccessOrTimeout(async () => { - // check that the aliceMessages array only contains the messages from bob and carol to alice - expect(aliceMessages.length).to.equal(2); - expect(aliceMessages).to.have.members([ - await Message.getCid(messageFromBobToAlice.message), - await Message.getCid(messageFromCarolToAlice.message) - ]); - - // check that the allMessages array contains all the messages - expect(allMessages.length).to.equal(4); - expect(allMessages).to.have.members([ - await Message.getCid(messageFromBobToAlice.message), - await Message.getCid(messageFromCarolToAlice.message), - await Message.getCid(messageFromAliceToBob.message), - await Message.getCid(messageFromBobToCarol.message) - ]); - }); - }); - - it('filters by dataFormat', async () => { - // Scenario: Alice subscribes events relating to `image/jpeg` after which a number of record messages of various data formats are processed - // 1. Alice subscribes for `image/jpeg` records - // 2. Alice creates 3 files, one of them `image/jpeg` - // 3. Alice receives the one `image/jpeg` message - // 4. Alice adds another image - // 5. Alice receives the other `image/jpeg` message - - const alice = await TestDataGenerator.generateDidKeyPersona(); - - const imageMessages: string[] = []; - const imageHandler = async (event: MessageEvent):Promise => { - const { message } = event; - imageMessages.push(await Message.getCid(message)); - }; - - // alice subscribes to image/jpeg changes - const imageSubscription = await TestDataGenerator.generateEventsSubscribe({ - author : alice, - filters : [{ dataFormat: 'image/jpeg' }] - }); - const imageSubscriptionReply = await dwn.processMessage(alice.did, imageSubscription.message, { - subscriptionHandler: imageHandler - }); - expect(imageSubscriptionReply.status.code).to.equal(200); - - // NOTE: we purposely create the non-matching files ahead of the matching files. - // this helps ensure that the non-matching files have had ample time to be processed by an external pub/sub system - - // write an `application/text` file (will not match) - const textFile = await TestDataGenerator.generateRecordsWrite({ - author : alice, - dataFormat : 'application/text' - }); - const textFileReply = await dwn.processMessage(alice.did, textFile.message, { dataStream: textFile.dataStream }); - expect(textFileReply.status.code).to.equal(202); - - // write an `application/json` file (will not match) - const jsonData = await TestDataGenerator.generateRecordsWrite({ - author : alice, - dataFormat : 'application/json' - }); - const jsonDataReply = await dwn.processMessage(alice.did, jsonData.message, { dataStream: jsonData.dataStream }); - expect(jsonDataReply.status.code).to.equal(202); - - // write an `image/jpeg` file (will match) - const imageData = await TestDataGenerator.generateRecordsWrite({ - author : alice, - dataFormat : 'image/jpeg' - }); - const imageDataReply = await dwn.processMessage(alice.did, imageData.message, { dataStream: imageData.dataStream }); - expect(imageDataReply.status.code).to.equal(202); - - // poll until the image message is received by the handlers - await Poller.pollUntilSuccessOrTimeout(async () => { - expect(imageMessages.length).to.equal(1); - expect(imageMessages).to.have.members([ await Message.getCid(imageData.message) ]); - }); - - // add another `image/jpeg` file, this should also be received by the handler - const imageData2 = await TestDataGenerator.generateRecordsWrite({ - author : alice, - dataFormat : 'image/jpeg' - }); - const imageData2Reply = await dwn.processMessage(alice.did, imageData2.message, { dataStream: imageData2.dataStream }); - expect(imageData2Reply.status.code).to.equal(202); - - // poll until the image message is received by the handlers - await Poller.pollUntilSuccessOrTimeout(async () => { - expect(imageMessages.length).to.equal(2); - expect(imageMessages).to.include.members([ await Message.getCid(imageData2.message) ]); - }); - });; - - it('filters by dataSize', async () => { - // scenario: - // alice subscribes to messages with data size under a threshold - // alice also subscribes to messages with data size over a threshold - // alice inserts both small and large data messages - // alice checks that the messages were received by their respective handlers - - const alice = await TestDataGenerator.generateDidKeyPersona(); - - // subscribe to small data size messages - const smallMessages: string[] = []; - const subscriptionHandler = async (event: MessageEvent):Promise => { - const { message } = event; - smallMessages.push(await Message.getCid(message)); - }; - const smallMessageSubscription = await TestDataGenerator.generateEventsSubscribe({ - author : alice, - filters : [{ dataSize: { lte: DwnConstant.maxDataSizeAllowedToBeEncoded } }] - }); - const smallMessageSubscriptionReply = await dwn.processMessage(alice.did, smallMessageSubscription.message, { - subscriptionHandler, - }); - expect(smallMessageSubscriptionReply.status.code).to.equal(200); - - // subscribe to large data size messages - const largeMessages: string[] = []; - const largeSubscriptionHandler = async (event: MessageEvent):Promise => { - const { message } = event; - largeMessages.push(await Message.getCid(message)); - }; - const largeMessageSubscription = await TestDataGenerator.generateEventsSubscribe({ - author : alice, - filters : [{ dataSize: { gt: DwnConstant.maxDataSizeAllowedToBeEncoded } }] - }); - const largeMessageSubscriptionReply = await dwn.processMessage(alice.did, largeMessageSubscription.message, { - subscriptionHandler: largeSubscriptionHandler, - }); - expect(largeMessageSubscriptionReply.status.code).to.equal(200); - - // add a small data size record - const smallSize1 = await TestDataGenerator.generateRecordsWrite({ - author: alice, - }); - const smallSize1Reply = await dwn.processMessage(alice.did, smallSize1.message, { dataStream: smallSize1.dataStream }); - expect(smallSize1Reply.status.code).to.equal(202); - - // add a large data size record - const largeSize = await TestDataGenerator.generateRecordsWrite({ - author : alice, - data : TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded + 1) - }); - const largeSizeReply = await dwn.processMessage(alice.did, largeSize.message, { dataStream: largeSize.dataStream }); - expect(largeSizeReply.status.code).to.equal(202); - - await Poller.pollUntilSuccessOrTimeout(async () => { - // smallMessages array should only contain the small data size record - expect(smallMessages.length).to.equal(1); - expect(smallMessages).to.have.members([ await Message.getCid(smallSize1.message) ]); - - // largeMessages array should only contain the large data size record - expect(largeMessages.length).to.equal(1); - expect(largeMessages).to.have.members([ await Message.getCid(largeSize.message) ]); - }); - - // add another large record - const largeSize2 = await TestDataGenerator.generateRecordsWrite({ - author : alice, - data : TestDataGenerator.randomBytes(DwnConstant.maxDataSizeAllowedToBeEncoded + 1) - }); - const largeSize2Reply = await dwn.processMessage(alice.did, largeSize2.message, { dataStream: largeSize2.dataStream }); - expect(largeSize2Reply.status.code).to.equal(202); - - // add another small record - const smallSize2 = await TestDataGenerator.generateRecordsWrite({ - author: alice, - }); - const smallSize2Reply = await dwn.processMessage(alice.did, smallSize2.message, { dataStream: smallSize2.dataStream }); - expect(smallSize2Reply.status.code).to.equal(202); - - await Poller.pollUntilSuccessOrTimeout(async () => { - // smallMessages array should only contain the two small data size records - expect(smallMessages.length).to.equal(2); - expect(smallMessages).to.include.members([ - await Message.getCid(smallSize1.message), - await Message.getCid(smallSize2.message) - ]); - - // largeMessages array should only contain the two large data size records - expect(largeMessages.length).to.equal(2); - expect(largeMessages).to.include.members([ - await Message.getCid(largeSize.message), - await Message.getCid(largeSize2.message) - ]); - }); - }); - it('does not emit events after subscription is closed', async () => { // scenario: create two subscriptions. // write a message, check that both subscriptions receive the message. @@ -1148,7 +522,6 @@ export function testSubscriptionScenarios(): void { }; const allSubscription = await TestDataGenerator.generateEventsSubscribe({ author : alice, - filters : [{ schema: 'http://schema1' }] }); const allSubscriptionReply = await dwn.processMessage(alice.did, allSubscription.message, { subscriptionHandler: allHandler }); expect(allSubscriptionReply.status.code).to.equal(200); diff --git a/tests/utils/events.spec.ts b/tests/utils/events.spec.ts index b7a59db70..739f68ce5 100644 --- a/tests/utils/events.spec.ts +++ b/tests/utils/events.spec.ts @@ -3,7 +3,7 @@ import type { Filter } from '../../src/types/query-types.js'; import { Events } from '../../src/utils/events.js'; import { FilterUtility } from '../../src/utils/filter.js'; -import { PermissionsProtocol, TestDataGenerator } from '../../src/index.js'; +import { DwnInterfaceName, DwnMethodName, PermissionsProtocol, TestDataGenerator } from '../../src/index.js'; import sinon from 'sinon'; @@ -25,21 +25,15 @@ describe('Events Utils', () => { describe('extractProtocolTagFilters', () => { it('does not apply any tag filters to non-protocol-filtered events', async () => { - const exampleDid = 'did:example:123'; - const exampleContextId = 'abc/123'; - - // contextIds are converted to range filters, so we should expect this to be converted to a range filter in the following tests - const prefixContextIdFilter = FilterUtility.constructPrefixFilterAsRangeFilter(exampleContextId); - const eventsFilter: EventsFilter = { - recipient : exampleDid, - contextId : exampleContextId + interface : DwnInterfaceName.Records, + method : DwnMethodName.Write }; const messageFilter: Filter[] = Events.convertFilters([eventsFilter]); expect(messageFilter.length).to.equal(1); - expect(messageFilter[0].recipient).to.equal(exampleDid); - expect(messageFilter[0].contextId).to.deep.equal(prefixContextIdFilter); + expect(messageFilter[0].interface).to.equal(DwnInterfaceName.Records); + expect(messageFilter[0].method).to.deep.equal(DwnMethodName.Write); }); it('applies appropriate tag filters to protocol-filtered events', async () => { @@ -47,11 +41,6 @@ describe('Events Utils', () => { // when we filter for a protocol, we should add the tag filters in to accommodate for the protocol tag index const exampleProtocol = 'https://example.xyz/protocol/1'; - const exampleDid = 'did:example:123'; - const exampleContextId = 'abc/123'; - - // contextIds are converted to range filters, so we should expect this to be converted to a range filter in the following tests - const prefixContextIdFilter = FilterUtility.constructPrefixFilterAsRangeFilter(exampleContextId); // only a protocol filter is applied const protocolEventsFilter: EventsFilter = { @@ -80,8 +69,8 @@ describe('Events Utils', () => { // with other filters in addition to the filtered protocol const otherEventsFilter: EventsFilter = { protocol : exampleProtocol, - recipient : exampleDid, - contextId : exampleContextId + interface : DwnInterfaceName.Records, + method : DwnMethodName.Write }; const messageFilter: Filter[] = Events.convertFilters([otherEventsFilter]); @@ -97,27 +86,22 @@ describe('Events Utils', () => { // should have the remaining filters expect(Object.keys(remainingFilter2).length).to.equal(3); expect(remainingFilter2.protocol).to.equal(exampleProtocol); - expect(remainingFilter2.recipient).to.equal(exampleDid); - expect(remainingFilter2.contextId).to.deep.equal(prefixContextIdFilter); + expect(remainingFilter2.interface).to.equal(DwnInterfaceName.Records); + expect(remainingFilter2.method).to.deep.equal(DwnMethodName.Write); }); - it('applies appropriate tag filters to protocol-filtered events with dateUpdated filter', async () => { + it('applies appropriate tag filters to protocol-filtered events with messageTimestamp filter', async () => { // should apply the dateUpdated filter to the protocol tag filter const exampleProtocol = 'https://example.xyz/protocol/1'; - const exampleDid = 'did:example:123'; - const exampleContextId = 'abc/123'; const dateUpdatedTimestamp = TestDataGenerator.randomTimestamp(); const messageTimestampFilterResult = FilterUtility.convertRangeCriterion({ from: dateUpdatedTimestamp }); - // contextIds are converted to range filters, so we should expect this to be converted to a range filter in the following tests - const prefixContextIdFilter = FilterUtility.constructPrefixFilterAsRangeFilter(exampleContextId); - const withDateUpdatedFilter: EventsFilter = { - protocol : exampleProtocol, - recipient : exampleDid, - contextId : exampleContextId, - dateUpdated : { from: dateUpdatedTimestamp } + protocol : exampleProtocol, + interface : DwnInterfaceName.Records, + method : DwnMethodName.Write, + messageTimestamp : { from: dateUpdatedTimestamp } }; const messageFilter: Filter[] = Events.convertFilters([withDateUpdatedFilter]); @@ -128,40 +112,9 @@ describe('Events Utils', () => { expect(messageFilter[1].protocol).to.equal(exampleProtocol); - expect(messageFilter[1].recipient).to.equal(exampleDid); - expect(messageFilter[1].contextId).to.deep.equal(prefixContextIdFilter); + expect(messageFilter[1].interface).to.equal(DwnInterfaceName.Records); + expect(messageFilter[1].method).to.deep.equal(DwnMethodName.Write); expect(messageFilter[1].messageTimestamp).to.deep.equal(messageTimestampFilterResult); }); - - it('applies appropriate tag filters to protocol-filtered events with dateCreated filter', async () => { - // should apply the dateCreated filter to the protocol tag filter - - const exampleProtocol = 'https://example.xyz/protocol/1'; - const exampleDid = 'did:example:123'; - const exampleContextId = 'abc/123'; - const dateCreatedTimestamp = TestDataGenerator.randomTimestamp(); - const dateCreatedFilterResult = FilterUtility.convertRangeCriterion({ from: dateCreatedTimestamp }); - - // contextIds are converted to range filters, so we should expect this to be converted to a range filter in the following tests - const prefixContextIdFilter = FilterUtility.constructPrefixFilterAsRangeFilter(exampleContextId); - - const withDateCreatedFilter: EventsFilter = { - protocol : exampleProtocol, - recipient : exampleDid, - contextId : exampleContextId, - dateCreated : { from: dateCreatedTimestamp } - }; - - const messageFilter: Filter[] = Events.convertFilters([withDateCreatedFilter]); - expect(messageFilter.length).to.equal(2); - expect(messageFilter[0].protocol).to.equal(PermissionsProtocol.uri); - expect(messageFilter[0]['tag.protocol']).to.equal(exampleProtocol); - expect(messageFilter[0].dateCreated).to.deep.equal(dateCreatedFilterResult); - - expect(messageFilter[1].protocol).to.equal(exampleProtocol); - expect(messageFilter[1].recipient).to.equal(exampleDid); - expect(messageFilter[1].contextId).to.deep.equal(prefixContextIdFilter); - expect(messageFilter[1].dateCreated).to.deep.equal(dateCreatedFilterResult); - }); }); }); \ No newline at end of file