diff --git a/packages/agent/tests/cached-permissions.spec.ts b/packages/agent/tests/cached-permissions.spec.ts index d65540acc..134e3b56c 100644 --- a/packages/agent/tests/cached-permissions.spec.ts +++ b/packages/agent/tests/cached-permissions.spec.ts @@ -5,13 +5,10 @@ import { PlatformAgentTestHarness } from '../src/test-harness.js'; import { TestAgent } from './utils/test-agent.js'; import { BearerDid } from '@web5/dids'; -import { testDwnUrl } from './utils/test-config.js'; import { DwnInterfaceName, DwnMethodName, Time } from '@tbd54566975/dwn-sdk-js'; import { CachedPermissions, DwnInterface } from '../src/index.js'; import { Convert } from '@web5/common'; -let testDwnUrls: string[] = [testDwnUrl]; - describe('CachedPermissions', () => { let permissions: AgentPermissionsApi; let testHarness: PlatformAgentTestHarness; @@ -37,11 +34,11 @@ describe('CachedPermissions', () => { await testHarness.createAgentDid(); // Create an "alice" Identity to author the DWN messages. - const alice = await testHarness.createIdentity({ name: 'Alice', testDwnUrls }); + const alice = await testHarness.agent.identity.create({ didMethod: 'jwk', metadata: { name: 'Alice' } }); await testHarness.agent.identity.manage({ portableIdentity: await alice.export() }); aliceDid = alice.did; - const bob = await testHarness.createIdentity({ name: 'Bob', testDwnUrls }); + const bob = await testHarness.agent.identity.create({ didMethod: 'jwk', metadata: { name: 'Bob' } }); await testHarness.agent.identity.manage({ portableIdentity: await bob.export() }); bobDid = bob.did; diff --git a/packages/agent/tests/permissions-api.spec.ts b/packages/agent/tests/permissions-api.spec.ts index 0514fb720..bb925d8a3 100644 --- a/packages/agent/tests/permissions-api.spec.ts +++ b/packages/agent/tests/permissions-api.spec.ts @@ -5,11 +5,9 @@ import { PlatformAgentTestHarness } from '../src/test-harness.js'; import { TestAgent } from './utils/test-agent.js'; import { BearerDid } from '@web5/dids'; -import { testDwnUrl } from './utils/test-config.js'; import { DwnInterfaceName, DwnMethodName, Time } from '@tbd54566975/dwn-sdk-js'; import { DwnInterface, DwnPermissionGrant, DwnPermissionScope, Web5PlatformAgent } from '../src/index.js'; -let testDwnUrls: string[] = [testDwnUrl]; describe('AgentPermissionsApi', () => { let testHarness: PlatformAgentTestHarness; @@ -34,7 +32,7 @@ describe('AgentPermissionsApi', () => { await testHarness.createAgentDid(); // Create an "alice" Identity to author the DWN messages. - const alice = await testHarness.createIdentity({ name: 'Alice', testDwnUrls }); + const alice = await testHarness.agent.identity.create({ didMethod: 'jwk', metadata: { name: 'Alice' } }); await testHarness.agent.identity.manage({ portableIdentity: await alice.export() }); aliceDid = alice.did; }); diff --git a/packages/api/tests/dwn-api.spec.ts b/packages/api/tests/dwn-api.spec.ts index d98e399e0..cad98bab1 100644 --- a/packages/api/tests/dwn-api.spec.ts +++ b/packages/api/tests/dwn-api.spec.ts @@ -3,7 +3,7 @@ import type { BearerDid } from '@web5/dids'; import sinon from 'sinon'; import { expect } from 'chai'; import { Web5UserAgent } from '@web5/user-agent'; -import { AgentPermissionsApi, DwnDateSort, DwnInterface, getRecordAuthor, PlatformAgentTestHarness } from '@web5/agent'; +import { AgentPermissionsApi, DwnDateSort, DwnInterface, DwnProtocolDefinition, getRecordAuthor, PlatformAgentTestHarness } from '@web5/agent'; import { DwnApi } from '../src/dwn-api.js'; import { testDwnUrl } from './utils/test-config.js'; @@ -13,6 +13,7 @@ import { DwnInterfaceName, DwnMethodName, PermissionsProtocol, Poller, RecordsWr import { PermissionGrant } from '../src/permission-grant.js'; import { Web5 } from '../src/web5.js'; import { Record } from '../src/record.js'; +import { TestDataGenerator } from './utils/test-data-generator.js'; let testDwnUrls: string[] = [testDwnUrl]; @@ -22,16 +23,15 @@ describe('DwnApi', () => { let dwnAlice: DwnApi; let dwnBob: DwnApi; let testHarness: PlatformAgentTestHarness; + let protocolUri: string; + let protocolDefinition: DwnProtocolDefinition; before(async () => { testHarness = await PlatformAgentTestHarness.setup({ agentClass : Web5UserAgent, agentStores : 'memory' }); - }); - beforeEach(async () => { - sinon.restore(); await testHarness.clearStorage(); await testHarness.createAgentDid(); @@ -48,10 +48,33 @@ describe('DwnApi', () => { // Instantiate DwnApi for both test identities. dwnAlice = new DwnApi({ agent: testHarness.agent, connectedDid: aliceDid.uri }); dwnBob = new DwnApi({ agent: testHarness.agent, connectedDid: bobDid.uri }); + }); + + beforeEach(async () => { + sinon.restore(); + await testHarness.syncStore.clear(); + await testHarness.dwnDataStore.clear(); + await testHarness.dwnEventLog.clear(); + await testHarness.dwnMessageStore.clear(); + await testHarness.dwnResumableTaskStore.clear(); + testHarness.dwnStores.clear(); // clear cached permissions between test runs dwnAlice['cachedPermissionsApi'].clear(); dwnBob['cachedPermissionsApi'].clear(); + + dwnAlice['connectedDid'] = aliceDid.uri; + dwnBob['connectedDid'] = bobDid.uri; + + delete dwnAlice['delegateDid']; + delete dwnBob['delegateDid']; + + // give the protocol a random URI on each run + protocolUri = `http://example.com/protocol/${TestDataGenerator.randomString(10)}`; + protocolDefinition = { + ...emailProtocolDefinition, + protocol: protocolUri + }; }); after(async () => { @@ -65,7 +88,7 @@ describe('DwnApi', () => { it('writes a protocol definition', async () => { const response = await dwnAlice.protocols.configure({ message: { - definition: emailProtocolDefinition + definition: protocolDefinition } }); @@ -81,7 +104,7 @@ describe('DwnApi', () => { // Write a protocols configure to the connected agent's DWN. const configureResponse = await dwnAlice.protocols.configure({ message: { - definition: emailProtocolDefinition + definition: protocolDefinition } }); expect(configureResponse.status.code).to.equal(202); @@ -91,7 +114,7 @@ describe('DwnApi', () => { const queryResponse = await dwnAlice.protocols.query({ message: { filter: { - protocol: emailProtocolDefinition.protocol + protocol: protocolDefinition.protocol } } }); @@ -100,7 +123,7 @@ describe('DwnApi', () => { expect(queryResponse.protocols.length).to.equal(1); expect(queryResponse.protocols[0].definition).to.have.property('types'); expect(queryResponse.protocols[0].definition).to.have.property('protocol'); - expect(queryResponse.protocols[0].definition.protocol).to.equal(emailProtocolDefinition.protocol); + expect(queryResponse.protocols[0].definition.protocol).to.equal(protocolDefinition.protocol); expect(queryResponse.protocols[0].definition).to.have.property('structure'); }); }); @@ -110,7 +133,7 @@ describe('DwnApi', () => { // Write a protocols configure to the connected agent's DWN. const configureResponse = await dwnAlice.protocols.configure({ message: { - definition: emailProtocolDefinition + definition: protocolDefinition } }); expect(configureResponse.status.code).to.equal(202); @@ -124,7 +147,7 @@ describe('DwnApi', () => { from : aliceDid.uri, message : { filter: { - protocol: emailProtocolDefinition.protocol + protocol: protocolDefinition.protocol } } }); @@ -133,7 +156,7 @@ describe('DwnApi', () => { expect(queryResponse.protocols.length).to.equal(1); expect(queryResponse.protocols[0].definition).to.have.property('types'); expect(queryResponse.protocols[0].definition).to.have.property('protocol'); - expect(queryResponse.protocols[0].definition.protocol).to.equal(emailProtocolDefinition.protocol); + expect(queryResponse.protocols[0].definition.protocol).to.equal(protocolDefinition.protocol); expect(queryResponse.protocols[0].definition).to.have.property('structure'); }); @@ -157,7 +180,7 @@ describe('DwnApi', () => { // Configure a published protocol on Alice's local DWN. const publicProtocol = await dwnAlice.protocols.configure({ message: { - definition: { ...emailProtocolDefinition, protocol: 'http://proto-published', published: true } + definition: { ...protocolDefinition, protocol: 'http://proto-published', published: true } } }); expect(publicProtocol.status.code).to.equal(202); @@ -186,7 +209,7 @@ describe('DwnApi', () => { // Configure an unpublished protocol on Alice's DWN. const notPublicProtocol = await dwnAlice.protocols.configure({ message: { - definition: { ...emailProtocolDefinition, protocol: 'http://proto-not-published', published: false } + definition: { ...protocolDefinition, protocol: 'http://proto-not-published', published: false } } }); expect(notPublicProtocol.status.code).to.equal(202); @@ -231,14 +254,29 @@ describe('DwnApi', () => { }); describe('records.create()', () => { + beforeEach(async() => { + // Configure the protocol on both DWNs + const { status: aliceProtocolStatus, protocol: aliceProtocol } = await dwnAlice.protocols.configure({ message: { definition: protocolDefinition } }); + expect(aliceProtocolStatus.code).to.equal(202); + expect(aliceProtocol).to.exist; + const { status: aliceProtocolSendStatus } = await aliceProtocol.send(aliceDid.uri); + expect(aliceProtocolSendStatus.code).to.equal(202); + const { status: bobProtocolStatus, protocol: bobProtocol } = await dwnBob.protocols.configure({ message: { definition: protocolDefinition } }); + expect(bobProtocolStatus.code).to.equal(202); + expect(bobProtocol).to.exist; + const { status: bobProtocolSendStatus } = await bobProtocol!.send(bobDid.uri); + expect(bobProtocolSendStatus.code).to.equal(202); + }); + describe('agent', () => { it('creates a record with string data', async () => { const dataString = 'Hello, world!Hello, world!'; const result = await dwnAlice.records.create({ data : dataString, message : { - schema : 'foo/bar', - dataFormat : 'text/plain' + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, } }); @@ -252,9 +290,10 @@ describe('DwnApi', () => { const result = await dwnAlice.records.create({ data : 'some data', message : { - schema : 'foo/bar', - dataFormat : 'text/plain', - tags : { + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + tags : { foo : 'bar', count : 2, bool : true @@ -279,11 +318,12 @@ describe('DwnApi', () => { const result = await dwnAlice.records.create({ data : dataJson, message : { - schema : 'foo/bar', - dataFormat : 'application/json' + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'application/json' } }); - expect(result.status.code).to.equal(202); expect(result.status.detail).to.equal('Accepted'); expect(result.record).to.exist; @@ -767,7 +807,7 @@ describe('DwnApi', () => { */ const { status: bobProtocolStatus, protocol: bobProtocol } = await dwnBob.protocols.configure({ message: { - definition: emailProtocolDefinition + definition: protocolDefinition, } }); expect(bobProtocolStatus.code).to.equal(202); @@ -783,7 +823,7 @@ describe('DwnApi', () => { store : false, data : 'test', message : { - protocol : 'http://email-protocol.xyz', + protocol : protocolUri, protocolPath : 'thread', schema : 'http://email-protocol.xyz/schema/thread', dataFormat : 'text/plain' @@ -811,16 +851,31 @@ describe('DwnApi', () => { }); describe('records.query()', () => { + beforeEach(async() => { + // Configure the protocol on both DWNs + const { status: aliceProtocolStatus, protocol: aliceProtocol } = await dwnAlice.protocols.configure({ message: { definition: protocolDefinition } }); + expect(aliceProtocolStatus.code).to.equal(202); + expect(aliceProtocol).to.exist; + const { status: aliceProtocolSendStatus } = await aliceProtocol.send(aliceDid.uri); + expect(aliceProtocolSendStatus.code).to.equal(202); + const { status: bobProtocolStatus, protocol: bobProtocol } = await dwnBob.protocols.configure({ message: { definition: protocolDefinition } }); + expect(bobProtocolStatus.code).to.equal(202); + expect(bobProtocol).to.exist; + const { status: bobProtocolSendStatus } = await bobProtocol!.send(bobDid.uri); + expect(bobProtocolSendStatus.code).to.equal(202); + }); + describe('agent', () => { it('returns an array of records that match the filter provided', async () => { const writeResult = await dwnAlice.records.write({ data : 'Hello, world!', message : { - schema : 'foo/bar', - dataFormat : 'text/plain' + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain' } }); - expect(writeResult.status.code).to.equal(202); expect(writeResult.status.detail).to.equal('Accepted'); expect(writeResult.record).to.exist; @@ -828,7 +883,10 @@ describe('DwnApi', () => { const result = await dwnAlice.records.query({ message: { filter: { - schema: 'foo/bar' + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain' } } }); @@ -844,8 +902,10 @@ describe('DwnApi', () => { const writeResult = await dwnAlice.records.write({ data : `Hello, world ${i + 1}!`, message : { - schema : 'foo/bar', - dataFormat : 'text/plain' + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain' } }); @@ -857,7 +917,10 @@ describe('DwnApi', () => { const results = await dwnAlice.records.query({ message: { filter: { - schema: 'foo/bar' + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain' }, pagination: { limit: 2 } // set a limit of 2 } @@ -871,7 +934,10 @@ describe('DwnApi', () => { const additionalResults = await dwnAlice.records.query({ message: { filter: { - schema: 'foo/bar' + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain' }, pagination: { limit: 2, cursor: results.cursor} } @@ -891,9 +957,11 @@ describe('DwnApi', () => { const writeResult = await dwnAlice.records.write({ data : `Hello, world ${i + 1}!`, message : { - published : i % 2 == 0 ? true : false, - schema : 'foo/bar', - dataFormat : 'text/plain' + published : i % 2 == 0 ? true : false, + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain' } }); @@ -914,7 +982,10 @@ describe('DwnApi', () => { const createdAscResults = await dwnAlice.records.query({ message: { filter: { - schema: 'foo/bar' + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain' }, dateSort: DwnDateSort.CreatedAscending // same as default } @@ -928,7 +999,10 @@ describe('DwnApi', () => { const createdDescResults = await dwnAlice.records.query({ message: { filter: { - schema: 'foo/bar' + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain' }, dateSort: DwnDateSort.CreatedDescending } @@ -942,7 +1016,10 @@ describe('DwnApi', () => { const publishedAscResults = await dwnAlice.records.query({ message: { filter: { - schema: 'foo/bar' + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain' }, dateSort: DwnDateSort.PublishedAscending } @@ -956,7 +1033,10 @@ describe('DwnApi', () => { const publishedDescResults = await dwnAlice.records.query({ message: { filter: { - schema: 'foo/bar' + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain' }, dateSort: DwnDateSort.PublishedDescending } @@ -973,9 +1053,11 @@ describe('DwnApi', () => { const { status, record } = await dwnAlice.records.write({ data : 'Hello, world!', message : { - schema : 'foo/bar', - dataFormat : 'text/plain', - tags : { + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain', + tags : { foo: 'bar', } } @@ -986,9 +1068,11 @@ describe('DwnApi', () => { const { status: status2 } = await dwnAlice.records.write({ data : 'Hello, world!', message : { - schema : 'foo/bar', - dataFormat : 'text/plain', - tags : { + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain', + tags : { foo: 'baz', } } @@ -999,7 +1083,10 @@ describe('DwnApi', () => { const result = await dwnAlice.records.query({ message: { filter: { - schema: 'foo/bar' + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain' } } }); @@ -1014,8 +1101,11 @@ describe('DwnApi', () => { const fooBarResult = await dwnAlice.records.query({ message: { filter: { - schema : 'foo/bar', - tags : { + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain', + tags : { foo: 'bar', } } @@ -1037,8 +1127,10 @@ describe('DwnApi', () => { const { record } = await dwnAlice.records.write({ data : 'Hello, world!', message : { - schema : 'foo/bar', - dataFormat : 'text/plain' + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain' } }); @@ -1050,7 +1142,10 @@ describe('DwnApi', () => { from : aliceDid.uri, message : { filter: { - schema: 'foo/bar' + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain' } } }); @@ -1090,7 +1185,7 @@ describe('DwnApi', () => { */ const { status: bobProtocolStatus, protocol: bobProtocol } = await dwnBob.protocols.configure({ message: { - definition: emailProtocolDefinition + definition: protocolDefinition } }); expect(bobProtocolStatus.code).to.equal(202); @@ -1106,9 +1201,9 @@ describe('DwnApi', () => { store : false, data : 'test', message : { - protocol : 'http://email-protocol.xyz', + protocol : protocolUri, protocolPath : 'thread', - schema : 'http://email-protocol.xyz/schema/thread', + schema : protocolDefinition.types.thread.schema, dataFormat : 'text/plain' } }); @@ -1143,9 +1238,11 @@ describe('DwnApi', () => { store : false, data : 'Hello, world!', message : { - schema : 'foo/bar', - dataFormat : 'text/plain', - tags : { + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain', + tags : { foo: 'bar', } } @@ -1159,9 +1256,11 @@ describe('DwnApi', () => { store : false, data : 'Hello, world!', message : { - schema : 'foo/bar', - dataFormat : 'text/plain', - tags : { + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain', + tags : { foo: 'baz', } } @@ -1175,7 +1274,10 @@ describe('DwnApi', () => { from : aliceDid.uri, message : { filter: { - schema: 'foo/bar' + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain' } } }); @@ -1191,8 +1293,11 @@ describe('DwnApi', () => { from : aliceDid.uri, message : { filter: { - schema : 'foo/bar', - tags : { + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain', + tags : { foo: 'bar', } } @@ -1210,13 +1315,29 @@ describe('DwnApi', () => { }); describe('records.read()', () => { + beforeEach(async() => { + // Configure the protocol on both DWNs + const { status: aliceProtocolStatus, protocol: aliceProtocol } = await dwnAlice.protocols.configure({ message: { definition: protocolDefinition } }); + expect(aliceProtocolStatus.code).to.equal(202); + expect(aliceProtocol).to.exist; + const { status: aliceProtocolSendStatus } = await aliceProtocol.send(aliceDid.uri); + expect(aliceProtocolSendStatus.code).to.equal(202); + const { status: bobProtocolStatus, protocol: bobProtocol } = await dwnBob.protocols.configure({ message: { definition: protocolDefinition } }); + expect(bobProtocolStatus.code).to.equal(202); + expect(bobProtocol).to.exist; + const { status: bobProtocolSendStatus } = await bobProtocol!.send(bobDid.uri); + expect(bobProtocolSendStatus.code).to.equal(202); + }); + describe('agent', () => { it('returns a record', async () => { const writeResult = await dwnAlice.records.write({ data : 'Hello, world!', message : { - schema : 'foo/bar', - dataFormat : 'text/plain' + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain' } }); @@ -1240,8 +1361,10 @@ describe('DwnApi', () => { const writeResult = await dwnAlice.records.write({ data : 'Hello, world!', message : { - schema : 'foo/bar', - dataFormat : 'text/plain' + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain' } }); @@ -1272,8 +1395,10 @@ describe('DwnApi', () => { const writeResult = await dwnAlice.records.write({ data : 'Hello, world!', message : { - schema : 'foo/bar', - dataFormat : 'text/plain' + protocol : protocolUri, + protocolPath : 'thread', + schema : protocolDefinition.types.thread.schema, + dataFormat : 'text/plain' } }); @@ -1326,7 +1451,7 @@ describe('DwnApi', () => { */ const { status: bobProtocolStatus, protocol: bobProtocol } = await dwnBob.protocols.configure({ message: { - definition: emailProtocolDefinition + definition: protocolDefinition, } }); expect(bobProtocolStatus.code).to.equal(202); @@ -1342,9 +1467,9 @@ describe('DwnApi', () => { store : false, data : 'test', message : { - protocol : 'http://email-protocol.xyz', + protocol : protocolUri, protocolPath : 'thread', - schema : 'http://email-protocol.xyz/schema/thread', + schema : protocolDefinition.types.thread.schema, dataFormat : 'text/plain' } }); @@ -1543,6 +1668,10 @@ describe('DwnApi', () => { }); describe('connected.findPermissionGrantForRequest', () => { + afterEach(() => { + + }); + it('caches result', async () => { // create a grant for bob const deviceXGrant = await dwnAlice.permissions.grant({ @@ -1560,6 +1689,7 @@ describe('DwnApi', () => { // simulate a connect where bobDid can impersonate aliceDid dwnBob['connectedDid'] = aliceDid.uri; dwnBob['delegateDid'] = bobDid.uri; + await Web5.processConnectedGrants({ agent : testHarness.agent, delegateDid : bobDid.uri, @@ -2275,11 +2405,11 @@ describe('DwnApi', () => { const grantFromAlice = await PermissionGrant.parse({ agent : testHarness.agent, - connectedDid : bobDid.uri, + connectedDid : bobDid.uri, // bob is the connectedDid message : messageGrantFromAlice }); - // import the grant + // bob imports the grant const importFromAlice = await grantFromAlice.import(true); expect(importFromAlice.status.code).to.equal(202); @@ -2298,7 +2428,7 @@ describe('DwnApi', () => { const grantFromCarol = await PermissionGrant.parse({ agent : testHarness.agent, - connectedDid : bobDid.uri, + connectedDid : bobDid.uri, // bob is the connectedDid message : messageGrantFromCarol }); @@ -2309,14 +2439,14 @@ describe('DwnApi', () => { const fetchedGrantsAlice = await dwnBob.permissions.queryGrants({ grantor: aliceDid.uri }); - expect(fetchedGrantsAlice.length).to.equal(1); + expect(fetchedGrantsAlice.length).to.equal(1, 'alice grantor'); expect(fetchedGrantsAlice[0].id).to.equal(grantFromAlice.id); // query for the grants with carol as the grantor const fetchedGrantsCarol = await dwnBob.permissions.queryGrants({ grantor: carolDid.uri }); - expect(fetchedGrantsCarol.length).to.equal(1); + expect(fetchedGrantsCarol.length).to.equal(1, 'carol grantor'); expect(fetchedGrantsCarol[0].id).to.equal(grantFromCarol.id); }); diff --git a/packages/api/tests/fixtures/protocol-definitions/email.json b/packages/api/tests/fixtures/protocol-definitions/email.json index 12885130b..ad8b4ddb2 100644 --- a/packages/api/tests/fixtures/protocol-definitions/email.json +++ b/packages/api/tests/fixtures/protocol-definitions/email.json @@ -5,7 +5,8 @@ "thread": { "schema": "http://email-protocol.xyz/schema/thread", "dataFormats": [ - "text/plain" + "text/plain", + "application/json" ] }, "email": { diff --git a/packages/api/tests/permission-grant.spec.ts b/packages/api/tests/permission-grant.spec.ts index 77c131923..0ee7de3d1 100644 --- a/packages/api/tests/permission-grant.spec.ts +++ b/packages/api/tests/permission-grant.spec.ts @@ -9,7 +9,7 @@ import { testDwnUrl } from './utils/test-config.js'; // Remove when we move off of node.js v18 to v20, earliest possible time would be Oct 2023: https://github.com/nodejs/release#release-schedule import { webcrypto } from 'node:crypto'; import { PlatformAgentTestHarness } from '@web5/agent'; -import { DwnInterfaceName, DwnMethodName, Time } from '@tbd54566975/dwn-sdk-js'; +import { DwnInterfaceName, DwnMethodName, TestDataGenerator, Time } from '@tbd54566975/dwn-sdk-js'; import { PermissionGrant } from '../src/permission-grant.js'; import { DwnApi } from '../src/dwn-api.js'; // @ts-ignore @@ -23,6 +23,7 @@ describe('PermissionGrant', () => { let aliceDwn: DwnApi; let bobDwn: DwnApi; let testHarness: PlatformAgentTestHarness; + let protocolUri: string; before(async () => { testHarness = await PlatformAgentTestHarness.setup({ @@ -30,9 +31,6 @@ describe('PermissionGrant', () => { agentStores : 'memory' }); - }); - - beforeEach(async () => { sinon.restore(); await testHarness.clearStorage(); await testHarness.createAgentDid(); @@ -51,6 +49,20 @@ describe('PermissionGrant', () => { bobDwn = new DwnApi({ agent: testHarness.agent, connectedDid: bobDid.uri }); }); + beforeEach(async () => { + sinon.restore(); + await testHarness.syncStore.clear(); + await testHarness.dwnDataStore.clear(); + await testHarness.dwnEventLog.clear(); + await testHarness.dwnMessageStore.clear(); + await testHarness.dwnResumableTaskStore.clear(); + testHarness.dwnStores.clear(); + + // create a random protocol URI for each run + protocolUri = `http://example.com/protocol/${TestDataGenerator.randomString(10)}`; + }); + + after(async () => { sinon.restore(); await testHarness.clearStorage(); @@ -66,7 +78,7 @@ describe('PermissionGrant', () => { requestId : '123', dateExpires : Time.createOffsetTimestamp({ seconds: 60 }), description : 'This is a grant', - scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read } + scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read, protocol: protocolUri }, }); const parsedGrant = await PermissionGrant.parse({ @@ -100,12 +112,13 @@ describe('PermissionGrant', () => { store : false, grantedTo : bobDid.uri, dateExpires : Time.createOffsetTimestamp({ seconds: 60 }), - scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read } + scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read, protocol: protocolUri }, }); // query the remote for the grant let fetchedRemote = await aliceDwn.permissions.queryGrants({ - from: aliceDid.uri, + from : aliceDid.uri, + protocol : protocolUri, }); expect(fetchedRemote.length).to.equal(0); @@ -115,7 +128,8 @@ describe('PermissionGrant', () => { // query the remote for the grant, should now exist fetchedRemote = await aliceDwn.permissions.queryGrants({ - from: aliceDid.uri, + from : aliceDid.uri, + protocol : protocolUri, }); expect(fetchedRemote.length).to.equal(1); }); @@ -126,7 +140,7 @@ describe('PermissionGrant', () => { store : false, grantedTo : bobDid.uri, dateExpires : Time.createOffsetTimestamp({ seconds: 60 }), - scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read } + scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read, protocol: protocolUri }, }); // alice sends it to her own DWN const aliceSent = await grant.send(); @@ -134,13 +148,15 @@ describe('PermissionGrant', () => { // bob queries alice's remote for a grant const fetchedFromAlice = await bobDwn.permissions.queryGrants({ - from: aliceDid.uri, + from : aliceDid.uri, + protocol : protocolUri, }); expect(fetchedFromAlice.length).to.equal(1); // fetch from bob's remote. should have no grants let fetchedRemote = await bobDwn.permissions.queryGrants({ - from: bobDid.uri, + from : bobDid.uri, + protocol : protocolUri, }); expect(fetchedRemote.length).to.equal(0); @@ -157,7 +173,8 @@ describe('PermissionGrant', () => { // // send the gran // the grant should now exist in bob's remote fetchedRemote = await bobDwn.permissions.queryGrants({ - from: bobDid.uri, + from : bobDid.uri, + protocol : protocolUri, }); expect(fetchedRemote.length).to.equal(1); expect(fetchedRemote[0].toJSON()).to.deep.equal(grant.toJSON()); @@ -171,11 +188,13 @@ describe('PermissionGrant', () => { store : false, grantedTo : bobDid.uri, dateExpires : Time.createOffsetTimestamp({ seconds: 60 }), - scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read } + scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read, protocol: protocolUri }, }); // validate the grant does not exist in the DWN - let fetchedGrants = await aliceDwn.permissions.queryGrants(); + let fetchedGrants = await aliceDwn.permissions.queryGrants({ + protocol: protocolUri, + }); expect(fetchedGrants.length).to.equal(0); // store the grant @@ -183,7 +202,9 @@ describe('PermissionGrant', () => { expect(stored.status.code).to.equal(202); // validate the grant now exists in the DWN - fetchedGrants = await aliceDwn.permissions.queryGrants(); + fetchedGrants = await aliceDwn.permissions.queryGrants({ + protocol: protocolUri, + }); expect(fetchedGrants.length).to.equal(1); expect(fetchedGrants[0].toJSON()).to.deep.equal(grant.toJSON()); }); @@ -194,14 +215,15 @@ describe('PermissionGrant', () => { store : false, grantedTo : bobDid.uri, dateExpires : Time.createOffsetTimestamp({ seconds: 60 }), - scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read } + scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read, protocol: protocolUri }, }); const sent = await grant.send(); expect(sent.status.code).to.equal(202); // bob queries alice's remote for a grant let fetchedFromAlice = await bobDwn.permissions.queryGrants({ - from: aliceDid.uri, + from : aliceDid.uri, + protocol : protocolUri, }); expect(fetchedFromAlice.length).to.equal(1); @@ -211,7 +233,9 @@ describe('PermissionGrant', () => { expect(stored.status.code).to.equal(401); // attempt to fetch from local to ensure it was not imported - let fetchedLocal = await bobDwn.permissions.queryGrants(); + let fetchedLocal = await bobDwn.permissions.queryGrants({ + protocol: protocolUri, + }); expect(fetchedLocal.length).to.equal(0); // store the grant and import it @@ -219,7 +243,9 @@ describe('PermissionGrant', () => { expect(stored.status.code).to.equal(202); // fetch from local to ensure it was imported - fetchedLocal = await bobDwn.permissions.queryGrants(); + fetchedLocal = await bobDwn.permissions.queryGrants({ + protocol: protocolUri, + }); expect(fetchedLocal.length).to.equal(1); expect(fetchedLocal[0].toJSON()).to.deep.equal(fetchedGrant.toJSON()); }); @@ -232,21 +258,23 @@ describe('PermissionGrant', () => { store : false, grantedTo : bobDid.uri, dateExpires : Time.createOffsetTimestamp({ seconds: 60 }), - scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read } + scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read, protocol: protocolUri }, }); const sent = await grant.send(); expect(sent.status.code).to.equal(202); // bob queries alice's remote for a grant let fetchedFromAlice = await bobDwn.permissions.queryGrants({ - from: aliceDid.uri, + from : aliceDid.uri, + protocol : protocolUri, }); expect(fetchedFromAlice.length).to.equal(1); const fetchedGrant = fetchedFromAlice[0]; // confirm the grant does not yet exist in bob's remote let fetchedRemote = await bobDwn.permissions.queryGrants({ - from: bobDid.uri, + from : bobDid.uri, + protocol : protocolUri, }); expect(fetchedRemote.length).to.equal(0); @@ -259,7 +287,9 @@ describe('PermissionGrant', () => { expect(imported.status.code).to.equal(202); // fetch from local to ensure it was not stored - const fetchedLocal = await bobDwn.permissions.queryGrants(); + const fetchedLocal = await bobDwn.permissions.queryGrants({ + protocol: protocolUri, + }); expect(fetchedLocal.length).to.equal(0); // send the grant to bob's remote @@ -268,7 +298,8 @@ describe('PermissionGrant', () => { // fetch from bob's remote to ensure it was imported fetchedRemote = await bobDwn.permissions.queryGrants({ - from: bobDid.uri, + from : bobDid.uri, + protocol : protocolUri, }); expect(fetchedRemote.length).to.equal(1); expect(fetchedRemote[0].toJSON()).to.deep.equal(fetchedGrant.toJSON()); @@ -280,21 +311,23 @@ describe('PermissionGrant', () => { store : false, grantedTo : bobDid.uri, dateExpires : Time.createOffsetTimestamp({ seconds: 60 }), - scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read } + scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read, protocol: protocolUri }, }); const sent = await grant.send(); expect(sent.status.code).to.equal(202); // bob queries alice's remote for a grant let fetchedFromAlice = await bobDwn.permissions.queryGrants({ - from: aliceDid.uri, + from : aliceDid.uri, + protocol : protocolUri, }); expect(fetchedFromAlice.length).to.equal(1); const fetchedGrant = fetchedFromAlice[0]; // confirm the grant does not yet exist in bob's remote let fetchedRemote = await bobDwn.permissions.queryGrants({ - from: bobDid.uri, + from : bobDid.uri, + protocol : protocolUri, }); expect(fetchedRemote.length).to.equal(0); @@ -303,7 +336,9 @@ describe('PermissionGrant', () => { expect(imported.status.code).to.equal(202); // fetch from local to ensure it was stored - const fetchedLocal = await bobDwn.permissions.queryGrants(); + const fetchedLocal = await bobDwn.permissions.queryGrants({ + protocol: protocolUri, + }); expect(fetchedLocal.length).to.equal(1); expect(fetchedLocal[0].toJSON()).to.deep.equal(fetchedGrant.toJSON()); }); @@ -316,7 +351,7 @@ describe('PermissionGrant', () => { author : aliceDid.uri, grantedTo : bobDid.uri, dateExpires : Time.createOffsetTimestamp({ seconds: 60 }), - scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read } + scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read, protocol: protocolUri }, }); const parsedGrant = await PermissionGrant.parse({ @@ -336,7 +371,7 @@ describe('PermissionGrant', () => { store : true, grantedTo : bobDid.uri, dateExpires : Time.createOffsetTimestamp({ seconds: 60 }), - scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read } + scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read, protocol: protocolUri }, }); let isRevoked = await grant.isRevoked(); @@ -356,7 +391,7 @@ describe('PermissionGrant', () => { store : true, grantedTo : bobDid.uri, dateExpires : Time.createOffsetTimestamp({ seconds: 60 }), - scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read } + scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read, protocol: protocolUri }, }); let isRevoked = await grant.isRevoked(); @@ -384,7 +419,7 @@ describe('PermissionGrant', () => { store : true, grantedTo : bobDid.uri, dateExpires : Time.createOffsetTimestamp({ seconds: 60 }), - scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read } + scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read, protocol: protocolUri }, }); // send the grant to alice's remote @@ -413,7 +448,7 @@ describe('PermissionGrant', () => { store : true, grantedTo : bobDid.uri, dateExpires : Time.createOffsetTimestamp({ seconds: 60 }), - scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read } + scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read, protocol: protocolUri }, }); let isRevoked = await grant.isRevoked(); @@ -433,7 +468,7 @@ describe('PermissionGrant', () => { store : true, grantedTo : bobDid.uri, dateExpires : Time.createOffsetTimestamp({ seconds: 60 }), - scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read } + scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read, protocol: protocolUri }, }); // send the grant to alice's remote diff --git a/packages/api/tests/permission-request.spec.ts b/packages/api/tests/permission-request.spec.ts index e98d0c487..a15289845 100644 --- a/packages/api/tests/permission-request.spec.ts +++ b/packages/api/tests/permission-request.spec.ts @@ -9,6 +9,7 @@ import { PlatformAgentTestHarness } from '@web5/agent'; import { Web5UserAgent } from '@web5/user-agent'; import { DwnInterfaceName, DwnMethodName, Time } from '@tbd54566975/dwn-sdk-js'; import { PermissionRequest } from '../src/permission-request.js'; +import { TestDataGenerator } from './utils/test-data-generator.js'; const testDwnUrls = [testDwnUrl]; @@ -18,6 +19,7 @@ describe('PermissionRequest', () => { let aliceDwn: DwnApi; let bobDwn: DwnApi; let testHarness: PlatformAgentTestHarness; + let protocolUri: string; before(async () => { testHarness = await PlatformAgentTestHarness.setup({ @@ -25,9 +27,6 @@ describe('PermissionRequest', () => { agentStores : 'memory' }); - }); - - beforeEach(async () => { sinon.restore(); await testHarness.clearStorage(); await testHarness.createAgentDid(); @@ -46,6 +45,20 @@ describe('PermissionRequest', () => { bobDwn = new DwnApi({ agent: testHarness.agent, connectedDid: bobDid.uri }); }); + beforeEach(async () => { + sinon.restore(); + await testHarness.syncStore.clear(); + await testHarness.dwnDataStore.clear(); + await testHarness.dwnEventLog.clear(); + await testHarness.dwnMessageStore.clear(); + await testHarness.dwnResumableTaskStore.clear(); + testHarness.dwnStores.clear(); + + // create a random protocol URI for each run + protocolUri = `http://example.com/protocol/${TestDataGenerator.randomString(10)}`; + }); + + after(async () => { sinon.restore(); await testHarness.clearStorage(); @@ -58,7 +71,8 @@ describe('PermissionRequest', () => { author : aliceDid.uri, scope : { interface : DwnInterfaceName.Messages, - method : DwnMethodName.Read + method : DwnMethodName.Read, + protocol : protocolUri } }); @@ -88,13 +102,15 @@ describe('PermissionRequest', () => { store : false, scope : { interface : DwnInterfaceName.Messages, - method : DwnMethodName.Read + method : DwnMethodName.Read, + protocol : protocolUri } }); // confirm the request is not present on the remote let requests = await aliceDwn.permissions.queryRequests({ - from: aliceDid.uri + from : aliceDid.uri, + protocol : protocolUri }); expect(requests).to.have.length(0); @@ -103,7 +119,8 @@ describe('PermissionRequest', () => { // fetch the requests from the remote requests = await aliceDwn.permissions.queryRequests({ - from: aliceDid.uri + from : aliceDid.uri, + protocol : protocolUri }); expect(requests).to.have.length(1); @@ -115,13 +132,15 @@ describe('PermissionRequest', () => { store : false, scope : { interface : DwnInterfaceName.Messages, - method : DwnMethodName.Read + method : DwnMethodName.Read, + protocol : protocolUri } }); // confirm the request is not present on the remote let remoteRequestsBob = await bobDwn.permissions.queryRequests({ - from: bobDid.uri + from : bobDid.uri, + protocol : protocolUri }); expect(remoteRequestsBob).to.have.length(0); @@ -131,7 +150,8 @@ describe('PermissionRequest', () => { // fetch the requests from the remote remoteRequestsBob = await bobDwn.permissions.queryRequests({ - from: bobDid.uri + from : bobDid.uri, + protocol : protocolUri }); expect(remoteRequestsBob).to.have.length(1); expect(remoteRequestsBob[0].id).to.deep.equal(grantRequest.id); @@ -143,12 +163,13 @@ describe('PermissionRequest', () => { // create a grant not marked as stored const request = await aliceDwn.permissions.request({ store : false, - scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read } + scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read, protocol: protocolUri } }); // validate the grant does not exist in the DWN let fetchedRequests = await bobDwn.permissions.queryRequests({ - from: bobDid.uri, + from : bobDid.uri, + protocol : protocolUri }); expect(fetchedRequests.length).to.equal(0); @@ -157,11 +178,14 @@ describe('PermissionRequest', () => { // Bob fetches requests fetchedRequests = await bobDwn.permissions.queryRequests({ - from: bobDid.uri, + from : bobDid.uri, + protocol : protocolUri }); expect(fetchedRequests.length).to.equal(1); - let localRequests = await bobDwn.permissions.queryRequests(); + let localRequests = await bobDwn.permissions.queryRequests({ + protocol: protocolUri + }); expect(localRequests.length).to.equal(0); const remoteGrant = fetchedRequests[0]; @@ -171,7 +195,9 @@ describe('PermissionRequest', () => { expect(stored.status.code).to.equal(202); // validate the grant now exists in the DWN - localRequests = await bobDwn.permissions.queryRequests(); + localRequests = await bobDwn.permissions.queryRequests({ + protocol: protocolUri + }); expect(localRequests.length).to.equal(1); expect(localRequests[0].toJSON()).to.deep.equal(request.toJSON()); }); @@ -181,7 +207,7 @@ describe('PermissionRequest', () => { it('should create a grant and store it by default', async () => { const requestFromBob = await bobDwn.permissions.request({ store : false, - scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read } + scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read, protocol: protocolUri } }); const sentToAlice = await requestFromBob.send(aliceDid.uri); @@ -189,12 +215,15 @@ describe('PermissionRequest', () => { // Alice fetches requests let requests = await aliceDwn.permissions.queryRequests({ - from: aliceDid.uri + from : aliceDid.uri, + protocol : protocolUri }); expect(requests.length).to.equal(1); // confirm no grants exist - let grants = await aliceDwn.permissions.queryGrants(); + let grants = await aliceDwn.permissions.queryGrants({ + protocol: protocolUri + }); expect(grants.length).to.equal(0); // Alice grants the request and it will be stored by default @@ -203,7 +232,9 @@ describe('PermissionRequest', () => { expect(grant).to.exist; // confirm the grant exists - grants = await aliceDwn.permissions.queryGrants(); + grants = await aliceDwn.permissions.queryGrants({ + protocol: protocolUri + }); expect(grants.length).to.equal(1); expect(grants[0].id).to.equal(grant.id); }); @@ -211,7 +242,7 @@ describe('PermissionRequest', () => { it('does not store the grant if store is false', async () => { const requestFromBob = await bobDwn.permissions.request({ store : false, - scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read } + scope : { interface: DwnInterfaceName.Messages, method: DwnMethodName.Read, protocol: protocolUri } }); const sentToAlice = await requestFromBob.send(aliceDid.uri); @@ -219,12 +250,15 @@ describe('PermissionRequest', () => { // Alice fetches requests let requests = await aliceDwn.permissions.queryRequests({ - from: aliceDid.uri + from : aliceDid.uri, + protocol : protocolUri }); expect(requests.length).to.equal(1); // confirm no grants exist - let grants = await aliceDwn.permissions.queryGrants(); + let grants = await aliceDwn.permissions.queryGrants({ + protocol: protocolUri + }); expect(grants.length).to.equal(0); // Alice grants the request but does not store it @@ -233,7 +267,9 @@ describe('PermissionRequest', () => { expect(grant).to.exist; // confirm the grant does not exist - grants = await aliceDwn.permissions.queryGrants(); + grants = await aliceDwn.permissions.queryGrants({ + protocol: protocolUri + }); expect(grants.length).to.equal(0); }); }); @@ -244,7 +280,8 @@ describe('PermissionRequest', () => { author : aliceDid.uri, scope : { interface : DwnInterfaceName.Messages, - method : DwnMethodName.Read + method : DwnMethodName.Read, + protocol : protocolUri } }); diff --git a/packages/api/tests/protocol.spec.ts b/packages/api/tests/protocol.spec.ts index b990e0373..7eba23c0e 100644 --- a/packages/api/tests/protocol.spec.ts +++ b/packages/api/tests/protocol.spec.ts @@ -11,6 +11,7 @@ import emailProtocolDefinition from './fixtures/protocol-definitions/email.json' // NOTE: @noble/secp256k1 requires globalThis.crypto polyfill for node.js <=18: https://github.com/paulmillr/noble-secp256k1/blob/main/README.md#usage // Remove when we move off of node.js v18 to v20, earliest possible time would be Oct 2023: https://github.com/nodejs/release#release-schedule import { webcrypto } from 'node:crypto'; +import { TestDataGenerator } from './utils/test-data-generator.js'; // @ts-ignore if (!globalThis.crypto) globalThis.crypto = webcrypto; @@ -27,9 +28,7 @@ describe('Protocol', () => { agentClass : Web5UserAgent, agentStores : 'memory' }); - }); - beforeEach(async () => { await testHarness.clearStorage(); await testHarness.createAgentDid(); @@ -42,6 +41,15 @@ describe('Protocol', () => { dwnAlice = new DwnApi({ agent: testHarness.agent, connectedDid: aliceDid.uri }); }); + beforeEach(async () => { + await testHarness.syncStore.clear(); + await testHarness.dwnDataStore.clear(); + await testHarness.dwnEventLog.clear(); + await testHarness.dwnMessageStore.clear(); + await testHarness.dwnResumableTaskStore.clear(); + testHarness.dwnStores.clear(); + }); + after(async () => { await testHarness.clearStorage(); await testHarness.closeStorage(); @@ -50,14 +58,21 @@ describe('Protocol', () => { describe('send()', () => { it('configures protocols on remote DWNs for your own DID', async () => { // Alice configures a protocol on her agent connected DWN. + const protocolUri = `http://example.com/protocol/${TestDataGenerator.randomString(10)}`; const { status: aliceEmailStatus, protocol: aliceEmailProtocol } = await dwnAlice.protocols.configure({ message: { - definition: emailProtocolDefinition + definition: { + ...emailProtocolDefinition, + protocol: protocolUri + } } }); expect(aliceEmailStatus.code).to.equal(202); - expect(aliceEmailProtocol.definition).to.deep.equal(emailProtocolDefinition); + expect(aliceEmailProtocol.definition).to.deep.equal({ + ...emailProtocolDefinition, + protocol: protocolUri + }); // Attempt to configure the protocol on Alice's remote DWN. const { status } = await aliceEmailProtocol.send(aliceDid.uri); @@ -68,7 +83,7 @@ describe('Protocol', () => { from : aliceDid.uri, message : { filter: { - protocol: emailProtocolDefinition.protocol + protocol: protocolUri, } } }); @@ -77,7 +92,10 @@ describe('Protocol', () => { expect(aliceRemoteQueryResult.protocols).to.exist; expect(aliceRemoteQueryResult.protocols.length).to.equal(1); const [ aliceRemoteEmailProtocol ] = aliceRemoteQueryResult.protocols; - expect(aliceRemoteEmailProtocol.definition).to.deep.equal(emailProtocolDefinition); + expect(aliceRemoteEmailProtocol.definition).to.deep.equal({ + ...emailProtocolDefinition, + protocol: protocolUri + }); }); }); diff --git a/packages/api/tests/record.spec.ts b/packages/api/tests/record.spec.ts index fcdfbbaa2..39f8028d1 100644 --- a/packages/api/tests/record.spec.ts +++ b/packages/api/tests/record.spec.ts @@ -1,5 +1,5 @@ import type { BearerDid } from '@web5/dids'; -import type { DwnMessageParams, DwnPublicKeyJwk, DwnSigner } from '@web5/agent'; +import type { DwnMessageParams, DwnProtocolDefinition, DwnPublicKeyJwk, DwnSigner } from '@web5/agent'; import sinon from 'sinon'; import { expect } from 'chai'; @@ -32,6 +32,7 @@ describe('Record', () => { let dwnAlice: DwnApi; let dwnBob: DwnApi; let testHarness: PlatformAgentTestHarness; + let protocolUri: string; before(async () => { testHarness = await PlatformAgentTestHarness.setup({ @@ -41,10 +42,7 @@ describe('Record', () => { dataText = TestDataGenerator.randomString(100); ({ dataBlob, dataFormat } = dataToBlob(dataText)); - }); - beforeEach(async () => { - sinon.restore(); await testHarness.clearStorage(); await testHarness.createAgentDid(); @@ -63,6 +61,36 @@ describe('Record', () => { dwnBob = new DwnApi({ agent: testHarness.agent, connectedDid: bobDid.uri }); }); + beforeEach(async () => { + sinon.restore(); + await testHarness.syncStore.clear(); + await testHarness.dwnDataStore.clear(); + await testHarness.dwnEventLog.clear(); + await testHarness.dwnMessageStore.clear(); + await testHarness.dwnResumableTaskStore.clear(); + testHarness.dwnStores.clear(); + + + // give the protocol a random URI on each run + protocolUri = `http://example.com/protocol/${TestDataGenerator.randomString(10)}`; + const protocolDefinition = { + ...emailProtocolDefinition, + protocol: protocolUri + }; + + // Configure the protocol on both DWNs + const { status: aliceProtocolStatus, protocol: aliceProtocol } = await dwnAlice.protocols.configure({ message: { definition: protocolDefinition } }); + expect(aliceProtocolStatus.code).to.equal(202); + expect(aliceProtocol).to.exist; + const { status: aliceProtocolSendStatus } = await aliceProtocol.send(aliceDid.uri); + expect(aliceProtocolSendStatus.code).to.equal(202); + const { status: bobProtocolStatus, protocol: bobProtocol } = await dwnBob.protocols.configure({ message: { definition: protocolDefinition } }); + expect(bobProtocolStatus.code).to.equal(202); + expect(bobProtocol).to.exist; + const { status: bobProtocolSendStatus } = await bobProtocol!.send(bobDid.uri); + expect(bobProtocolSendStatus.code).to.equal(202); + }); + after(async () => { sinon.restore(); await testHarness.clearStorage(); @@ -70,40 +98,12 @@ describe('Record', () => { }); it('imports a record that another user wrote', async () => { - - // Install the thread protocol for Alice's local DWN. - let { protocol: aliceProtocol, status: aliceStatus } = await dwnAlice.protocols.configure({ - message: { - definition: emailProtocolDefinition, - } - }); - expect(aliceStatus.code).to.equal(202); - expect(aliceProtocol).to.exist; - - // Install the thread protocol for Alice's remote DWN. - const { status: alicePushStatus } = await aliceProtocol!.send(aliceDid.uri); - expect(alicePushStatus.code).to.equal(202); - - // Install the thread protocol for Bob's local DWN. - const { protocol: bobProtocol, status: bobStatus } = await dwnBob.protocols.configure({ - message: { - definition: emailProtocolDefinition - } - }); - - expect(bobStatus.code).to.equal(202); - expect(bobProtocol).to.exist; - - // Install the thread protocol for Bob's remote DWN. - const { status: bobPushStatus } = await bobProtocol!.send(bobDid.uri); - expect(bobPushStatus.code).to.equal(202); - // Alice creates a new large record and stores it on her own dwn const { status: aliceThreadStatus, record: aliceThreadRecord } = await dwnAlice.records.write({ data : TestDataGenerator.randomString(DwnConstant.maxDataSizeAllowedToBeEncoded + 1000), message : { recipient : bobDid.uri, - protocol : emailProtocolDefinition.protocol, + protocol : protocolUri, protocolPath : 'thread', schema : 'http://email-protocol.xyz/schema/thread', } @@ -117,7 +117,7 @@ describe('Record', () => { from : bobDid.uri, message : { filter: { - protocol : emailProtocolDefinition.protocol, + protocol : protocolUri, protocolPath : 'thread', } } @@ -130,7 +130,7 @@ describe('Record', () => { from : aliceDid.uri, message : { filter: { - protocol : emailProtocolDefinition.protocol, + protocol : protocolUri, protocolPath : 'thread', } } @@ -152,7 +152,7 @@ describe('Record', () => { from : bobDid.uri, message : { filter: { - protocol : emailProtocolDefinition.protocol, + protocol : protocolUri, protocolPath : 'thread', } } @@ -186,7 +186,7 @@ describe('Record', () => { from : aliceDid.uri, message : { filter: { - protocol : emailProtocolDefinition.protocol, + protocol : protocolUri, protocolPath : 'thread', } } @@ -209,7 +209,7 @@ describe('Record', () => { from : bobDid.uri, message : { filter: { - protocol : emailProtocolDefinition.protocol, + protocol : protocolUri, protocolPath : 'thread', } } @@ -259,19 +259,12 @@ describe('Record', () => { }; // RecordsWriteDescriptor properties that can be pre-defined - const protocol = emailProtocolDefinition.protocol; + const protocol = protocolUri; const protocolPath = 'thread'; const schema = emailProtocolDefinition.types.thread.schema; const recipient = aliceDid.uri; const published = true; - // Install a protocol on Alice's agent connected DWN. - await dwnAlice.protocols.configure({ - message: { - definition: emailProtocolDefinition - } - }); - const RecordsWrite = dwnMessageConstructors[DwnInterface.RecordsWrite]; // Create a parent record to reference in the RecordsWriteMessage used for validation @@ -1154,35 +1147,54 @@ describe('Record', () => { }); describe('with two Agents', () => { - let testHarnessBob: PlatformAgentTestHarness; + let dwnCarol: DwnApi; + let carolDid: BearerDid; + let testHarnessCarol: PlatformAgentTestHarness; before(async () => { - // Create a second `TestManagedAgent` that only Bob will use. - testHarnessBob = await PlatformAgentTestHarness.setup({ + // Create a second `TestManagedAgent` that only Carol will use. + testHarnessCarol = await PlatformAgentTestHarness.setup({ agentClass : Web5UserAgent, agentStores : 'memory', testDataLocation : '__TESTDATA__/AGENT_BOB' }); - }); - beforeEach(async () => { - await testHarnessBob.clearStorage(); - // Create an Agent DID. - await testHarnessBob.createAgentDid(); + await testHarnessCarol.clearStorage(); + await testHarnessCarol.createAgentDid(); - // Create a new "bob" Identity to author the DWN messages. - const bob = await testHarnessBob.createIdentity({ name: 'Bob', testDwnUrls }); - await testHarnessBob.agent.identity.manage({ portableIdentity: await bob.export() }); - bobDid = bob.did; + // Create a carol Identity to author the DWN messages. + const carol = await testHarnessCarol.createIdentity({ name: 'Carol', testDwnUrls }); + await testHarnessCarol.agent.identity.manage({ portableIdentity: await carol.export() }); + carolDid = carol.did; // Instantiate a new `DwnApi` using Bob's test agent. - dwnBob = new DwnApi({ agent: testHarnessBob.agent, connectedDid: bobDid.uri }); + dwnCarol = new DwnApi({ agent: testHarnessCarol.agent, connectedDid: carolDid.uri }); + }); + + beforeEach(async () => { + await testHarnessCarol.syncStore.clear(); + await testHarnessCarol.dwnDataStore.clear(); + await testHarnessCarol.dwnEventLog.clear(); + await testHarnessCarol.dwnMessageStore.clear(); + await testHarnessCarol.dwnResumableTaskStore.clear(); + testHarnessCarol.dwnStores.clear(); + + const protocolDefinition = { + ...emailProtocolDefinition, + protocol: protocolUri + }; + + const { status: carolProtocolStatus, protocol: carolProtocol } = await dwnCarol.protocols.configure({ message: { definition: protocolDefinition } }); + expect(carolProtocolStatus.code).to.equal(202); + expect(carolProtocol).to.exist; + const { status: carolProtocolSendStatus } = await carolProtocol.send(carolDid.uri); + expect(carolProtocolSendStatus.code).to.equal(202); }); after(async () => { - await testHarnessBob.clearStorage(); - await testHarnessBob.closeStorage(); + await testHarnessCarol.clearStorage(); + await testHarnessCarol.closeStorage(); }); it('returns large data payloads of records signed by another entity after remote dwn.records.query()', async () => { @@ -1210,25 +1222,6 @@ describe('Record', () => { * record to Bob's DWN, the record is signed by Alice's keys. When Bob fetches the record from * his DWN, this test validates that the `RecordsRead` is signed by Bob's keys. * - * SETUP STEPS: - * S1. Install the email protocol to both Alice's and Bob's DWNs. - */ - let { protocol: aliceProtocol, status: aliceStatus } = await dwnAlice.protocols.configure({ - message: { definition: emailProtocolDefinition } - }); - expect(aliceStatus.code).to.equal(202); - const { status: alicePushStatus } = await aliceProtocol!.send(aliceDid.uri); - expect(alicePushStatus.code).to.equal(202); - const { protocol: bobProtocol, status: bobStatus } = await dwnBob.protocols.configure({ - message: { - definition: emailProtocolDefinition - } - }); - expect(bobStatus.code).to.equal(202); - const { status: bobPushStatus } = await bobProtocol!.send(bobDid.uri); - expect(bobPushStatus.code).to.equal(202); - - /** * TEST STEPS: * * 1. Alice creates a record but does NOT store it her local, agent-connected DWN. @@ -1237,22 +1230,22 @@ describe('Record', () => { data : dataTextExceedingMaxSize, store : false, message : { - protocol : emailProtocolDefinition.protocol, + protocol : protocolUri, protocolPath : 'thread', schema : emailProtocolDefinition.types.thread.schema } }); expect(status.code).to.equal(202); /** - * 2. Alice writes the record to Bob's remote DWN. + * 2. Alice writes the record to Carol's remote DWN. */ - const { status: sendStatus } = await record!.send(bobDid.uri); + const { status: sendStatus } = await record!.send(carolDid.uri); expect(sendStatus.code).to.equal(202); /** - * 3. Bob queries his remote DWN for the record that Alice just wrote. + * 3. Carol queries his remote DWN for the record that Alice just wrote. */ - const { records: queryRecordsFrom, status: queryRecordStatusFrom } = await dwnBob.records.query({ - from : bobDid.uri, + const { records: queryRecordsFrom, status: queryRecordStatusFrom } = await dwnCarol.records.query({ + from : carolDid.uri, message : { filter: { recordId: record!.id }} }); expect(queryRecordStatusFrom.code).to.equal(200); @@ -1288,25 +1281,6 @@ describe('Record', () => { * record to Bob's DWN, the record is signed by Alice's keys. When Bob fetches the record from * his DWN, this test validates that the `RecordsRead` is signed by Bob's keys. * - * SETUP STEPS: - * S1. Install the email protocol to both Alice's and Bob's DWNs. - */ - let { protocol: aliceProtocol, status: aliceStatus } = await dwnAlice.protocols.configure({ - message: { definition: emailProtocolDefinition } - }); - expect(aliceStatus.code).to.equal(202); - const { status: alicePushStatus } = await aliceProtocol!.send(aliceDid.uri); - expect(alicePushStatus.code).to.equal(202); - const { protocol: bobProtocol, status: bobStatus } = await dwnBob.protocols.configure({ - message: { - definition: emailProtocolDefinition - } - }); - expect(bobStatus.code).to.equal(202); - const { status: bobPushStatus } = await bobProtocol!.send(bobDid.uri); - expect(bobPushStatus.code).to.equal(202); - - /** * TEST STEPS: * * 1. Alice creates a record but does NOT store it her local, agent-connected DWN. @@ -1315,32 +1289,32 @@ describe('Record', () => { data : dataTextExceedingMaxSize, store : false, message : { - protocol : emailProtocolDefinition.protocol, + protocol : protocolUri, protocolPath : 'thread', schema : emailProtocolDefinition.types.thread.schema } }); expect(status.code).to.equal(202); /** - * 2. Alice writes the record to Bob's remote DWN. + * 2. Alice writes the record to Carol's remote DWN. */ - const { status: sendStatus } = await record!.send(bobDid.uri); + const { status: sendStatus } = await record!.send(carolDid.uri); expect(sendStatus.code).to.equal(202); /** - * 3. Bob queries his remote DWN for the record that Alice just wrote. + * 3. Carol queries her remote DWN for the record that Alice just wrote. */ - const { records: queryRecordsFrom, status: queryRecordStatusFrom } = await dwnBob.records.query({ - from : bobDid.uri, + const { records: queryRecordsFrom, status: queryRecordStatusFrom } = await dwnCarol.records.query({ + from : carolDid.uri, message : { filter: { recordId: record!.id }} }); expect(queryRecordStatusFrom.code).to.equal(200); /** - * 4. Validate that Bob is able to write the record to Alice's remote DWN. + * 4. Validate that Carol is able to write the record to Alice's remote DWN. */ const { status: sendStatusToAlice } = await queryRecordsFrom[0]!.send(aliceDid.uri); expect(sendStatusToAlice.code).to.equal(202); /** - * 5. Alice queries her remote DWN for the record that Bob just wrote. + * 5. Alice queries her remote DWN for the record that Carol just wrote. */ const { records: queryRecordsTo, status: queryRecordStatusTo } = await dwnAlice.records.query({ from : aliceDid.uri, @@ -1534,39 +1508,14 @@ describe('Record', () => { * be fetched with a RecordsRead when record.data.blob() is executed. */ const dataText = TestDataGenerator.randomString(DwnConstant.maxDataSizeAllowedToBeEncoded + 1000); - // Install the email protocol for Alice's local DWN. - let { protocol: aliceProtocol, status: aliceStatus } = await dwnAlice.protocols.configure({ - message: { definition: emailProtocolDefinition } - }); - expect(aliceStatus.code).to.equal(202); - expect(aliceProtocol).to.exist; - - // Install the email protocol for Alice's remote DWN. - const { status: alicePushStatus } = await aliceProtocol!.send(aliceDid.uri); - expect(alicePushStatus.code).to.equal(202); - - // Install the email protocol for Bob's local DWN. - const { protocol: bobProtocol, status: bobStatus } = await dwnBob.protocols.configure({ - message: { - definition: emailProtocolDefinition - } - }); - - expect(bobStatus.code).to.equal(202); - expect(bobProtocol).to.exist; - - // Install the email protocol for Bob's remote DWN. - const { status: bobPushStatus } = await bobProtocol!.send(bobDid.uri); - expect(bobPushStatus.code).to.equal(202); - // Alice creates a new large record but does not store it in her local DWN. const { status: aliceEmailStatus, record: aliceEmailRecord } = await dwnAlice.records.write({ store : false, data : dataText, message : { - protocol : emailProtocolDefinition.protocol, + protocol : protocolUri, protocolPath : 'thread', - schema : 'http://email-protocol.xyz/schema/thread', + schema : emailProtocolDefinition.types.thread.schema } }); expect(aliceEmailStatus.code).to.equal(202); @@ -1592,7 +1541,8 @@ describe('Record', () => { from : bobDid.uri, message : { filter: { - schema: 'http://email-protocol.xyz/schema/thread' + protocol : protocolUri, + schema : emailProtocolDefinition.types.thread.schema } } }); @@ -1606,39 +1556,14 @@ describe('Record', () => { * be fetched with a RecordsRead when record.data.blob() is executed. */ const dataText = TestDataGenerator.randomString(DwnConstant.maxDataSizeAllowedToBeEncoded + 1000); - // Install the email protocol for Alice's local DWN. - let { protocol: aliceProtocol, status: aliceStatus } = await dwnAlice.protocols.configure({ - message: { definition: emailProtocolDefinition } - }); - expect(aliceStatus.code).to.equal(202); - expect(aliceProtocol).to.exist; - - // Install the email protocol for Alice's remote DWN. - const { status: alicePushStatus } = await aliceProtocol!.send(aliceDid.uri); - expect(alicePushStatus.code).to.equal(202); - - // Install the email protocol for Bob's local DWN. - const { protocol: bobProtocol, status: bobStatus } = await dwnBob.protocols.configure({ - message: { - definition: emailProtocolDefinition - } - }); - - expect(bobStatus.code).to.equal(202); - expect(bobProtocol).to.exist; - - // Install the email protocol for Bob's remote DWN. - const { status: bobPushStatus } = await bobProtocol!.send(bobDid.uri); - expect(bobPushStatus.code).to.equal(202); - // Alice creates a new large record but does not store it in her local DWN. const { status: aliceEmailStatus, record: aliceEmailRecord } = await dwnAlice.records.write({ store : false, data : dataText, message : { - protocol : emailProtocolDefinition.protocol, + protocol : protocolUri, protocolPath : 'thread', - schema : 'http://email-protocol.xyz/schema/thread', + schema : emailProtocolDefinition.types.thread.schema } }); expect(aliceEmailStatus.code).to.equal(202); @@ -1663,7 +1588,8 @@ describe('Record', () => { from : bobDid.uri, message : { filter: { - schema: 'http://email-protocol.xyz/schema/thread' + protocol : protocolUri, + schema : emailProtocolDefinition.types.thread.schema } } }); @@ -1675,41 +1601,13 @@ describe('Record', () => { it(`writes records to remote DWNs for someone else's DID`, async () => { const dataString = 'Hello, world!'; - // Install the email protocol for Alice's local DWN. - let { protocol: aliceProtocol, status: aliceStatus } = await dwnAlice.protocols.configure({ - message: { - definition: emailProtocolDefinition - } - }); - - expect(aliceStatus.code).to.equal(202); - expect(aliceProtocol).to.exist; - - // Install the email protocol for Alice's remote DWN. - const { status: alicePushStatus } = await aliceProtocol!.send(aliceDid.uri); - expect(alicePushStatus.code).to.equal(202); - - // Install the email protocol for Bob's local DWN. - const { protocol: bobProtocol, status: bobStatus } = await dwnBob.protocols.configure({ - message: { - definition: emailProtocolDefinition - } - }); - - expect(bobStatus.code).to.equal(202); - expect(bobProtocol).to.exist; - - // Install the email protocol for Bob's remote DWN. - const { status: bobPushStatus } = await bobProtocol!.send(bobDid.uri); - expect(bobPushStatus.code).to.equal(202); - // Alice writes a message to her own DWN. const { status: aliceEmailStatus, record: aliceEmailRecord } = await dwnAlice.records.write({ data : dataString, message : { - protocol : emailProtocolDefinition.protocol, + protocol : protocolUri, protocolPath : 'thread', - schema : 'http://email-protocol.xyz/schema/thread', + schema : emailProtocolDefinition.types.thread.schema } }); @@ -1724,7 +1622,8 @@ describe('Record', () => { from : bobDid.uri, message : { filter: { - schema: 'http://email-protocol.xyz/schema/thread' + protocol : protocolUri, + schema : emailProtocolDefinition.types.thread.schema } } }); @@ -1744,7 +1643,9 @@ describe('Record', () => { store : false, data : dataString, message : { - dataFormat: 'text/plain' + protocol : protocolUri, + protocolPath : 'thread', + schema : emailProtocolDefinition.types.thread.schema } }); @@ -1758,7 +1659,9 @@ describe('Record', () => { const queryResult = await dwnAlice.records.query({ message: { filter: { - dataFormat: 'text/plain' + protocol : protocolUri, + protocolPath : 'thread', + schema : emailProtocolDefinition.types.thread.schema } } }); @@ -1777,7 +1680,9 @@ describe('Record', () => { from : aliceDid.uri, message : { filter: { - dataFormat: 'text/plain' + protocol : protocolUri, + protocolPath : 'thread', + schema : emailProtocolDefinition.types.thread.schema } } }); @@ -1791,43 +1696,15 @@ describe('Record', () => { }); it(`writes records to someone else's remote DWN but not your agent DWN`, async () => { - // Install a protocol on Alice's agent connected DWN. - let { protocol: aliceProtocol, status: aliceStatus } = await dwnAlice.protocols.configure({ - message: { - definition: emailProtocolDefinition - } - }); - - expect(aliceStatus.code).to.equal(202); - expect(aliceProtocol).to.exist; - - // Install the protocol on Alice's remote DWN. - const { status: alicePushStatus } = await aliceProtocol!.send(aliceDid.uri); - expect(alicePushStatus.code).to.equal(202); - - // Install the email protocol for Bob's local DWN. - const { protocol: bobProtocol, status: bobStatus } = await dwnBob.protocols.configure({ - message: { - definition: emailProtocolDefinition - } - }); - - expect(bobStatus.code).to.equal(202); - expect(bobProtocol).to.exist; - - // Install the email protocol for Bob's remote DWN. - const { status: bobPushStatus } = await bobProtocol!.send(bobDid.uri); - expect(bobPushStatus.code).to.equal(202); - // Alice writes a message to her agent DWN with `store: false`. const dataString = 'Hello, world!'; const writeResult = await dwnAlice.records.write({ store : false, data : dataString, message : { - protocol : emailProtocolDefinition.protocol, + protocol : protocolUri, protocolPath : 'thread', - schema : 'http://email-protocol.xyz/schema/thread', + schema : emailProtocolDefinition.types.thread.schema } }); @@ -1841,7 +1718,9 @@ describe('Record', () => { const queryResult = await dwnAlice.records.query({ message: { filter: { - schema: 'http://email-protocol.xyz/schema/thread' + protocol : protocolUri, + protocolPath : 'thread', + schema : emailProtocolDefinition.types.thread.schema } } }); @@ -1860,7 +1739,9 @@ describe('Record', () => { from : bobDid.uri, message : { filter: { - dataFormat: 'text/plain' + protocol : protocolUri, + protocolPath : 'thread', + schema : emailProtocolDefinition.types.thread.schema } } }); @@ -1880,7 +1761,9 @@ describe('Record', () => { store : true, data : dataString, message : { - dataFormat: 'text/plain' + protocol : protocolUri, + protocolPath : 'thread', + schema : emailProtocolDefinition.types.thread.schema } }); @@ -1894,7 +1777,9 @@ describe('Record', () => { const queryResult = await dwnAlice.records.query({ message: { filter: { - dataFormat: 'text/plain' + protocol : protocolUri, + protocolPath : 'thread', + schema : emailProtocolDefinition.types.thread.schema } } }); @@ -1915,7 +1800,9 @@ describe('Record', () => { from : aliceDid.uri, message : { filter: { - dataFormat: 'text/plain' + protocol : protocolUri, + protocolPath : 'thread', + schema : emailProtocolDefinition.types.thread.schema } } }); @@ -1970,19 +1857,12 @@ describe('Record', () => { }; // RecordsWriteDescriptor properties that can be pre-defined - const protocol = emailProtocolDefinition.protocol; + const protocol = protocolUri; const protocolPath = 'thread'; const schema = emailProtocolDefinition.types.thread.schema; const recipient = aliceDid.uri; const published = true; - // Install a protocol on Alice's agent connected DWN. - await dwnAlice.protocols.configure({ - message: { - definition: emailProtocolDefinition - } - }); - const RecordsWrite = dwnMessageConstructors[DwnInterface.RecordsWrite]; // Create a parent record to reference in the RecordsWriteMessage used for validation @@ -2074,20 +1954,11 @@ describe('Record', () => { }); it('should return a string representation of the record with protocol properties', async () => { - // install a protocol to use for the record - let { protocol: aliceProtocol, status: aliceStatus } = await dwnAlice.protocols.configure({ - message: { - definition: emailProtocolDefinition, - } - }); - expect(aliceStatus.code).to.equal(202); - expect(aliceProtocol).to.exist; - // create a record const { record, status } = await dwnAlice.records.write({ data : 'Hello, world!', message : { - protocol : emailProtocolDefinition.protocol, + protocol : protocolUri, protocolPath : 'thread', schema : emailProtocolDefinition.types.thread.schema, dataFormat : 'text/plain' @@ -2406,20 +2277,11 @@ describe('Record', () => { }); it('updates a record which has a parent reference', async () => { - // install a protocol - let { protocol, status: protocolStatus } = await dwnAlice.protocols.configure({ - message: { - definition: emailProtocolDefinition, - } - }); - expect(protocolStatus.code).to.equal(202); - expect(protocolStatus).to.exist; - // create a parent thread const { status: threadStatus, record: threadRecord } = await dwnAlice.records.write({ data : 'Hello, world!', message : { - protocol : protocol.definition.protocol, + protocol : protocolUri, schema : emailProtocolDefinition.types.thread.schema, protocolPath : 'thread' } @@ -2433,7 +2295,7 @@ describe('Record', () => { data : 'Hello, world!', message : { parentContextId : threadRecord.contextId, - protocol : emailProtocolDefinition.protocol, + protocol : protocolUri, protocolPath : 'thread/email', schema : emailProtocolDefinition.types.email.schema } @@ -3075,6 +2937,44 @@ describe('Record', () => { }); describe('store()', () => { + let ownerOnlyProtocolUri: string; + // install a protocol that only the owner of the DWN should be able to writing records + const ownerOnlyProtocolDefinition: DwnProtocolDefinition = { + protocol : 'owner-only', + published : true, + types : { + note: { + schema : 'http://example.com/note', + dataFormats : ['text/plain', 'application/json'] + } + }, + structure: { + note: {} + } + }; + + beforeEach(async () => { + + // give the protocol a random URI on each run + ownerOnlyProtocolUri = `http://example.com/protocol/${TestDataGenerator.randomString(10)}`; + const protocolDefinition = { + ...ownerOnlyProtocolDefinition, + protocol: ownerOnlyProtocolUri + }; + + + const { status: aliceProtocolStatus, protocol: aliceProtocol } = await dwnAlice.protocols.configure({ message: { definition: protocolDefinition } }); + expect(aliceProtocolStatus.code).to.equal(202); + expect(aliceProtocol).to.exist; + const { status: aliceProtocolSendStatus } = await aliceProtocol.send(aliceDid.uri); + expect(aliceProtocolSendStatus.code).to.equal(202); + const { status: bobProtocolStatus, protocol: bobProtocol } = await dwnBob.protocols.configure({ message: { definition: protocolDefinition } }); + expect(bobProtocolStatus.code).to.equal(202); + expect(bobProtocol).to.exist; + const { status: bobProtocolSendStatus } = await bobProtocol!.send(bobDid.uri); + expect(bobProtocolSendStatus.code).to.equal(202); + }); + it('should store an external record if it has been imported by the dwn owner', async () => { // Scenario: Alice creates a record. // Bob queries for the record from Alice's DWN and then stores it to their own DWN. @@ -3083,9 +2983,10 @@ describe('Record', () => { const { status, record } = await dwnAlice.records.write({ data : 'Hello, world!', message : { - published : true, - schema : 'foo/bar', - dataFormat : 'text/plain' + published : true, + protocol : ownerOnlyProtocolUri, + protocolPath : 'note', + schema : ownerOnlyProtocolDefinition.types.note.schema } }); expect(status.code).to.equal(202, status.detail); @@ -3146,9 +3047,10 @@ describe('Record', () => { const { status, record } = await dwnAlice.records.write({ data : 'Hello, world!', message : { - published : true, - schema : 'foo/bar', - dataFormat : 'text/plain' + published : true, + protocol : ownerOnlyProtocolUri, + protocolPath : 'note', + schema : ownerOnlyProtocolDefinition.types.note.schema } }); expect(status.code).to.equal(202, status.detail); @@ -3218,8 +3120,9 @@ describe('Record', () => { store : false, data : 'Hello, world!', message : { - schema : 'foo/bar', - dataFormat : 'text/plain' + protocol : ownerOnlyProtocolUri, + protocolPath : 'note', + schema : ownerOnlyProtocolDefinition.types.note.schema } }); expect(writeStatus.code).to.equal(202); @@ -3254,9 +3157,10 @@ describe('Record', () => { const { status, record } = await dwnAlice.records.write({ data : 'Hello, world!', message : { - published : true, - schema : 'foo/bar', - dataFormat : 'text/plain' + published : true, + protocol : protocolUri, + protocolPath : 'thread', + schema : emailProtocolDefinition.types.thread.schema } }); expect(status.code).to.equal(202, status.detail); @@ -3302,9 +3206,10 @@ describe('Record', () => { const { status, record } = await dwnAlice.records.write({ data : 'Hello, world!', message : { - published : true, - schema : 'foo/bar', - dataFormat : 'text/plain' + published : true, + protocol : protocolUri, + protocolPath : 'thread', + schema : emailProtocolDefinition.types.thread.schema } }); expect(status.code).to.equal(202, status.detail); @@ -3356,8 +3261,9 @@ describe('Record', () => { store : false, data : 'Hello, world!', message : { - schema : 'foo/bar', - dataFormat : 'text/plain' + protocol : protocolUri, + protocolPath : 'thread', + schema : emailProtocolDefinition.types.thread.schema } }); expect(writeStatus.code).to.equal(202); @@ -3391,9 +3297,10 @@ describe('Record', () => { const { status, record } = await dwnAlice.records.write({ data : 'Hello, world!', message : { - published : true, - schema : 'foo/bar', - dataFormat : 'text/plain' + published : true, + protocol : protocolUri, + protocolPath : 'thread', + schema : emailProtocolDefinition.types.thread.schema } }); expect(status.code).to.equal(202, status.detail); @@ -3455,9 +3362,10 @@ describe('Record', () => { const { status, record } = await dwnAlice.records.write({ data : 'Hello, world!', message : { - published : true, - schema : 'foo/bar', - dataFormat : 'text/plain' + published : true, + protocol : protocolUri, + protocolPath : 'thread', + schema : emailProtocolDefinition.types.thread.schema } }); expect(status.code).to.equal(202, status.detail); @@ -3521,8 +3429,9 @@ describe('Record', () => { const { status, record } = await dwnAlice.records.write({ data : 'Hello, world!', message : { - schema : 'foo/bar', - dataFormat : 'text/plain' + protocol : protocolUri, + protocolPath : 'thread', + schema : emailProtocolDefinition.types.thread.schema } }); @@ -3547,9 +3456,10 @@ describe('Record', () => { const { status, record } = await dwnAlice.records.write({ data : 'Hello, world!', message : { - published : true, - schema : 'foo/bar', - dataFormat : 'text/plain' + published : true, + protocol : protocolUri, + protocolPath : 'thread', + schema : emailProtocolDefinition.types.thread.schema } }); expect(status.code).to.equal(202); @@ -3586,8 +3496,9 @@ describe('Record', () => { store : false, data : 'Hello, world!', message : { - schema : 'foo/bar', - dataFormat : 'text/plain' + protocol : protocolUri, + protocolPath : 'thread', + schema : emailProtocolDefinition.types.thread.schema } }); expect(writeStatus.code).to.equal(202);