Skip to content

Commit

Permalink
Add tests for document handler
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulLeCam committed Jun 14, 2024
1 parent 998cb59 commit 1534d3b
Show file tree
Hide file tree
Showing 13 changed files with 626 additions and 95 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
"@biomejs/biome": "1.8.1",
"@jest/globals": "^29.7.0",
"@swc/cli": "^0.3.12",
"@swc/core": "^1.5.28",
"@swc/core": "^1.5.29",
"@swc/jest": "^0.2.36",
"@types/jest": "^29.5.12",
"@types/node": "^20.14.2",
"del-cli": "^5.1.0",
"jest": "^29.7.0",
"tsx": "^4.15.2",
"tsx": "^4.15.4",
"turbo": "^2.0.3",
"typescript": "^5.4.5"
},
Expand Down
18 changes: 17 additions & 1 deletion packages/document-client/src/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import {
type DeterministicInitEventPayload,
type DocumentDataEventHeader,
DocumentDataEventPayload,
type EncodedDeterministicInitEventPayload,
type JSONPatchOperation,
assertValidContentLength,
assertValidPatchOperations,
} from '@ceramic-sdk/document-protocol'
import {
InitEventHeader,
type SignedEvent,
createSignedInitEvent,
signEvent,
Expand Down Expand Up @@ -39,7 +41,7 @@ export async function createInitEvent<
return await createSignedInitEvent(controller, content, header)
}

export function getDeterministicInitEvent(
export function getDeterministicInitEventPayload(
model: StreamID,
controller: DIDString | string,
uniqueValue?: Uint8Array,
Expand All @@ -54,6 +56,20 @@ export function getDeterministicInitEvent(
}
}

export function getDeterministicInitEvent(
model: StreamID,
controller: DIDString | string,
uniqueValue?: Uint8Array,
): EncodedDeterministicInitEventPayload {
const { header } = getDeterministicInitEventPayload(
model,
controller,
uniqueValue,
)
// @ts-ignore: "sep" value is typed as string rather than "model" literal
return { data: null, header: InitEventHeader.encode(header) }
}

export function createDataEventPayload(
current: CommitID,
data: Array<JSONPatchOperation>,
Expand Down
1 change: 1 addition & 0 deletions packages/document-client/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export {
createDataEventPayload,
createInitEvent,
getDeterministicInitEvent,
getDeterministicInitEventPayload,
} from './events.js'
export type { UnknownContent } from './types.js'
export { getPatchOperations } from './utils.js'
41 changes: 29 additions & 12 deletions packages/document-client/test/lib.test.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
import {
DataInitEventPayload,
DocumentDataEventPayload,
DocumentInitEventPayload,
} from '@ceramic-sdk/document-protocol'
import { assertSignedEvent, getSignedEventPayload } from '@ceramic-sdk/events'
import { CommitID, randomCID, randomStreamID } from '@ceramic-sdk/identifiers'
import { getAuthenticatedDID } from '@ceramic-sdk/key-did'
import { equals } from 'uint8arrays'

import {
createDataEvent,
createInitEvent,
getDeterministicInitEvent,
getDeterministicInitEventPayload,
} from '../src/index.js'

const authenticatedDID = await getAuthenticatedDID(new Uint8Array(32))

describe('getDeterministicInitEvent()', () => {
describe('getDeterministicInitEventPayload()', () => {
test('returns the deterministic event payload without unique value by default', () => {
const model = randomStreamID()
const event = getDeterministicInitEvent(model, 'did:key:123')
const event = getDeterministicInitEventPayload(model, 'did:key:123')
expect(event.data).toBeNull()
expect(event.header.controllers).toEqual(['did:key:123'])
expect(event.header.model).toBe(model)
Expand All @@ -27,14 +29,35 @@ describe('getDeterministicInitEvent()', () => {
test('returns the deterministic event payload with the provided unique value', () => {
const model = randomStreamID()
const unique = new Uint8Array([0, 1, 2])
const event = getDeterministicInitEvent(model, 'did:key:123', unique)
const event = getDeterministicInitEventPayload(model, 'did:key:123', unique)
expect(event.data).toBeNull()
expect(event.header.controllers).toEqual(['did:key:123'])
expect(event.header.model).toBe(model)
expect(event.header.unique).toBe(unique)
})
})

describe('getDeterministicInitEvent()', () => {
test('returns the deterministic event without unique value by default', () => {
const model = randomStreamID()
const event = getDeterministicInitEvent(model, 'did:key:123')
expect(event.data).toBeNull()
expect(event.header.controllers).toEqual(['did:key:123'])
expect(equals(event.header.model, model.bytes)).toBe(true)
expect(event.header.unique).toBeUndefined()
})

test('returns the deterministic event with the provided unique value', () => {
const model = randomStreamID()
const unique = new Uint8Array([0, 1, 2])
const event = getDeterministicInitEvent(model, 'did:key:123', unique)
expect(event.data).toBeNull()
expect(event.header.controllers).toEqual(['did:key:123'])
expect(equals(event.header.model, model.bytes)).toBe(true)
expect(event.header.unique).toBe(unique)
})
})

describe('createInitEvent()', () => {
test('creates unique events by adding a random unique value', async () => {
const model = randomStreamID()
Expand All @@ -60,10 +83,7 @@ describe('createInitEvent()', () => {
controller: authenticatedDID,
model,
})
const payload1 = await getSignedEventPayload(
DocumentInitEventPayload,
event1,
)
const payload1 = await getSignedEventPayload(DataInitEventPayload, event1)
expect(payload1.header.context).toBeUndefined()
expect(payload1.header.shouldIndex).toBeUndefined()

Expand All @@ -75,10 +95,7 @@ describe('createInitEvent()', () => {
context,
shouldIndex: true,
})
const payload2 = await getSignedEventPayload(
DocumentInitEventPayload,
event2,
)
const payload2 = await getSignedEventPayload(DataInitEventPayload, event2)
expect(payload2.header.context?.equals(context)).toBe(true)
expect(payload2.header.shouldIndex).toBe(true)
})
Expand Down
2 changes: 2 additions & 0 deletions packages/document-handler/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
"uint8arrays": "^5.1.0"
},
"devDependencies": {
"@ceramic-sdk/document-client": "workspace:^",
"@ceramic-sdk/key-did": "workspace:^",
"@ceramic-sdk/model-protocol": "workspace:^",
"dids": "^5.0.2"
},
Expand Down
22 changes: 14 additions & 8 deletions packages/document-handler/src/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
DocumentInitEventPayload,
DocumentMetadata,
type EncodedDocumentMetadata,
assertValidContentLength,
getDeterministicStreamID,
getStreamID,
Expand All @@ -27,21 +28,21 @@ export async function handleInitEvent(
const definition = await context.loadModelDefinition(modelID)
assertValidInitHeader(definition, header)

const metadata = DocumentMetadata.encode({
controller: header.controllers[0],
model: header.model,
unique: header.unique,
context: header.context,
shouldIndex: header.shouldIndex,
})

let streamID: StreamID
let metadata: EncodedDocumentMetadata
if (container.signed) {
// Handle non-deterministic event - should have content
assertValidContentLength(data)
assertValidContent(modelID, definition.schema, data)
await validateRelationsContent(context, definition, data)
streamID = getStreamID(container.cid)
metadata = DocumentMetadata.encode({
controller: header.controllers[0],
model: header.model,
unique: header.unique,
context: header.context,
shouldIndex: header.shouldIndex,
})
} else {
// Handle deterministic event - no content
if (data !== null) {
Expand All @@ -50,6 +51,11 @@ export async function handleInitEvent(
)
}
streamID = getDeterministicStreamID(header)
metadata = DocumentMetadata.encode({
controller: header.controllers[0],
model: header.model,
unique: header.unique,
})
}

return {
Expand Down
6 changes: 2 additions & 4 deletions packages/document-handler/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import type { DocumentMetadata } from '@ceramic-sdk/document-protocol'
import type { EncodedDocumentMetadata } from '@ceramic-sdk/document-protocol'
import type { ModelDefinition } from '@ceramic-sdk/model-protocol'
import type { DID } from 'dids'

export type UnknowContent = Record<string, unknown>

export type EncodedMetadata = ReturnType<typeof DocumentMetadata.encode>

export type DocumentSnapshot = {
content: UnknowContent | null
metadata: EncodedMetadata
metadata: EncodedDocumentMetadata
}

export type DocumentState = DocumentSnapshot & {
Expand Down
Loading

0 comments on commit 1534d3b

Please sign in to comment.