"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
const node_assert_1 = require("node:assert");
const internal_1 = require("@fluidframework/telemetry-utils/internal");
const internal_2 = require("@fluidframework/test-runtime-utils/internal");
const index_js_1 = require("../../index.js");
const index_js_2 = require("../../opLifecycle/index.js");
describe("OpGroupingManager", () => {
    const mockLogger = new internal_1.MockLogger();
    const createBatch = (length, hasReentrantOps, opHasMetadata = false, batchId) => ({
        ...messagesToBatch(Array.from({ length }, () => createMessage(opHasMetadata, batchId))),
        hasReentrantOps,
    });
    const messagesToBatch = (messages) => ({
        messages,
        contentSizeInBytes: messages
            .map((message) => JSON.stringify(message).length)
            .reduce((a, b) => a + b),
        referenceSequenceNumber: messages[0].referenceSequenceNumber,
    });
    const createMessage = (opHasMetadata, batchId) => {
        let metadata = opHasMetadata
            ? { flag: true }
            : undefined;
        metadata = batchId === undefined ? metadata : { ...metadata, batchId };
        return {
            metadata,
            type: index_js_1.ContainerMessageType.FluidDataStoreOp,
            contents: "0",
            referenceSequenceNumber: 0,
        };
    };
    describe("groupBatch", () => {
        it("grouped batching disabled", () => {
            node_assert_1.strict.throws(() => {
                new index_js_2.OpGroupingManager({
                    groupedBatchingEnabled: false,
                }, mockLogger).groupBatch(createBatch(5));
            });
        });
        it("grouped batching enabled", () => {
            const result = new index_js_2.OpGroupingManager({
                groupedBatchingEnabled: true,
            }, mockLogger).groupBatch(createBatch(5));
            node_assert_1.strict.strictEqual(result.messages.length, 1);
            node_assert_1.strict.deepStrictEqual(result.messages, [
                {
                    contents: '{"type":"groupedBatch","contents":[{"contents":0},{"contents":0},{"contents":0},{"contents":0},{"contents":0}]}',
                    metadata: { batchId: undefined },
                    referenceSequenceNumber: 0,
                },
            ]);
        });
        it("batchId on grouped batch", () => {
            const batchId = "batchId";
            const result = new index_js_2.OpGroupingManager({
                groupedBatchingEnabled: true,
            }, mockLogger).groupBatch(createBatch(5, false, false, batchId));
            node_assert_1.strict.strictEqual(result.messages.length, 1);
            node_assert_1.strict.strictEqual(result.messages[0].metadata?.batchId, batchId);
        });
        it("empty grouped batching disabled", () => {
            node_assert_1.strict.throws(() => {
                new index_js_2.OpGroupingManager({
                    groupedBatchingEnabled: false,
                }, mockLogger).createEmptyGroupedBatch("resubmittingBatchId", 0);
            });
        });
        it("create empty batch", () => {
            const emptyGroupedBatch = {
                type: "groupedBatch",
                contents: [],
            };
            const batchId = "batchId";
            const expectedOutboundMessage = {
                contents: '{"type":"groupedBatch","contents":[]}',
                metadata: { batchId },
                localOpMetadata: { emptyBatch: true },
                referenceSequenceNumber: 0,
                runtimeOp: undefined,
            };
            const result = new index_js_2.OpGroupingManager({
                groupedBatchingEnabled: true,
            }, mockLogger).createEmptyGroupedBatch(batchId, 0);
            node_assert_1.strict.deepStrictEqual(result.outboundBatch.messages, [expectedOutboundMessage]);
            const expectedPlaceholderMessage = {
                runtimeOp: emptyGroupedBatch,
                metadata: { batchId },
                localOpMetadata: { emptyBatch: true },
                referenceSequenceNumber: 0,
            };
            node_assert_1.strict.deepStrictEqual(result.placeholderMessage, expectedPlaceholderMessage);
        });
        it("should throw for an empty batch", () => {
            const emptyBatch = {
                messages: [],
                contentSizeInBytes: 0,
                referenceSequenceNumber: 0,
            };
            node_assert_1.strict.throws(() => {
                new index_js_2.OpGroupingManager({
                    groupedBatchingEnabled: true,
                }, mockLogger).groupBatch(emptyBatch);
            }, (0, internal_2.validateAssertionError)("Unexpected attempt to group an empty batch"));
        });
        it("singleton batch is returned as-is", () => {
            const original = createBatch(1);
            const result = new index_js_2.OpGroupingManager({
                groupedBatchingEnabled: true,
            }, mockLogger).groupBatch(original);
            node_assert_1.strict.equal(result, original, "Expected the original batch to be returned");
        });
        it("grouped batching enabled, op metadata not allowed", () => {
            node_assert_1.strict.throws(() => {
                new index_js_2.OpGroupingManager({
                    groupedBatchingEnabled: true,
                }, mockLogger).groupBatch(createBatch(5, false, true));
            });
        });
        it("grouped batching enabled, op metadata not allowed with batch id", () => {
            node_assert_1.strict.throws(() => {
                new index_js_2.OpGroupingManager({
                    groupedBatchingEnabled: true,
                }, mockLogger).groupBatch(createBatch(5, false, true, "batchId"));
            });
        });
    });
    describe("ungroupOp", () => {
        it("packed grouped op", () => {
            const opGroupingManager = new index_js_2.OpGroupingManager({
                groupedBatchingEnabled: true,
            }, mockLogger);
            const op = {
                clientSequenceNumber: 10,
                contents: {
                    type: index_js_2.OpGroupingManager.groupedBatchOp,
                    contents: [
                        {
                            contents: "1",
                        },
                        {
                            contents: "2",
                        },
                        {
                            contents: "3",
                        },
                    ],
                },
            };
            node_assert_1.strict.strictEqual((0, index_js_2.isGroupedBatch)(op), true);
            const result = opGroupingManager.ungroupOp(op);
            node_assert_1.strict.deepStrictEqual(result, [
                {
                    clientSequenceNumber: 1,
                    contents: "1",
                    compression: undefined,
                    metadata: undefined,
                },
                {
                    clientSequenceNumber: 2,
                    contents: "2",
                    compression: undefined,
                    metadata: undefined,
                },
                {
                    clientSequenceNumber: 3,
                    contents: "3",
                    compression: undefined,
                    metadata: undefined,
                },
            ]);
        });
        it("non-grouped op with grouped batching enabled", () => {
            const opGroupingManager = new index_js_2.OpGroupingManager({
                groupedBatchingEnabled: true,
            }, mockLogger);
            const op = {
                clientSequenceNumber: 10,
                contents: "1",
            };
            node_assert_1.strict.strictEqual((0, index_js_2.isGroupedBatch)(op), false);
            node_assert_1.strict.throws(() => opGroupingManager.ungroupOp(op));
        });
        it("non-grouped op with grouped batching disabled", () => {
            const opGroupingManager = new index_js_2.OpGroupingManager({
                groupedBatchingEnabled: false,
            }, mockLogger);
            const op = {
                clientSequenceNumber: 10,
                contents: "1",
            };
            node_assert_1.strict.strictEqual((0, index_js_2.isGroupedBatch)(op), false);
            node_assert_1.strict.throws(() => opGroupingManager.ungroupOp(op));
        });
        it("Ungrouping multiple times is not allowed", () => {
            const groupedBatch = {
                type: "op",
                sequenceNumber: 10,
                clientSequenceNumber: 12,
                contents: {
                    type: index_js_2.OpGroupingManager.groupedBatchOp,
                    contents: [
                        {
                            contents: {
                                type: index_js_1.ContainerMessageType.FluidDataStoreOp,
                                contents: {
                                    contents: "a",
                                },
                            },
                        },
                        {
                            contents: {
                                type: index_js_1.ContainerMessageType.FluidDataStoreOp,
                                contents: {
                                    contents: "b",
                                },
                            },
                        },
                    ],
                },
            };
            const opGroupingManager = new index_js_2.OpGroupingManager({
                groupedBatchingEnabled: false,
            }, mockLogger);
            for (const ungroupedOp of opGroupingManager.ungroupOp(groupedBatch)) {
                node_assert_1.strict.strictEqual((0, index_js_2.isGroupedBatch)(ungroupedOp), false);
                node_assert_1.strict.throws(() => opGroupingManager.ungroupOp(ungroupedOp));
            }
        });
    });
});
//# sourceMappingURL=OpGroupingManager.spec.js.map