Skip to content

Commit

Permalink
additional test coverage for roles cases
Browse files Browse the repository at this point in the history
  • Loading branch information
LiranCohen committed Oct 18, 2024
1 parent 0a53308 commit 158c3b2
Show file tree
Hide file tree
Showing 4 changed files with 287 additions and 31 deletions.
29 changes: 12 additions & 17 deletions packages/api/src/record.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,6 @@ export type RecordModel = ImmutableRecordProperties & OptionalRecordProperties &

/** The timestamp indicating when the record was last modified. */
messageTimestamp?: string;

/** The protocol role under which this record is written. */
protocolRole?: RecordOptions['protocolRole'];
}

/**
Expand Down Expand Up @@ -153,7 +150,7 @@ export type RecordUpdateParams = {
datePublished?: DwnMessageDescriptor[DwnInterface.RecordsWrite]['datePublished'];

/** The protocol role under which this record is written. */
protocolRole?: RecordOptions['protocolRole'];
protocolRole?: string;

/** The published status of the record. */
published?: DwnMessageDescriptor[DwnInterface.RecordsWrite]['published'];
Expand Down Expand Up @@ -185,7 +182,7 @@ export type RecordDeleteParams = {
dateModified?: DwnMessageDescriptor[DwnInterface.RecordsDelete]['messageTimestamp'];

/** The protocol role under which this record will be deleted. */
protocolRole?: RecordOptions['protocolRole'];
protocolRole?: string;
};

/**
Expand Down Expand Up @@ -227,6 +224,8 @@ export class Record implements RecordModel {
private _readableStream?: Readable;
/** The origin DID if the record was fetched from a remote DWN. */
private _remoteOrigin?: string;
/** The protocolRole to use when reading the record */
private _protocolRole?: string;

// Private variables for DWN `RecordsWrite` message properties.

Expand All @@ -252,8 +251,6 @@ export class Record implements RecordModel {
private _initialWriteSigned: boolean;
/** Unique identifier of the record. */
private _recordId: string;
/** Role under which the record is written. */
private _protocolRole?: RecordOptions['protocolRole'];

/** The `RecordsWriteMessage` descriptor unless the record is in a deleted state */
private get _recordsWriteDescriptor() {
Expand Down Expand Up @@ -314,7 +311,6 @@ export class Record implements RecordModel {
/** Tags of the record */
get tags() { return this._recordsWriteDescriptor?.tags; }


// Getters for for properties that depend on the current state of the Record.
/** DID that is the logical author of the Record. */
get author(): string { return this._author; }
Expand All @@ -334,9 +330,6 @@ export class Record implements RecordModel {
/** Record's signatures attestation */
get attestation(): DwnMessage[DwnInterface.RecordsWrite]['attestation'] | undefined { return this._attestation; }

/** Role under which the author is writing the record */
get protocolRole() { return this._protocolRole; }

/** Record's deleted state (true/false) */
get deleted() { return isDwnMessage(DwnInterface.RecordsDelete, this.rawMessage); }

Expand All @@ -356,14 +349,12 @@ export class Record implements RecordModel {
descriptor : this._descriptor,
attestation : this._attestation,
authorization : this._authorization,
protocolRole : this._protocolRole,
encryption : this._encryption,
}));
} else {
message = JSON.parse(JSON.stringify({
descriptor : this._descriptor,
authorization : this._authorization,
protocolRole : this._protocolRole,
}));
}

Expand Down Expand Up @@ -656,7 +647,6 @@ export class Record implements RecordModel {
parentId : this.parentId,
protocol : this.protocol,
protocolPath : this.protocolPath,
protocolRole : this.protocolRole,
published : this.published,
recipient : this.recipient,
recordId : this.id,
Expand Down Expand Up @@ -708,7 +698,7 @@ export class Record implements RecordModel {
*
* @beta
*/
async update({ dateModified, data, ...params }: RecordUpdateParams): Promise<DwnResponseStatus> {
async update({ dateModified, data, protocolRole, ...params }: RecordUpdateParams): Promise<DwnResponseStatus> {

if (this.deleted) {
throw new Error('Record: Cannot revive a deleted record.');
Expand All @@ -723,6 +713,7 @@ export class Record implements RecordModel {
...descriptor,
...params,
parentContextId,
protocolRole,
messageTimestamp : dateModified, // Map Record class `dateModified` property to DWN SDK `messageTimestamp`
recordId : this._recordId
};
Expand Down Expand Up @@ -791,7 +782,6 @@ export class Record implements RecordModel {

// Only update the local Record instance mutable properties if the record was successfully (over)written.
this._authorization = responseMessage.authorization;
this._protocolRole = params.protocolRole;
mutableDescriptorProperties.forEach(property => {
this._descriptor[property] = responseMessage.descriptor[property];
});
Expand Down Expand Up @@ -839,7 +829,11 @@ export class Record implements RecordModel {
store
};

if (this.deleted) {
// Check to see if the provided protocolRole is different from the current protocolRole
// If so we need to construct a delete message with the new protocolRole, otherwise we can use the existing
// NOTE: currently this is testing the instance _protocolRole, not the actual signature payload.
const differentRole = deleteParams?.protocolRole ? this._protocolRole !== deleteParams.protocolRole : false;
if (this.deleted && !differentRole) {
// if we have a delete message we can just use it
deleteOptions.rawMessage = this.rawMessage as DwnMessage[DwnInterface.RecordsDelete];
} else {
Expand All @@ -848,6 +842,7 @@ export class Record implements RecordModel {
prune : prune,
recordId : this._recordId,
messageTimestamp : dateModified,
protocolRole : deleteParams?.protocolRole
};
}

Expand Down
34 changes: 22 additions & 12 deletions packages/api/tests/dwn-api.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2082,10 +2082,15 @@ describe('DwnApi', () => {
});

it('ensures that a protocolRole used to query is also used to read the data of the resulted records', async () => {
const protocol = {
...notesProtocolDefinition,
protocol: 'http://example.com/notes' + TestDataGenerator.randomString(15)
};

// Bob configures the notes protocol for himself
const { status: bobProtocolStatus, protocol: bobProtocol } = await dwnBob.protocols.configure({
message: {
definition: notesProtocolDefinition
definition: protocol
}
});
expect(bobProtocolStatus.code).to.equal(202);
Expand All @@ -2100,9 +2105,9 @@ describe('DwnApi', () => {
const { status: noteCreateStatus, record: noteRecord } = await dwnBob.records.create({
data,
message: {
protocol : notesProtocolDefinition.protocol,
protocol : protocol.protocol,
protocolPath : 'note',
schema : notesProtocolDefinition.types.note.schema,
schema : protocol.types.note.schema,
dataFormat : 'text/plain',
}
});
Expand All @@ -2117,9 +2122,9 @@ describe('DwnApi', () => {
data : 'friend!',
message : {
recipient : aliceDid.uri,
protocol : notesProtocolDefinition.protocol,
protocol : protocol.protocol,
protocolPath : 'friend',
schema : notesProtocolDefinition.types.friend.schema,
schema : protocol.types.friend.schema,
dataFormat : 'text/plain'
}
});
Expand All @@ -2133,7 +2138,7 @@ describe('DwnApi', () => {
message : {
protocolRole : 'friend',
filter : {
protocol : notesProtocolDefinition.protocol,
protocol : protocol.protocol,
protocolPath : 'note'
}
}
Expand Down Expand Up @@ -2517,10 +2522,15 @@ describe('DwnApi', () => {
});

it('ensures that a protocolRole used to subscribe is also used to read the data of the resulted records', async () => {
const protocol = {
...notesProtocolDefinition,
protocol: 'http://example.com/notes' + TestDataGenerator.randomString(15)
};

// Bob configures the notes protocol for himself
const { status: bobProtocolStatus, protocol: bobProtocol } = await dwnBob.protocols.configure({
message: {
definition: notesProtocolDefinition
definition: protocol
}
});
expect(bobProtocolStatus.code).to.equal(202);
Expand All @@ -2533,9 +2543,9 @@ describe('DwnApi', () => {
data : 'friend!',
message : {
recipient : aliceDid.uri,
protocol : notesProtocolDefinition.protocol,
protocol : protocol.protocol,
protocolPath : 'friend',
schema : notesProtocolDefinition.types.friend.schema,
schema : protocol.types.friend.schema,
dataFormat : 'text/plain'
}
});
Expand All @@ -2555,7 +2565,7 @@ describe('DwnApi', () => {
message : {
protocolRole : 'friend',
filter : {
protocol : notesProtocolDefinition.protocol,
protocol : protocol.protocol,
protocolPath : 'note'
}
},
Expand All @@ -2572,9 +2582,9 @@ describe('DwnApi', () => {
const { status: noteCreateStatus, record: noteRecord } = await dwnBob.records.create({
data,
message: {
protocol : notesProtocolDefinition.protocol,
protocol : protocol.protocol,
protocolPath : 'note',
schema : notesProtocolDefinition.types.note.schema,
schema : protocol.types.note.schema,
dataFormat : 'text/plain',
}
});
Expand Down
19 changes: 18 additions & 1 deletion packages/api/tests/fixtures/protocol-definitions/notes.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,41 @@
"text/plain",
"application/json"
]
},
"coAuthor" : {
"schema": "http://notes-protocol.xyz/schema/coAuthor",
"dataFormats": [
"text/plain",
"application/json"
]
}
},
"structure": {
"friend" :{
"$role": true
},
"note": {
"coAuthor" : {
"$role": true
},
"$actions": [
{
"role": "friend",
"can": ["read", "query", "subscribe"]
},
{
"role": "note/coAuthor",
"can": [ "co-update", "co-delete" ]
}
],
"comment": {
"$actions": [
{
"role": "friend",
"can": ["create", "delete", "read", "query", "subscribe"]
"can": ["create", "update", "delete", "read", "query", "subscribe"]
}, {
"role": "note/coAuthor",
"can": ["create", "update", "delete", "co-delete", "read", "query", "subscribe"]
}
]
}
Expand Down
Loading

0 comments on commit 158c3b2

Please sign in to comment.