@fluidframework/test-utils 1.2.6 → 2.0.0-dev.1.3.0.96595

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/DriverWrappers.d.ts +29 -0
  2. package/dist/DriverWrappers.d.ts.map +1 -0
  3. package/dist/DriverWrappers.js +54 -0
  4. package/dist/DriverWrappers.js.map +1 -0
  5. package/dist/TestConfigs.d.ts +7 -0
  6. package/dist/TestConfigs.d.ts.map +1 -0
  7. package/dist/TestConfigs.js +15 -0
  8. package/dist/TestConfigs.js.map +1 -0
  9. package/dist/TestSummaryUtils.d.ts +18 -0
  10. package/dist/TestSummaryUtils.d.ts.map +1 -0
  11. package/dist/TestSummaryUtils.js +95 -0
  12. package/dist/TestSummaryUtils.js.map +1 -0
  13. package/dist/index.d.ts +3 -0
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +3 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/loaderContainerTracker.d.ts +25 -9
  18. package/dist/loaderContainerTracker.d.ts.map +1 -1
  19. package/dist/loaderContainerTracker.js +58 -17
  20. package/dist/loaderContainerTracker.js.map +1 -1
  21. package/dist/localCodeLoader.d.ts.map +1 -1
  22. package/dist/localCodeLoader.js +6 -14
  23. package/dist/localCodeLoader.js.map +1 -1
  24. package/dist/packageVersion.d.ts +1 -1
  25. package/dist/packageVersion.d.ts.map +1 -1
  26. package/dist/packageVersion.js +1 -1
  27. package/dist/packageVersion.js.map +1 -1
  28. package/dist/testFluidObject.d.ts +16 -9
  29. package/dist/testFluidObject.d.ts.map +1 -1
  30. package/dist/testFluidObject.js +16 -9
  31. package/dist/testFluidObject.js.map +1 -1
  32. package/dist/testObjectProvider.d.ts +3 -2
  33. package/dist/testObjectProvider.d.ts.map +1 -1
  34. package/dist/testObjectProvider.js +9 -2
  35. package/dist/testObjectProvider.js.map +1 -1
  36. package/dist/timeoutUtils.d.ts +2 -0
  37. package/dist/timeoutUtils.d.ts.map +1 -1
  38. package/dist/timeoutUtils.js +8 -2
  39. package/dist/timeoutUtils.js.map +1 -1
  40. package/package.json +29 -28
  41. package/src/DriverWrappers.ts +77 -0
  42. package/src/TestConfigs.ts +14 -0
  43. package/src/TestSummaryUtils.ts +144 -0
  44. package/src/index.ts +3 -0
  45. package/src/loaderContainerTracker.ts +66 -17
  46. package/src/localCodeLoader.ts +6 -14
  47. package/src/packageVersion.ts +1 -1
  48. package/src/testFluidObject.ts +16 -9
  49. package/src/testObjectProvider.ts +10 -3
  50. package/src/timeoutUtils.ts +9 -1
  51. package/tsconfig.json +1 -1
@@ -0,0 +1,29 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ import { IDocumentService, IDocumentServiceFactory, IDocumentStorageService, ISummaryContext } from "@fluidframework/driver-definitions";
6
+ import { ISummaryTree } from "@fluidframework/protocol-definitions";
7
+ /**
8
+ * Wraps the given IDocumentStorageService to override the `uploadSummaryWithContext` method. It calls the
9
+ * `uploadSummaryCb` whenever a summary is uploaded by the client. The summary context can be updated in the
10
+ * callback before it is uploaded to the server.
11
+ */
12
+ export declare function wrapDocumentStorageService(innerDocStorageService: IDocumentStorageService, uploadSummaryCb: (summaryTree: ISummaryTree, context: ISummaryContext) => ISummaryContext): IDocumentStorageService;
13
+ /**
14
+ * Wraps the given IDocumentService to override the `connectToStorage` method. The intent is to plumb the
15
+ * `uploadSummaryCb` to the IDocumentStorageService so that it is called whenever a summary is uploaded by
16
+ * the client.
17
+ * The document storage service that is created in `connectToStorage` is wrapped by calling `wrapDocumentStorageService`
18
+ * to pass in the `uploadSummaryCb`.
19
+ */
20
+ export declare function wrapDocumentService(innerDocService: IDocumentService, uploadSummaryCb: (summaryTree: ISummaryTree, context: ISummaryContext) => ISummaryContext): IDocumentService;
21
+ /**
22
+ * Wraps the given IDocumentServiceFactory to override the `createDocumentService` method. The intent is to plumb
23
+ * the `uploadSummaryCb` all the way to the IDocumentStorageService so that it is called whenever a summary is
24
+ * uploaded by the client.
25
+ * The document service that is created in `createDocumentService` is wrapped by calling `wrapDocumentService` to
26
+ * pass in the `uploadSummaryCb`.
27
+ */
28
+ export declare function wrapDocumentServiceFactory(innerDocServiceFactory: IDocumentServiceFactory, uploadSummaryCb: (summaryTree: ISummaryTree, context: ISummaryContext) => ISummaryContext): IDocumentServiceFactory;
29
+ //# sourceMappingURL=DriverWrappers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DriverWrappers.d.ts","sourceRoot":"","sources":["../src/DriverWrappers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACH,gBAAgB,EAChB,uBAAuB,EACvB,uBAAuB,EAEvB,eAAe,EAClB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAEpE;;;;GAIG;AACH,wBAAgB,0BAA0B,CACtC,sBAAsB,EAAE,uBAAuB,EAC/C,eAAe,EAAE,CAAC,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,eAAe,KAAK,eAAe,2BAW5F;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAC/B,eAAe,EAAE,gBAAgB,EACjC,eAAe,EAAE,CAAC,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,eAAe,KAAK,eAAe,oBAQ5F;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACtC,sBAAsB,EAAE,uBAAuB,EAC/C,eAAe,EAAE,CAAC,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,eAAe,KAAK,eAAe,2BAa5F"}
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ /*!
3
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
+ * Licensed under the MIT License.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.wrapDocumentServiceFactory = exports.wrapDocumentService = exports.wrapDocumentStorageService = void 0;
8
+ /**
9
+ * Wraps the given IDocumentStorageService to override the `uploadSummaryWithContext` method. It calls the
10
+ * `uploadSummaryCb` whenever a summary is uploaded by the client. The summary context can be updated in the
11
+ * callback before it is uploaded to the server.
12
+ */
13
+ function wrapDocumentStorageService(innerDocStorageService, uploadSummaryCb) {
14
+ const outerDocStorageService = Object.create(innerDocStorageService);
15
+ outerDocStorageService.uploadSummaryWithContext = async (summary, context) => {
16
+ const newContext = uploadSummaryCb(summary, context);
17
+ return innerDocStorageService.uploadSummaryWithContext(summary, newContext);
18
+ };
19
+ return outerDocStorageService;
20
+ }
21
+ exports.wrapDocumentStorageService = wrapDocumentStorageService;
22
+ /**
23
+ * Wraps the given IDocumentService to override the `connectToStorage` method. The intent is to plumb the
24
+ * `uploadSummaryCb` to the IDocumentStorageService so that it is called whenever a summary is uploaded by
25
+ * the client.
26
+ * The document storage service that is created in `connectToStorage` is wrapped by calling `wrapDocumentStorageService`
27
+ * to pass in the `uploadSummaryCb`.
28
+ */
29
+ function wrapDocumentService(innerDocService, uploadSummaryCb) {
30
+ const outerDocService = Object.create(innerDocService);
31
+ outerDocService.connectToStorage = async () => {
32
+ const storageService = await innerDocService.connectToStorage();
33
+ return wrapDocumentStorageService(storageService, uploadSummaryCb);
34
+ };
35
+ return outerDocService;
36
+ }
37
+ exports.wrapDocumentService = wrapDocumentService;
38
+ /**
39
+ * Wraps the given IDocumentServiceFactory to override the `createDocumentService` method. The intent is to plumb
40
+ * the `uploadSummaryCb` all the way to the IDocumentStorageService so that it is called whenever a summary is
41
+ * uploaded by the client.
42
+ * The document service that is created in `createDocumentService` is wrapped by calling `wrapDocumentService` to
43
+ * pass in the `uploadSummaryCb`.
44
+ */
45
+ function wrapDocumentServiceFactory(innerDocServiceFactory, uploadSummaryCb) {
46
+ const outerDocServiceFactory = Object.create(innerDocServiceFactory);
47
+ outerDocServiceFactory.createDocumentService = async (resolvedUrl, logger, clientIsSummarizer) => {
48
+ const documentService = await innerDocServiceFactory.createDocumentService(resolvedUrl, logger, clientIsSummarizer);
49
+ return wrapDocumentService(documentService, uploadSummaryCb);
50
+ };
51
+ return outerDocServiceFactory;
52
+ }
53
+ exports.wrapDocumentServiceFactory = wrapDocumentServiceFactory;
54
+ //# sourceMappingURL=DriverWrappers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DriverWrappers.js","sourceRoot":"","sources":["../src/DriverWrappers.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAYH;;;;GAIG;AACH,SAAgB,0BAA0B,CACtC,sBAA+C,EAC/C,eAAyF;IAEzF,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAA4B,CAAC;IAChG,sBAAsB,CAAC,wBAAwB,GAAG,KAAK,EACnD,OAAqB,EACrB,OAAwB,EACT,EAAE;QACjB,MAAM,UAAU,GAAG,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACrD,OAAO,sBAAsB,CAAC,wBAAwB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAChF,CAAC,CAAC;IACF,OAAO,sBAAsB,CAAC;AAClC,CAAC;AAbD,gEAaC;AAED;;;;;;GAMG;AACH,SAAgB,mBAAmB,CAC/B,eAAiC,EACjC,eAAyF;IAEzF,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,eAAe,CAAqB,CAAC;IAC3E,eAAe,CAAC,gBAAgB,GAAG,KAAK,IAAsC,EAAE;QAC5E,MAAM,cAAc,GAAG,MAAM,eAAe,CAAC,gBAAgB,EAAE,CAAC;QAChE,OAAO,0BAA0B,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;IACvE,CAAC,CAAC;IACF,OAAO,eAAe,CAAC;AAC3B,CAAC;AAVD,kDAUC;AAED;;;;;;GAMG;AACH,SAAgB,0BAA0B,CACtC,sBAA+C,EAC/C,eAAyF;IAEzF,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAA4B,CAAC;IAChG,sBAAsB,CAAC,qBAAqB,GAAG,KAAK,EAChD,WAAyB,EACzB,MAA6B,EAC7B,kBAA4B,EACH,EAAE;QAC3B,MAAM,eAAe,GAAG,MAAM,sBAAsB,CAAC,qBAAqB,CACtE,WAAW,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAC;QAC7C,OAAO,mBAAmB,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;IACjE,CAAC,CAAC;IACF,OAAO,sBAAsB,CAAC;AAClC,CAAC;AAfD,gEAeC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryBaseLogger } from \"@fluidframework/common-definitions\";\nimport {\n IDocumentService,\n IDocumentServiceFactory,\n IDocumentStorageService,\n IResolvedUrl,\n ISummaryContext,\n} from \"@fluidframework/driver-definitions\";\nimport { ISummaryTree } from \"@fluidframework/protocol-definitions\";\n\n/**\n * Wraps the given IDocumentStorageService to override the `uploadSummaryWithContext` method. It calls the\n * `uploadSummaryCb` whenever a summary is uploaded by the client. The summary context can be updated in the\n * callback before it is uploaded to the server.\n */\nexport function wrapDocumentStorageService(\n innerDocStorageService: IDocumentStorageService,\n uploadSummaryCb: (summaryTree: ISummaryTree, context: ISummaryContext) => ISummaryContext,\n) {\n const outerDocStorageService = Object.create(innerDocStorageService) as IDocumentStorageService;\n outerDocStorageService.uploadSummaryWithContext = async (\n summary: ISummaryTree,\n context: ISummaryContext,\n ): Promise<string> => {\n const newContext = uploadSummaryCb(summary, context);\n return innerDocStorageService.uploadSummaryWithContext(summary, newContext);\n };\n return outerDocStorageService;\n}\n\n/**\n * Wraps the given IDocumentService to override the `connectToStorage` method. The intent is to plumb the\n * `uploadSummaryCb` to the IDocumentStorageService so that it is called whenever a summary is uploaded by\n * the client.\n * The document storage service that is created in `connectToStorage` is wrapped by calling `wrapDocumentStorageService`\n * to pass in the `uploadSummaryCb`.\n */\nexport function wrapDocumentService(\n innerDocService: IDocumentService,\n uploadSummaryCb: (summaryTree: ISummaryTree, context: ISummaryContext) => ISummaryContext,\n) {\n const outerDocService = Object.create(innerDocService) as IDocumentService;\n outerDocService.connectToStorage = async (): Promise<IDocumentStorageService> => {\n const storageService = await innerDocService.connectToStorage();\n return wrapDocumentStorageService(storageService, uploadSummaryCb);\n };\n return outerDocService;\n}\n\n/**\n * Wraps the given IDocumentServiceFactory to override the `createDocumentService` method. The intent is to plumb\n * the `uploadSummaryCb` all the way to the IDocumentStorageService so that it is called whenever a summary is\n * uploaded by the client.\n * The document service that is created in `createDocumentService` is wrapped by calling `wrapDocumentService` to\n * pass in the `uploadSummaryCb`.\n */\nexport function wrapDocumentServiceFactory(\n innerDocServiceFactory: IDocumentServiceFactory,\n uploadSummaryCb: (summaryTree: ISummaryTree, context: ISummaryContext) => ISummaryContext,\n) {\n const outerDocServiceFactory = Object.create(innerDocServiceFactory) as IDocumentServiceFactory;\n outerDocServiceFactory.createDocumentService = async (\n resolvedUrl: IResolvedUrl,\n logger?: ITelemetryBaseLogger,\n clientIsSummarizer?: boolean,\n ): Promise<IDocumentService> => {\n const documentService = await innerDocServiceFactory.createDocumentService(\n resolvedUrl, logger, clientIsSummarizer);\n return wrapDocumentService(documentService, uploadSummaryCb);\n };\n return outerDocServiceFactory;\n}\n"]}
@@ -0,0 +1,7 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ import { ConfigTypes, IConfigProviderBase } from "@fluidframework/telemetry-utils";
6
+ export declare const mockConfigProvider: (settings?: Record<string, ConfigTypes>) => IConfigProviderBase;
7
+ //# sourceMappingURL=TestConfigs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestConfigs.d.ts","sourceRoot":"","sources":["../src/TestConfigs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAEnF,eAAO,MAAM,kBAAkB,cAAe,OAAO,MAAM,EAAE,WAAW,CAAC,KAAQ,mBAM/E,CAAC"}
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ /*!
3
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
+ * Licensed under the MIT License.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.mockConfigProvider = void 0;
8
+ exports.mockConfigProvider = ((settings = {}) => {
9
+ settings["Fluid.GarbageCollection.TrackGCState"] = "true";
10
+ settings["Fluid.GarbageCollection.WriteDataAtRoot"] = "true";
11
+ return {
12
+ getRawConfig: (name) => settings[name],
13
+ };
14
+ });
15
+ //# sourceMappingURL=TestConfigs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestConfigs.js","sourceRoot":"","sources":["../src/TestConfigs.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAIU,QAAA,kBAAkB,GAAG,CAAC,CAAC,WAAwC,EAAE,EAAuB,EAAE;IACnG,QAAQ,CAAC,sCAAsC,CAAC,GAAG,MAAM,CAAC;IAC1D,QAAQ,CAAC,yCAAyC,CAAC,GAAG,MAAM,CAAC;IAC7D,OAAO;QACH,YAAY,EAAE,CAAC,IAAY,EAAe,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC;KAC9D,CAAC;AACN,CAAC,CAAC,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ConfigTypes, IConfigProviderBase } from \"@fluidframework/telemetry-utils\";\n\nexport const mockConfigProvider = ((settings: Record<string, ConfigTypes> = {}): IConfigProviderBase => {\n settings[\"Fluid.GarbageCollection.TrackGCState\"] = \"true\";\n settings[\"Fluid.GarbageCollection.WriteDataAtRoot\"] = \"true\";\n return {\n getRawConfig: (name: string): ConfigTypes => settings[name],\n };\n});\n"]}
@@ -0,0 +1,18 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ import { ContainerRuntimeFactoryWithDefaultDataStore } from "@fluidframework/aqueduct";
6
+ import { IContainer } from "@fluidframework/container-definitions";
7
+ import { IGCRuntimeOptions, ISummarizer } from "@fluidframework/container-runtime";
8
+ import { IFluidDataStoreFactory, NamedFluidDataStoreRegistryEntries } from "@fluidframework/runtime-definitions";
9
+ import { IConfigProviderBase } from "@fluidframework/telemetry-utils";
10
+ import { ITestObjectProvider } from "./testObjectProvider";
11
+ export declare function createSummarizerFromFactory(provider: ITestObjectProvider, container: IContainer, dataStoreFactory: IFluidDataStoreFactory, summaryVersion?: string, containerRuntimeFactoryType?: typeof ContainerRuntimeFactoryWithDefaultDataStore, registryEntries?: NamedFluidDataStoreRegistryEntries): Promise<ISummarizer>;
12
+ export declare function createSummarizer(provider: ITestObjectProvider, container: IContainer, summaryVersion?: string, gcOptions?: IGCRuntimeOptions, configProvider?: IConfigProviderBase): Promise<ISummarizer>;
13
+ export declare function summarizeNow(summarizer: ISummarizer, reason?: string): Promise<{
14
+ summaryTree: import("@fluidframework/protocol-definitions").ISummaryTree;
15
+ summaryVersion: string;
16
+ }>;
17
+ export declare function waitForContainerConnection(container: IContainer): Promise<void>;
18
+ //# sourceMappingURL=TestSummaryUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestSummaryUtils.d.ts","sourceRoot":"","sources":["../src/TestSummaryUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,2CAA2C,EAAE,MAAM,0BAA0B,CAAC;AAEvF,OAAO,EAAE,UAAU,EAA6B,MAAM,uCAAuC,CAAC;AAE9F,OAAO,EACH,iBAAiB,EACjB,WAAW,EAEd,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAEH,sBAAsB,EACtB,kCAAkC,EACrC,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAwB,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AA6CjF,wBAAsB,2BAA2B,CAC7C,QAAQ,EAAE,mBAAmB,EAC7B,SAAS,EAAE,UAAU,EACrB,gBAAgB,EAAE,sBAAsB,EACxC,cAAc,CAAC,EAAE,MAAM,EACvB,2BAA2B,qDAA8C,EACzE,eAAe,CAAC,EAAE,kCAAkC,GACrD,OAAO,CAAC,WAAW,CAAC,CAoBtB;AAED,wBAAsB,gBAAgB,CAClC,QAAQ,EAAE,mBAAmB,EAC7B,SAAS,EAAE,UAAU,EACrB,cAAc,CAAC,EAAE,MAAM,EACvB,SAAS,CAAC,EAAE,iBAAiB,EAC7B,cAAc,GAAE,mBAA0C,GAC3D,OAAO,CAAC,WAAW,CAAC,CAWtB;AAED,wBAAsB,YAAY,CAAC,UAAU,EAAE,WAAW,EAAE,MAAM,GAAE,MAA0B;;;GAqB7F;AAED,wBAAsB,0BAA0B,CAAC,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAIrF"}
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ /*!
3
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
+ * Licensed under the MIT License.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.waitForContainerConnection = exports.summarizeNow = exports.createSummarizer = exports.createSummarizerFromFactory = void 0;
8
+ const aqueduct_1 = require("@fluidframework/aqueduct");
9
+ const common_utils_1 = require("@fluidframework/common-utils");
10
+ const container_definitions_1 = require("@fluidframework/container-definitions");
11
+ const container_loader_1 = require("@fluidframework/container-loader");
12
+ const driver_definitions_1 = require("@fluidframework/driver-definitions");
13
+ const runtime_utils_1 = require("@fluidframework/runtime-utils");
14
+ const TestConfigs_1 = require("./TestConfigs");
15
+ const summarizerClientType = "summarizer";
16
+ async function createSummarizerCore(container, loader, summaryVersion) {
17
+ const absoluteUrl = await container.getAbsoluteUrl("");
18
+ if (absoluteUrl === undefined) {
19
+ throw new Error("URL could not be resolved");
20
+ }
21
+ const request = {
22
+ headers: {
23
+ [container_definitions_1.LoaderHeader.cache]: false,
24
+ [container_definitions_1.LoaderHeader.clientDetails]: {
25
+ capabilities: { interactive: false },
26
+ type: summarizerClientType,
27
+ },
28
+ [driver_definitions_1.DriverHeader.summarizingClient]: true,
29
+ [container_definitions_1.LoaderHeader.reconnect]: false,
30
+ [container_definitions_1.LoaderHeader.version]: summaryVersion,
31
+ },
32
+ url: absoluteUrl,
33
+ };
34
+ const summarizerContainer = await loader.resolve(request);
35
+ await waitForContainerConnection(summarizerContainer);
36
+ const fluidObject = await (0, runtime_utils_1.requestFluidObject)(summarizerContainer, { url: "_summarizer" });
37
+ if (fluidObject.ISummarizer === undefined) {
38
+ throw new Error("Fluid object does not implement ISummarizer");
39
+ }
40
+ return fluidObject.ISummarizer;
41
+ }
42
+ const defaultSummaryOptions = {
43
+ summaryConfigOverrides: {
44
+ state: "disableHeuristics",
45
+ maxAckWaitTime: 10000,
46
+ maxOpsSinceLastSummary: 7000,
47
+ initialSummarizerDelayMs: 0,
48
+ summarizerClientElection: false,
49
+ },
50
+ };
51
+ async function createSummarizerFromFactory(provider, container, dataStoreFactory, summaryVersion, containerRuntimeFactoryType = aqueduct_1.ContainerRuntimeFactoryWithDefaultDataStore, registryEntries) {
52
+ const innerRequestHandler = async (request, runtime) => runtime.IFluidHandleContext.resolveHandle(request);
53
+ const runtimeFactory = new containerRuntimeFactoryType(dataStoreFactory, registryEntries !== null && registryEntries !== void 0 ? registryEntries : [
54
+ [dataStoreFactory.type, Promise.resolve(dataStoreFactory)],
55
+ ], undefined, [innerRequestHandler], { summaryOptions: defaultSummaryOptions });
56
+ const loader = provider.createLoader([[provider.defaultCodeDetails, runtimeFactory]], { configProvider: (0, TestConfigs_1.mockConfigProvider)() });
57
+ return createSummarizerCore(container, loader, summaryVersion);
58
+ }
59
+ exports.createSummarizerFromFactory = createSummarizerFromFactory;
60
+ async function createSummarizer(provider, container, summaryVersion, gcOptions, configProvider = (0, TestConfigs_1.mockConfigProvider)()) {
61
+ const testContainerConfig = {
62
+ runtimeOptions: {
63
+ summaryOptions: defaultSummaryOptions,
64
+ gcOptions,
65
+ },
66
+ loaderProps: { configProvider },
67
+ };
68
+ const loader = provider.makeTestLoader(testContainerConfig);
69
+ return createSummarizerCore(container, loader, summaryVersion);
70
+ }
71
+ exports.createSummarizer = createSummarizer;
72
+ async function summarizeNow(summarizer, reason = "end-to-end test") {
73
+ const result = summarizer.summarizeOnDemand({ reason });
74
+ const submitResult = await result.summarySubmitted;
75
+ (0, common_utils_1.assert)(submitResult.success, "on-demand summary should submit");
76
+ (0, common_utils_1.assert)(submitResult.data.stage === "submit", "on-demand summary submitted data stage should be submit");
77
+ (0, common_utils_1.assert)(submitResult.data.summaryTree !== undefined, "summary tree should exist");
78
+ const broadcastResult = await result.summaryOpBroadcasted;
79
+ (0, common_utils_1.assert)(broadcastResult.success, "summary op should be broadcast");
80
+ const ackNackResult = await result.receivedSummaryAckOrNack;
81
+ (0, common_utils_1.assert)(ackNackResult.success, "summary op should be acked");
82
+ await new Promise((resolve) => process.nextTick(resolve));
83
+ return {
84
+ summaryTree: submitResult.data.summaryTree,
85
+ summaryVersion: ackNackResult.data.summaryAckOp.contents.handle,
86
+ };
87
+ }
88
+ exports.summarizeNow = summarizeNow;
89
+ async function waitForContainerConnection(container) {
90
+ if (container.connectionState !== container_loader_1.ConnectionState.Connected) {
91
+ return new Promise((resolve) => container.once("connected", () => resolve()));
92
+ }
93
+ }
94
+ exports.waitForContainerConnection = waitForContainerConnection;
95
+ //# sourceMappingURL=TestSummaryUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestSummaryUtils.js","sourceRoot":"","sources":["../src/TestSummaryUtils.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ContainerRuntimeFactoryWithDefaultDataStore } from \"@fluidframework/aqueduct\";\nimport { assert } from \"@fluidframework/common-utils\";\nimport { IContainer, IHostLoader, LoaderHeader } from \"@fluidframework/container-definitions\";\nimport { ConnectionState } from \"@fluidframework/container-loader\";\nimport {\n IGCRuntimeOptions,\n ISummarizer,\n ISummaryRuntimeOptions,\n} from \"@fluidframework/container-runtime\";\nimport { FluidObject, IRequest } from \"@fluidframework/core-interfaces\";\nimport { DriverHeader } from \"@fluidframework/driver-definitions\";\nimport {\n IContainerRuntimeBase,\n IFluidDataStoreFactory,\n NamedFluidDataStoreRegistryEntries,\n} from \"@fluidframework/runtime-definitions\";\nimport { requestFluidObject } from \"@fluidframework/runtime-utils\";\nimport { IConfigProviderBase } from \"@fluidframework/telemetry-utils\";\nimport { ITestContainerConfig, ITestObjectProvider } from \"./testObjectProvider\";\nimport { mockConfigProvider } from \"./TestConfigs\";\n\nconst summarizerClientType = \"summarizer\";\n\nasync function createSummarizerCore(container: IContainer, loader: IHostLoader, summaryVersion?: string) {\n const absoluteUrl = await container.getAbsoluteUrl(\"\");\n if (absoluteUrl === undefined) {\n throw new Error(\"URL could not be resolved\");\n }\n\n const request: IRequest = {\n headers: {\n [LoaderHeader.cache]: false,\n [LoaderHeader.clientDetails]: {\n capabilities: { interactive: false },\n type: summarizerClientType,\n },\n [DriverHeader.summarizingClient]: true,\n [LoaderHeader.reconnect]: false,\n [LoaderHeader.version]: summaryVersion,\n },\n url: absoluteUrl,\n };\n const summarizerContainer = await loader.resolve(request);\n await waitForContainerConnection(summarizerContainer);\n\n const fluidObject =\n await requestFluidObject<FluidObject<ISummarizer>>(summarizerContainer, { url: \"_summarizer\" });\n if (fluidObject.ISummarizer === undefined) {\n throw new Error(\"Fluid object does not implement ISummarizer\");\n }\n return fluidObject.ISummarizer;\n}\n\nconst defaultSummaryOptions: ISummaryRuntimeOptions = {\n summaryConfigOverrides: {\n state: \"disableHeuristics\",\n maxAckWaitTime: 10000,\n maxOpsSinceLastSummary: 7000,\n initialSummarizerDelayMs: 0,\n summarizerClientElection: false,\n },\n};\n\nexport async function createSummarizerFromFactory(\n provider: ITestObjectProvider,\n container: IContainer,\n dataStoreFactory: IFluidDataStoreFactory,\n summaryVersion?: string,\n containerRuntimeFactoryType = ContainerRuntimeFactoryWithDefaultDataStore,\n registryEntries?: NamedFluidDataStoreRegistryEntries,\n): Promise<ISummarizer> {\n const innerRequestHandler = async (request: IRequest, runtime: IContainerRuntimeBase) =>\n runtime.IFluidHandleContext.resolveHandle(request);\n const runtimeFactory = new containerRuntimeFactoryType(\n dataStoreFactory,\n registryEntries ??\n [\n [dataStoreFactory.type, Promise.resolve(dataStoreFactory)],\n ],\n undefined,\n [innerRequestHandler],\n { summaryOptions: defaultSummaryOptions },\n );\n\n const loader = provider.createLoader(\n [[provider.defaultCodeDetails, runtimeFactory]],\n { configProvider: mockConfigProvider() },\n );\n\n return createSummarizerCore(container, loader, summaryVersion);\n}\n\nexport async function createSummarizer(\n provider: ITestObjectProvider,\n container: IContainer,\n summaryVersion?: string,\n gcOptions?: IGCRuntimeOptions,\n configProvider: IConfigProviderBase = mockConfigProvider(),\n): Promise<ISummarizer> {\n const testContainerConfig: ITestContainerConfig = {\n runtimeOptions: {\n summaryOptions: defaultSummaryOptions,\n gcOptions,\n },\n loaderProps: { configProvider },\n };\n\n const loader = provider.makeTestLoader(testContainerConfig);\n return createSummarizerCore(container, loader, summaryVersion);\n}\n\nexport async function summarizeNow(summarizer: ISummarizer, reason: string = \"end-to-end test\") {\n const result = summarizer.summarizeOnDemand({ reason });\n\n const submitResult = await result.summarySubmitted;\n assert(submitResult.success, \"on-demand summary should submit\");\n assert(submitResult.data.stage === \"submit\",\n \"on-demand summary submitted data stage should be submit\");\n assert(submitResult.data.summaryTree !== undefined, \"summary tree should exist\");\n\n const broadcastResult = await result.summaryOpBroadcasted;\n assert(broadcastResult.success, \"summary op should be broadcast\");\n\n const ackNackResult = await result.receivedSummaryAckOrNack;\n assert(ackNackResult.success, \"summary op should be acked\");\n\n await new Promise((resolve) => process.nextTick(resolve));\n\n return {\n summaryTree: submitResult.data.summaryTree,\n summaryVersion: ackNackResult.data.summaryAckOp.contents.handle,\n };\n}\n\nexport async function waitForContainerConnection(container: IContainer): Promise<void> {\n if (container.connectionState !== ConnectionState.Connected) {\n return new Promise((resolve) => container.once(\"connected\", () => resolve()));\n }\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -11,4 +11,7 @@ export * from "./retry";
11
11
  export * from "./testContainerRuntimeFactory";
12
12
  export * from "./testFluidObject";
13
13
  export * from "./timeoutUtils";
14
+ export * from "./DriverWrappers";
15
+ export * from "./TestSummaryUtils";
16
+ export * from "./TestConfigs";
14
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,SAAS,CAAC;AACxB,cAAc,+BAA+B,CAAC;AAC9C,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,SAAS,CAAC;AACxB,cAAc,+BAA+B,CAAC;AAC9C,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -23,4 +23,7 @@ __exportStar(require("./retry"), exports);
23
23
  __exportStar(require("./testContainerRuntimeFactory"), exports);
24
24
  __exportStar(require("./testFluidObject"), exports);
25
25
  __exportStar(require("./timeoutUtils"), exports);
26
+ __exportStar(require("./DriverWrappers"), exports);
27
+ __exportStar(require("./TestSummaryUtils"), exports);
28
+ __exportStar(require("./TestConfigs"), exports);
26
29
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;AAEH,+CAA6B;AAC7B,uDAAqC;AACrC,2DAAyC;AACzC,gDAA8B;AAC9B,oDAAkC;AAClC,0CAAwB;AACxB,gEAA8C;AAC9C,oDAAkC;AAClC,iDAA+B","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport * from \"./interfaces\";\nexport * from \"./testObjectProvider\";\nexport * from \"./loaderContainerTracker\";\nexport * from \"./localLoader\";\nexport * from \"./localCodeLoader\";\nexport * from \"./retry\";\nexport * from \"./testContainerRuntimeFactory\";\nexport * from \"./testFluidObject\";\nexport * from \"./timeoutUtils\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;AAEH,+CAA6B;AAC7B,uDAAqC;AACrC,2DAAyC;AACzC,gDAA8B;AAC9B,oDAAkC;AAClC,0CAAwB;AACxB,gEAA8C;AAC9C,oDAAkC;AAClC,iDAA+B;AAC/B,mDAAiC;AACjC,qDAAmC;AACnC,gDAA8B","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport * from \"./interfaces\";\nexport * from \"./testObjectProvider\";\nexport * from \"./loaderContainerTracker\";\nexport * from \"./localLoader\";\nexport * from \"./localCodeLoader\";\nexport * from \"./retry\";\nexport * from \"./testContainerRuntimeFactory\";\nexport * from \"./testFluidObject\";\nexport * from \"./timeoutUtils\";\nexport * from \"./DriverWrappers\";\nexport * from \"./TestSummaryUtils\";\nexport * from \"./TestConfigs\";\n"]}
@@ -34,17 +34,33 @@ export declare class LoaderContainerTracker implements IOpProcessingController {
34
34
  */
35
35
  reset(): void;
36
36
  /**
37
- * Make sure all the tracked containers are synchronized.
38
- * - No isDirty (non-readonly) containers
39
- * - No extra clientId in quorum of any container that is not tracked and still opened.
40
- * - i.e. no pending Join/Leave message.
41
- * - No unresolved proposal (minSeqNum \>= lastProposalSeqNum)
42
- * - lastSequenceNumber of all container is the same
43
- * - clientSequenceNumberObserved is the same as clientSequenceNumber sent
44
- * - this overlaps with !isDirty, but include task scheduler ops.
45
- * - Trailing NoOp is tracked and don't count as pending ops.
37
+ * Ensure all tracked containers are synchronized
46
38
  */
47
39
  ensureSynchronized(...containers: IContainer[]): Promise<void>;
40
+ /**
41
+ * Ensure all tracked containers are synchronized with a time limit
42
+ */
43
+ ensureSynchronizedWithTimeout?(timeoutDuration: number | undefined, ...containers: IContainer[]): Promise<void>;
44
+ /**
45
+ * Make sure all the tracked containers are synchronized.
46
+ *
47
+ * No isDirty (non-readonly) containers
48
+ *
49
+ * No extra clientId in quorum of any container that is not tracked and still opened.
50
+ *
51
+ * - i.e. no pending Join/Leave message.
52
+ *
53
+ * No unresolved proposal (minSeqNum \>= lastProposalSeqNum)
54
+ *
55
+ * lastSequenceNumber of all container is the same
56
+ *
57
+ * clientSequenceNumberObserved is the same as clientSequenceNumber sent
58
+ *
59
+ * - this overlaps with !isDirty, but include task scheduler ops.
60
+ *
61
+ * - Trailing NoOp is tracked and don't count as pending ops.
62
+ */
63
+ private processSynchronized;
48
64
  /**
49
65
  * Utility to calculate the set of clientId per container in quorum that is NOT associated with
50
66
  * any container we tracked, indicating there is a pending join or leave op that we need to wait.
@@ -1 +1 @@
1
- {"version":3,"file":"loaderContainerTracker.d.ts","sourceRoot":"","sources":["../src/loaderContainerTracker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,UAAU,EAAe,WAAW,EAAE,MAAM,uCAAuC,CAAC;AAI7F,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAqB/D,qBAAa,sBAAuB,YAAW,uBAAuB;IAItD,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IAHlD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0C;IACrE,OAAO,CAAC,kBAAkB,CAAa;gBAEV,qBAAqB,GAAE,OAAe;IAEnE;;;OAGG;IACI,GAAG,CAAC,UAAU,SAAS,WAAW,EAAE,MAAM,EAAE,UAAU;IAiB7D;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAoBpB;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;IAsC1B,OAAO,CAAC,iBAAiB;IAQzB;;OAEG;IACI,KAAK;IAUZ;;;;;;;;;;OAUG;IACU,kBAAkB,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAqD3D;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAyBzB;;;;;OAKG;IACH,OAAO,CAAC,4BAA4B;IA0CpC;;;;;;;OAOG;YACW,qBAAqB;IA6BnC;;;OAGG;YACW,oBAAoB;IAclC;;OAEG;IACI,gBAAgB,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAgBnD;;;OAGG;IACU,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAexD;;;;OAIG;IACU,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAIxD;;;;OAIG;IACU,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAIxD;;OAEG;YACW,YAAY;IAqC1B;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IAyBzB;;OAEG;IACH,OAAO,CAAC,UAAU;IA8DlB;;;;OAIG;IACH,OAAO,CAAC,aAAa;CAIxB"}
1
+ {"version":3,"file":"loaderContainerTracker.d.ts","sourceRoot":"","sources":["../src/loaderContainerTracker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,UAAU,EAAe,WAAW,EAAE,MAAM,uCAAuC,CAAC;AAK7F,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAyB/D,qBAAa,sBAAuB,YAAW,uBAAuB;IAItD,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IAHlD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0C;IACrE,OAAO,CAAC,kBAAkB,CAAa;gBAEV,qBAAqB,GAAE,OAAe;IAEnE;;;OAGG;IACI,GAAG,CAAC,UAAU,SAAS,WAAW,EAAE,MAAM,EAAE,UAAU;IAiB7D;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAoBpB;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;IAsC1B,OAAO,CAAC,iBAAiB;IAQzB;;OAEG;IACI,KAAK;IAUZ;;OAEG;IACU,kBAAkB,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3E;;OAEG;IACU,6BAA6B,CAAC,CAAC,eAAe,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,UAAU,EAAE,UAAU,EAAE;IAI5G;;;;;;;;;;;;;;;;;;OAkBG;YACW,mBAAmB;IA0EjC;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAyBzB;;;;;OAKG;IACH,OAAO,CAAC,4BAA4B;IA0CpC;;;;;;;OAOG;YACW,qBAAqB;IA6BnC;;;OAGG;YACW,oBAAoB;IAclC;;OAEG;IACI,gBAAgB,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAgBnD;;;OAGG;IACU,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAexD;;;;OAIG;IACU,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAIxD;;;;OAIG;IACU,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAIxD;;OAEG;YACW,YAAY;IAqC1B;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IAyBzB;;OAEG;IACH,OAAO,CAAC,UAAU;IA8DlB;;;;OAIG;IACH,OAAO,CAAC,aAAa;CAIxB"}
@@ -3,13 +3,18 @@
3
3
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
4
  * Licensed under the MIT License.
5
5
  */
6
+ /* eslint-disable @typescript-eslint/strict-boolean-expressions */
6
7
  Object.defineProperty(exports, "__esModule", { value: true });
7
8
  exports.LoaderContainerTracker = void 0;
8
9
  const common_utils_1 = require("@fluidframework/common-utils");
10
+ const driver_utils_1 = require("@fluidframework/driver-utils");
9
11
  const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
10
12
  const debug_1 = require("./debug");
13
+ const timeoutUtils_1 = require("./timeoutUtils");
11
14
  const debugOp = debug_1.debug.extend("ops");
12
15
  const debugWait = debug_1.debug.extend("wait");
16
+ // set the maximum timeout value as 5 mins
17
+ const defaultMaxTimeout = 5 * 6000;
13
18
  class LoaderContainerTracker {
14
19
  constructor(syncSummarizerClients = false) {
15
20
  this.syncSummarizerClients = syncSummarizerClients;
@@ -72,7 +77,7 @@ class LoaderContainerTracker {
72
77
  trackTrailingNoOps(container, record) {
73
78
  container.deltaManager.outbound.on("op", (messages) => {
74
79
  for (const msg of messages) {
75
- if (msg.type === protocol_definitions_1.MessageType.NoOp) {
80
+ if ((0, driver_utils_1.canBeCoalescedByService)(msg)) {
76
81
  // Track the NoOp that was sent.
77
82
  if (record.trailingNoOps === 0) {
78
83
  // record the starting sequence number of the trailing no ops if we haven't been tracking yet.
@@ -88,7 +93,7 @@ class LoaderContainerTracker {
88
93
  });
89
94
  container.deltaManager.inbound.on("push", (message) => {
90
95
  // Received the no op back, update the record if we are tracking
91
- if (message.type === protocol_definitions_1.MessageType.NoOp
96
+ if ((0, driver_utils_1.canBeCoalescedByService)(message)
92
97
  && message.clientId === container.clientId
93
98
  && record.trailingNoOps !== 0
94
99
  && record.startTrailingNoOps <= message.clientSequenceNumber) {
@@ -123,17 +128,38 @@ class LoaderContainerTracker {
123
128
  // REVIEW: do we need to unpatch the loaders?
124
129
  }
125
130
  /**
126
- * Make sure all the tracked containers are synchronized.
127
- * - No isDirty (non-readonly) containers
128
- * - No extra clientId in quorum of any container that is not tracked and still opened.
129
- * - i.e. no pending Join/Leave message.
130
- * - No unresolved proposal (minSeqNum \>= lastProposalSeqNum)
131
- * - lastSequenceNumber of all container is the same
132
- * - clientSequenceNumberObserved is the same as clientSequenceNumber sent
133
- * - this overlaps with !isDirty, but include task scheduler ops.
134
- * - Trailing NoOp is tracked and don't count as pending ops.
131
+ * Ensure all tracked containers are synchronized
135
132
  */
136
133
  async ensureSynchronized(...containers) {
134
+ await this.processSynchronized(undefined, ...containers);
135
+ }
136
+ /**
137
+ * Ensure all tracked containers are synchronized with a time limit
138
+ */
139
+ async ensureSynchronizedWithTimeout(timeoutDuration, ...containers) {
140
+ await this.processSynchronized(timeoutDuration, ...containers);
141
+ }
142
+ /**
143
+ * Make sure all the tracked containers are synchronized.
144
+ *
145
+ * No isDirty (non-readonly) containers
146
+ *
147
+ * No extra clientId in quorum of any container that is not tracked and still opened.
148
+ *
149
+ * - i.e. no pending Join/Leave message.
150
+ *
151
+ * No unresolved proposal (minSeqNum \>= lastProposalSeqNum)
152
+ *
153
+ * lastSequenceNumber of all container is the same
154
+ *
155
+ * clientSequenceNumberObserved is the same as clientSequenceNumber sent
156
+ *
157
+ * - this overlaps with !isDirty, but include task scheduler ops.
158
+ *
159
+ * - Trailing NoOp is tracked and don't count as pending ops.
160
+ */
161
+ async processSynchronized(timeoutDuration, ...containers) {
162
+ const start = Date.now();
137
163
  const resumed = this.resumeProcessing(...containers);
138
164
  let waitingSequenceNumberSynchronized = false;
139
165
  // eslint-disable-next-line no-constant-condition
@@ -159,12 +185,18 @@ class LoaderContainerTracker {
159
185
  // Only write it out once
160
186
  waitingSequenceNumberSynchronized = true;
161
187
  debugWait("Waiting for sequence number synchronized");
162
- await this.waitForAnyInboundOps(containersToApply);
188
+ await (0, timeoutUtils_1.timeoutAwait)(this.waitForAnyInboundOps(containersToApply), {
189
+ durationMs: timeoutDuration ? timeoutDuration - (Date.now() - start) : defaultMaxTimeout,
190
+ errorMsg: "Timeout on waiting for sequence number synchronized",
191
+ });
163
192
  }
164
193
  }
165
194
  else {
166
195
  waitingSequenceNumberSynchronized = false;
167
- await this.waitForPendingClients(pendingClients);
196
+ await (0, timeoutUtils_1.timeoutAwait)(this.waitForPendingClients(pendingClients), {
197
+ durationMs: timeoutDuration ? timeoutDuration - (Date.now() - start) : defaultMaxTimeout,
198
+ errorMsg: "Timeout on waiting for pending join or leave op",
199
+ });
168
200
  }
169
201
  }
170
202
  else {
@@ -172,7 +204,13 @@ class LoaderContainerTracker {
172
204
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
173
205
  debugWait(`Waiting container to be saved ${dirtyContainers.map((c) => this.containers.get(c).index)}`);
174
206
  waitingSequenceNumberSynchronized = false;
175
- await Promise.all(dirtyContainers.map(async (c) => new Promise((resolve) => c.once("saved", resolve))));
207
+ const remainedDuration = timeoutDuration ? timeoutDuration - (Date.now() - start) : defaultMaxTimeout;
208
+ await Promise.all(dirtyContainers.map(async (c) => Promise.race([(0, timeoutUtils_1.timeoutPromise)((resolve) => c.once("saved", () => resolve()), {
209
+ durationMs: remainedDuration,
210
+ errorMsg: "Timeout on waiting a container to be saved",
211
+ }),
212
+ new Promise((resolve) => c.once("closed", resolve)),
213
+ ])));
176
214
  }
177
215
  // yield a turn to allow side effect of the ops we just processed execute before we check again
178
216
  await new Promise((resolve) => { setTimeout(resolve, 0); });
@@ -180,7 +218,10 @@ class LoaderContainerTracker {
180
218
  // Pause all container that was resumed
181
219
  // don't call pause if resumed is empty and pause everything, which is not what we want
182
220
  if (resumed.length !== 0) {
183
- await this.pauseProcessing(...resumed);
221
+ await (0, timeoutUtils_1.timeoutAwait)(this.pauseProcessing(...resumed), {
222
+ durationMs: timeoutDuration ? timeoutDuration - (Date.now() - start) : defaultMaxTimeout,
223
+ errorMsg: "Timeout on waiting for pausing all resumed containers",
224
+ });
184
225
  }
185
226
  debugWait("Synchronized");
186
227
  }
@@ -404,13 +445,13 @@ class LoaderContainerTracker {
404
445
  setupInOutTracker(container, inflightTracker) {
405
446
  const outHandler = (messages) => {
406
447
  for (const message of messages) {
407
- if (message.type !== protocol_definitions_1.MessageType.NoOp) {
448
+ if (!(0, driver_utils_1.canBeCoalescedByService)(message)) {
408
449
  inflightTracker.set(container, message.clientSequenceNumber);
409
450
  }
410
451
  }
411
452
  };
412
453
  const inHandler = (message) => {
413
- if (message.type !== protocol_definitions_1.MessageType.NoOp
454
+ if (!(0, driver_utils_1.canBeCoalescedByService)(message)
414
455
  && message.clientId === container.clientId
415
456
  && inflightTracker.get(container) === message.clientSequenceNumber) {
416
457
  inflightTracker.delete(container);