/*! * Copyright (c) Microsoft Corporation and contributors. All rights reserved. * Licensed under the MIT License. */ import { EventEmitter, TypedEventEmitter } from "@fluid-internal/client-utils"; import { IDeltaManager, IDeltaManagerEvents, IDeltaQueue, ReadOnlyInfo, } from "@fluidframework/container-definitions/internal"; import { assert } from "@fluidframework/core-utils/internal"; import { IClientDetails } from "@fluidframework/driver-definitions"; import { IClientConfiguration, IDocumentMessage, MessageType, ISequencedDocumentMessage, ISignalMessage, } from "@fluidframework/driver-definitions/internal"; /** * Mock implementation of IDeltaQueue for testing that does nothing * @legacy @beta */ export class MockDeltaQueue extends EventEmitter implements IDeltaQueue { protected readonly queue: T[] = []; protected pauseCount = 0; public processCallback: (el: T) => void = (): void => {}; public get disposed(): any { return undefined; } public get paused(): boolean { return this.pauseCount !== 0; } public get length(): number { return this.queue.length; } public get idle(): boolean { return this.queue.length === 0; } protected process(): void { void Promise.resolve().then(() => { while (this.pauseCount === 0 && this.length > 0) { const el = this.pop(); assert(el !== undefined, "this is impossible due to the above length check"); this.processCallback(el); } }); } public push(el: T): void { this.queue.push(el); this.emit("push", el); this.process(); } public pop(): T | undefined { return this.queue.shift(); } public async pause(): Promise { this.pauseCount++; return; } public resume(): void { this.pauseCount--; this.process(); } public peek(): T | undefined { return this.queue[0]; } public toArray(): T[] { return this.queue; } public dispose(): void {} public async waitTillProcessingDone(): Promise<{ count: number; duration: number }> { throw new Error("NYI"); } constructor() { super(); } } /** * Mock implementation of IDeltaManager for testing that creates mock DeltaQueues for testing * @legacy @beta */ export class MockDeltaManager extends TypedEventEmitter implements IDeltaManager { public get disposed(): any { return undefined; } public readOnlyInfo: ReadOnlyInfo = { readonly: false }; public readonly clientType: string = undefined as any; public readonly clientDetails: IClientDetails = {} as any; public get IDeltaSender(): this { return this; } private readonly _inbound: MockDeltaQueue = undefined as any; private readonly _inboundSignal: MockDeltaQueue = undefined as any; private readonly _outbound: MockDeltaQueue = undefined as any; public get inbound(): MockDeltaQueue { return this._inbound; } public get outbound(): MockDeltaQueue { return this._outbound; } public get inboundSignal(): MockDeltaQueue { return this._inboundSignal; } public minimumSequenceNumber = 0; public lastSequenceNumber = 0; public lastMessage: ISequencedDocumentMessage | undefined; readonly lastKnownSeqNumber = 0; public initialSequenceNumber = 0; public hasCheckpointSequenceNumber = false; public get version(): string { return undefined as any as string; } public readonly maxMessageSize: number = 0; public get serviceConfiguration(): IClientConfiguration { return undefined as any as IClientConfiguration; } public active: boolean = true; public close(): void {} public submitSignal(content: any): void {} public flush(): void {} public submit( type: MessageType, contents: any, batch = false, localOpMetadata: any, ): number { return 0; } public dispose(): void { this.removeAllListeners(); } public clientSequenceNumber = 0; public process(message: ISequencedDocumentMessage): void { assert(message.sequenceNumber !== undefined, "message missing sequenceNumber"); assert( message.minimumSequenceNumber !== undefined, "message missing minimumSequenceNumber", ); this.lastSequenceNumber = message.sequenceNumber; this.lastMessage = message; this.minimumSequenceNumber = message.minimumSequenceNumber; this.emit("op", message); } constructor(private readonly getClientId?: () => string | undefined) { super(); this._inbound = new MockDeltaQueue(); this._outbound = new MockDeltaQueue(); this._outbound.on("push", (messages: IDocumentMessage[]) => { messages.forEach((message: IDocumentMessage) => { // eslint-disable-next-line @typescript-eslint/consistent-type-assertions this._inbound.push({ ...message, clientId: this.getClientId?.() ?? null, // ! sequenceNumber and minimumSequenceNumber should be added by MockContainerRuntimeFactory } as ISequencedDocumentMessage); }); }); this._inboundSignal = new MockDeltaQueue(); } }