@fluidframework/test-utils 2.0.0-dev.4.1.0.148229 → 2.0.0-dev.4.3.0.157531
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.
- package/CHANGELOG.md +5 -0
- package/dist/TestSummaryUtils.d.ts +11 -1
- package/dist/TestSummaryUtils.d.ts.map +1 -1
- package/dist/TestSummaryUtils.js +14 -1
- package/dist/TestSummaryUtils.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/loaderContainerTracker.d.ts +27 -10
- package/dist/loaderContainerTracker.d.ts.map +1 -1
- package/dist/loaderContainerTracker.js +132 -49
- package/dist/loaderContainerTracker.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/testObjectProvider.d.ts +3 -0
- package/dist/testObjectProvider.d.ts.map +1 -1
- package/dist/testObjectProvider.js +10 -9
- package/dist/testObjectProvider.js.map +1 -1
- package/package.json +24 -24
- package/src/TestSummaryUtils.ts +29 -0
- package/src/index.ts +6 -1
- package/src/loaderContainerTracker.ts +163 -51
- package/src/packageVersion.ts +1 -1
- package/src/testObjectProvider.ts +24 -11
package/CHANGELOG.md
ADDED
|
@@ -8,7 +8,7 @@ import { IGCRuntimeOptions, ISummarizer } from "@fluidframework/container-runtim
|
|
|
8
8
|
import { IFluidDataStoreFactory, NamedFluidDataStoreRegistryEntries } from "@fluidframework/runtime-definitions";
|
|
9
9
|
import { IConfigProviderBase } from "@fluidframework/telemetry-utils";
|
|
10
10
|
import { ITelemetryBaseLogger } from "@fluidframework/common-definitions";
|
|
11
|
-
import { ITestObjectProvider } from "./testObjectProvider";
|
|
11
|
+
import { ITestContainerConfig, ITestObjectProvider } from "./testObjectProvider";
|
|
12
12
|
/**
|
|
13
13
|
* Creates a summarizer client from the given container and data store factory, and returns the summarizer client's
|
|
14
14
|
* IContainer and ISummarizer.
|
|
@@ -26,6 +26,16 @@ export declare function createSummarizer(provider: ITestObjectProvider, containe
|
|
|
26
26
|
container: IContainer;
|
|
27
27
|
summarizer: ISummarizer;
|
|
28
28
|
}>;
|
|
29
|
+
/**
|
|
30
|
+
* Creates a summarizer client from the given container and returns the summarizer client's IContainer and ISummarizer.
|
|
31
|
+
* The ISummarizer can be used to generate on-demand summaries. The IContainer can be used to fetch data stores, etc.
|
|
32
|
+
*
|
|
33
|
+
* Can pass in a test config provider to enable/disable features.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createSummarizerWithTestConfig(provider: ITestObjectProvider, container: IContainer, config: ITestContainerConfig, summaryVersion?: string, logger?: ITelemetryBaseLogger): Promise<{
|
|
36
|
+
container: IContainer;
|
|
37
|
+
summarizer: ISummarizer;
|
|
38
|
+
}>;
|
|
29
39
|
/**
|
|
30
40
|
* Summarizes on demand and returns the summary tree, the version number and the reference sequence number of the
|
|
31
41
|
* submitted summary.
|
|
@@ -1 +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;AAC9F,OAAO,EACN,iBAAiB,EACjB,WAAW,EAEX,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAEN,sBAAsB,EACtB,kCAAkC,EAClC,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,
|
|
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;AAC9F,OAAO,EACN,iBAAiB,EACjB,WAAW,EAEX,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAEN,sBAAsB,EACtB,kCAAkC,EAClC,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAwDjF;;;;GAIG;AACH,wBAAsB,2BAA2B,CAChD,QAAQ,EAAE,mBAAmB,EAC7B,SAAS,EAAE,UAAU,EACrB,gBAAgB,EAAE,sBAAsB,EACxC,cAAc,CAAC,EAAE,MAAM,EACvB,2BAA2B,qDAA8C,EACzE,eAAe,CAAC,EAAE,kCAAkC,EACpD,MAAM,CAAC,EAAE,oBAAoB,GAC3B,OAAO,CAAC;IAAE,SAAS,EAAE,UAAU,CAAC;IAAC,UAAU,EAAE,WAAW,CAAA;CAAE,CAAC,CAgB7D;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACrC,QAAQ,EAAE,mBAAmB,EAC7B,SAAS,EAAE,UAAU,EACrB,cAAc,CAAC,EAAE,MAAM,EACvB,SAAS,CAAC,EAAE,iBAAiB,EAC7B,cAAc,GAAE,mBAA0C,EAC1D,MAAM,CAAC,EAAE,oBAAoB,GAC3B,OAAO,CAAC;IAAE,SAAS,EAAE,UAAU,CAAC;IAAC,UAAU,EAAE,WAAW,CAAA;CAAE,CAAC,CAU7D;AAED;;;;;GAKG;AACH,wBAAsB,8BAA8B,CACnD,QAAQ,EAAE,mBAAmB,EAC7B,SAAS,EAAE,UAAU,EACrB,MAAM,EAAE,oBAAoB,EAC5B,cAAc,CAAC,EAAE,MAAM,EACvB,MAAM,CAAC,EAAE,oBAAoB,GAC3B,OAAO,CAAC;IAAE,SAAS,EAAE,UAAU,CAAC;IAAC,UAAU,EAAE,WAAW,CAAA;CAAE,CAAC,CAe7D;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,UAAU,EAAE,WAAW,EAAE,MAAM,GAAE,MAA0B;;;;GAwB7F"}
|
package/dist/TestSummaryUtils.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.summarizeNow = exports.createSummarizer = exports.createSummarizerFromFactory = void 0;
|
|
7
|
+
exports.summarizeNow = exports.createSummarizerWithTestConfig = exports.createSummarizer = exports.createSummarizerFromFactory = void 0;
|
|
8
8
|
const aqueduct_1 = require("@fluidframework/aqueduct");
|
|
9
9
|
const common_utils_1 = require("@fluidframework/common-utils");
|
|
10
10
|
const container_definitions_1 = require("@fluidframework/container-definitions");
|
|
@@ -86,6 +86,19 @@ async function createSummarizer(provider, container, summaryVersion, gcOptions,
|
|
|
86
86
|
return createSummarizerCore(container, loader, summaryVersion);
|
|
87
87
|
}
|
|
88
88
|
exports.createSummarizer = createSummarizer;
|
|
89
|
+
/**
|
|
90
|
+
* Creates a summarizer client from the given container and returns the summarizer client's IContainer and ISummarizer.
|
|
91
|
+
* The ISummarizer can be used to generate on-demand summaries. The IContainer can be used to fetch data stores, etc.
|
|
92
|
+
*
|
|
93
|
+
* Can pass in a test config provider to enable/disable features.
|
|
94
|
+
*/
|
|
95
|
+
async function createSummarizerWithTestConfig(provider, container, config, summaryVersion, logger) {
|
|
96
|
+
var _a, _b;
|
|
97
|
+
const testContainerConfig = Object.assign(Object.assign({}, config), { runtimeOptions: Object.assign(Object.assign({}, config.runtimeOptions), { summaryOptions: defaultSummaryOptions }), loaderProps: Object.assign(Object.assign({}, config.loaderProps), { configProvider: (_b = (_a = config.loaderProps) === null || _a === void 0 ? void 0 : _a.configProvider) !== null && _b !== void 0 ? _b : (0, TestConfigs_1.mockConfigProvider)(), logger }) });
|
|
98
|
+
const loader = provider.makeTestLoader(testContainerConfig);
|
|
99
|
+
return createSummarizerCore(container, loader, summaryVersion);
|
|
100
|
+
}
|
|
101
|
+
exports.createSummarizerWithTestConfig = createSummarizerWithTestConfig;
|
|
89
102
|
/**
|
|
90
103
|
* Summarizes on demand and returns the summary tree, the version number and the reference sequence number of the
|
|
91
104
|
* submitted summary.
|
|
@@ -1 +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 {\n\tIGCRuntimeOptions,\n\tISummarizer,\n\tISummaryRuntimeOptions,\n} from \"@fluidframework/container-runtime\";\nimport { FluidObject, IRequest } from \"@fluidframework/core-interfaces\";\nimport { DriverHeader } from \"@fluidframework/driver-definitions\";\nimport {\n\tIContainerRuntimeBase,\n\tIFluidDataStoreFactory,\n\tNamedFluidDataStoreRegistryEntries,\n} from \"@fluidframework/runtime-definitions\";\nimport { requestFluidObject } from \"@fluidframework/runtime-utils\";\nimport { IConfigProviderBase } from \"@fluidframework/telemetry-utils\";\nimport { ITelemetryBaseLogger } from \"@fluidframework/common-definitions\";\nimport { ITestContainerConfig, ITestObjectProvider } from \"./testObjectProvider\";\nimport { mockConfigProvider } from \"./TestConfigs\";\nimport { waitForContainerConnection } from \"./containerUtils\";\nimport { timeoutAwait } from \"./timeoutUtils\";\n\nconst summarizerClientType = \"summarizer\";\n\nasync function createSummarizerCore(\n\tcontainer: IContainer,\n\tloader: IHostLoader,\n\tsummaryVersion?: string,\n) {\n\tconst absoluteUrl = await container.getAbsoluteUrl(\"\");\n\tif (absoluteUrl === undefined) {\n\t\tthrow new Error(\"URL could not be resolved\");\n\t}\n\n\tconst request: IRequest = {\n\t\theaders: {\n\t\t\t[LoaderHeader.cache]: false,\n\t\t\t[LoaderHeader.clientDetails]: {\n\t\t\t\tcapabilities: { interactive: false },\n\t\t\t\ttype: summarizerClientType,\n\t\t\t},\n\t\t\t[DriverHeader.summarizingClient]: true,\n\t\t\t[LoaderHeader.version]: summaryVersion,\n\t\t},\n\t\turl: absoluteUrl,\n\t};\n\tconst summarizerContainer = await loader.resolve(request);\n\tawait waitForContainerConnection(summarizerContainer);\n\n\tconst fluidObject: FluidObject<ISummarizer> | undefined = summarizerContainer.getEntryPoint\n\t\t? await summarizerContainer.getEntryPoint?.()\n\t\t: await requestFluidObject<FluidObject<ISummarizer>>(summarizerContainer, {\n\t\t\t\turl: \"_summarizer\",\n\t\t });\n\tif (fluidObject?.ISummarizer === undefined) {\n\t\tthrow new Error(\"Fluid object does not implement ISummarizer\");\n\t}\n\n\treturn {\n\t\tcontainer: summarizerContainer,\n\t\tsummarizer: fluidObject.ISummarizer,\n\t};\n}\n\nconst defaultSummaryOptions: ISummaryRuntimeOptions = {\n\tsummaryConfigOverrides: {\n\t\tstate: \"disableHeuristics\",\n\t\tmaxAckWaitTime: 10000,\n\t\tmaxOpsSinceLastSummary: 7000,\n\t\tinitialSummarizerDelayMs: 0,\n\t},\n};\n\n/**\n * Creates a summarizer client from the given container and data store factory, and returns the summarizer client's\n * IContainer and ISummarizer.\n * The ISummarizer can be used to generate on-demand summaries. The IContainer can be used to fetch data stores, etc.\n */\nexport async function createSummarizerFromFactory(\n\tprovider: ITestObjectProvider,\n\tcontainer: IContainer,\n\tdataStoreFactory: IFluidDataStoreFactory,\n\tsummaryVersion?: string,\n\tcontainerRuntimeFactoryType = ContainerRuntimeFactoryWithDefaultDataStore,\n\tregistryEntries?: NamedFluidDataStoreRegistryEntries,\n\tlogger?: ITelemetryBaseLogger,\n): Promise<{ container: IContainer; summarizer: ISummarizer }> {\n\tconst innerRequestHandler = async (request: IRequest, runtime: IContainerRuntimeBase) =>\n\t\truntime.IFluidHandleContext.resolveHandle(request);\n\tconst runtimeFactory = new containerRuntimeFactoryType(\n\t\tdataStoreFactory,\n\t\tregistryEntries ?? [[dataStoreFactory.type, Promise.resolve(dataStoreFactory)]],\n\t\tundefined,\n\t\t[innerRequestHandler],\n\t\t{ summaryOptions: defaultSummaryOptions },\n\t);\n\n\tconst loader = provider.createLoader([[provider.defaultCodeDetails, runtimeFactory]], {\n\t\tconfigProvider: mockConfigProvider(),\n\t\tlogger,\n\t});\n\treturn createSummarizerCore(container, loader, summaryVersion);\n}\n\n/**\n * Creates a summarizer client from the given container and returns the summarizer client's IContainer and ISummarizer.\n * The ISummarizer can be used to generate on-demand summaries. The IContainer can be used to fetch data stores, etc.\n */\nexport async function createSummarizer(\n\tprovider: ITestObjectProvider,\n\tcontainer: IContainer,\n\tsummaryVersion?: string,\n\tgcOptions?: IGCRuntimeOptions,\n\tconfigProvider: IConfigProviderBase = mockConfigProvider(),\n\tlogger?: ITelemetryBaseLogger,\n): Promise<{ container: IContainer; summarizer: ISummarizer }> {\n\tconst testContainerConfig: ITestContainerConfig = {\n\t\truntimeOptions: {\n\t\t\tsummaryOptions: defaultSummaryOptions,\n\t\t\tgcOptions,\n\t\t},\n\t\tloaderProps: { configProvider, logger },\n\t};\n\tconst loader = provider.makeTestLoader(testContainerConfig);\n\treturn createSummarizerCore(container, loader, summaryVersion);\n}\n\n/**\n * Summarizes on demand and returns the summary tree, the version number and the reference sequence number of the\n * submitted summary.\n */\nexport async function summarizeNow(summarizer: ISummarizer, reason: string = \"end-to-end test\") {\n\tconst result = summarizer.summarizeOnDemand({ reason });\n\n\tconst submitResult = await timeoutAwait(result.summarySubmitted);\n\tassert(submitResult.success, \"on-demand summary should submit\");\n\tassert(\n\t\tsubmitResult.data.stage === \"submit\",\n\t\t\"on-demand summary submitted data stage should be submit\",\n\t);\n\tassert(submitResult.data.summaryTree !== undefined, \"summary tree should exist\");\n\n\tconst broadcastResult = await timeoutAwait(result.summaryOpBroadcasted);\n\tassert(broadcastResult.success, \"summary op should be broadcast\");\n\n\tconst ackNackResult = await timeoutAwait(result.receivedSummaryAckOrNack);\n\tassert(ackNackResult.success, \"summary op should be acked\");\n\n\tawait new Promise((resolve) => process.nextTick(resolve));\n\n\treturn {\n\t\tsummaryTree: submitResult.data.summaryTree,\n\t\tsummaryVersion: ackNackResult.data.summaryAckOp.contents.handle,\n\t\tsummaryRefSeq: submitResult.data.referenceSequenceNumber,\n\t};\n}\n"]}
|
|
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 {\n\tIGCRuntimeOptions,\n\tISummarizer,\n\tISummaryRuntimeOptions,\n} from \"@fluidframework/container-runtime\";\nimport { FluidObject, IRequest } from \"@fluidframework/core-interfaces\";\nimport { DriverHeader } from \"@fluidframework/driver-definitions\";\nimport {\n\tIContainerRuntimeBase,\n\tIFluidDataStoreFactory,\n\tNamedFluidDataStoreRegistryEntries,\n} from \"@fluidframework/runtime-definitions\";\nimport { requestFluidObject } from \"@fluidframework/runtime-utils\";\nimport { IConfigProviderBase } from \"@fluidframework/telemetry-utils\";\nimport { ITelemetryBaseLogger } from \"@fluidframework/common-definitions\";\nimport { ITestContainerConfig, ITestObjectProvider } from \"./testObjectProvider\";\nimport { mockConfigProvider } from \"./TestConfigs\";\nimport { waitForContainerConnection } from \"./containerUtils\";\nimport { timeoutAwait } from \"./timeoutUtils\";\n\nconst summarizerClientType = \"summarizer\";\n\nasync function createSummarizerCore(\n\tcontainer: IContainer,\n\tloader: IHostLoader,\n\tsummaryVersion?: string,\n) {\n\tconst absoluteUrl = await container.getAbsoluteUrl(\"\");\n\tif (absoluteUrl === undefined) {\n\t\tthrow new Error(\"URL could not be resolved\");\n\t}\n\n\tconst request: IRequest = {\n\t\theaders: {\n\t\t\t[LoaderHeader.cache]: false,\n\t\t\t[LoaderHeader.clientDetails]: {\n\t\t\t\tcapabilities: { interactive: false },\n\t\t\t\ttype: summarizerClientType,\n\t\t\t},\n\t\t\t[DriverHeader.summarizingClient]: true,\n\t\t\t[LoaderHeader.version]: summaryVersion,\n\t\t},\n\t\turl: absoluteUrl,\n\t};\n\tconst summarizerContainer = await loader.resolve(request);\n\tawait waitForContainerConnection(summarizerContainer);\n\n\tconst fluidObject: FluidObject<ISummarizer> | undefined = summarizerContainer.getEntryPoint\n\t\t? await summarizerContainer.getEntryPoint?.()\n\t\t: await requestFluidObject<FluidObject<ISummarizer>>(summarizerContainer, {\n\t\t\t\turl: \"_summarizer\",\n\t\t });\n\tif (fluidObject?.ISummarizer === undefined) {\n\t\tthrow new Error(\"Fluid object does not implement ISummarizer\");\n\t}\n\n\treturn {\n\t\tcontainer: summarizerContainer,\n\t\tsummarizer: fluidObject.ISummarizer,\n\t};\n}\n\nconst defaultSummaryOptions: ISummaryRuntimeOptions = {\n\tsummaryConfigOverrides: {\n\t\tstate: \"disableHeuristics\",\n\t\tmaxAckWaitTime: 10000,\n\t\tmaxOpsSinceLastSummary: 7000,\n\t\tinitialSummarizerDelayMs: 0,\n\t},\n};\n\n/**\n * Creates a summarizer client from the given container and data store factory, and returns the summarizer client's\n * IContainer and ISummarizer.\n * The ISummarizer can be used to generate on-demand summaries. The IContainer can be used to fetch data stores, etc.\n */\nexport async function createSummarizerFromFactory(\n\tprovider: ITestObjectProvider,\n\tcontainer: IContainer,\n\tdataStoreFactory: IFluidDataStoreFactory,\n\tsummaryVersion?: string,\n\tcontainerRuntimeFactoryType = ContainerRuntimeFactoryWithDefaultDataStore,\n\tregistryEntries?: NamedFluidDataStoreRegistryEntries,\n\tlogger?: ITelemetryBaseLogger,\n): Promise<{ container: IContainer; summarizer: ISummarizer }> {\n\tconst innerRequestHandler = async (request: IRequest, runtime: IContainerRuntimeBase) =>\n\t\truntime.IFluidHandleContext.resolveHandle(request);\n\tconst runtimeFactory = new containerRuntimeFactoryType(\n\t\tdataStoreFactory,\n\t\tregistryEntries ?? [[dataStoreFactory.type, Promise.resolve(dataStoreFactory)]],\n\t\tundefined,\n\t\t[innerRequestHandler],\n\t\t{ summaryOptions: defaultSummaryOptions },\n\t);\n\n\tconst loader = provider.createLoader([[provider.defaultCodeDetails, runtimeFactory]], {\n\t\tconfigProvider: mockConfigProvider(),\n\t\tlogger,\n\t});\n\treturn createSummarizerCore(container, loader, summaryVersion);\n}\n\n/**\n * Creates a summarizer client from the given container and returns the summarizer client's IContainer and ISummarizer.\n * The ISummarizer can be used to generate on-demand summaries. The IContainer can be used to fetch data stores, etc.\n */\nexport async function createSummarizer(\n\tprovider: ITestObjectProvider,\n\tcontainer: IContainer,\n\tsummaryVersion?: string,\n\tgcOptions?: IGCRuntimeOptions,\n\tconfigProvider: IConfigProviderBase = mockConfigProvider(),\n\tlogger?: ITelemetryBaseLogger,\n): Promise<{ container: IContainer; summarizer: ISummarizer }> {\n\tconst testContainerConfig: ITestContainerConfig = {\n\t\truntimeOptions: {\n\t\t\tsummaryOptions: defaultSummaryOptions,\n\t\t\tgcOptions,\n\t\t},\n\t\tloaderProps: { configProvider, logger },\n\t};\n\tconst loader = provider.makeTestLoader(testContainerConfig);\n\treturn createSummarizerCore(container, loader, summaryVersion);\n}\n\n/**\n * Creates a summarizer client from the given container and returns the summarizer client's IContainer and ISummarizer.\n * The ISummarizer can be used to generate on-demand summaries. The IContainer can be used to fetch data stores, etc.\n *\n * Can pass in a test config provider to enable/disable features.\n */\nexport async function createSummarizerWithTestConfig(\n\tprovider: ITestObjectProvider,\n\tcontainer: IContainer,\n\tconfig: ITestContainerConfig,\n\tsummaryVersion?: string,\n\tlogger?: ITelemetryBaseLogger,\n): Promise<{ container: IContainer; summarizer: ISummarizer }> {\n\tconst testContainerConfig: ITestContainerConfig = {\n\t\t...config,\n\t\truntimeOptions: {\n\t\t\t...config.runtimeOptions,\n\t\t\tsummaryOptions: defaultSummaryOptions,\n\t\t},\n\t\tloaderProps: {\n\t\t\t...config.loaderProps,\n\t\t\tconfigProvider: config.loaderProps?.configProvider ?? mockConfigProvider(),\n\t\t\tlogger,\n\t\t},\n\t};\n\tconst loader = provider.makeTestLoader(testContainerConfig);\n\treturn createSummarizerCore(container, loader, summaryVersion);\n}\n\n/**\n * Summarizes on demand and returns the summary tree, the version number and the reference sequence number of the\n * submitted summary.\n */\nexport async function summarizeNow(summarizer: ISummarizer, reason: string = \"end-to-end test\") {\n\tconst result = summarizer.summarizeOnDemand({ reason });\n\n\tconst submitResult = await timeoutAwait(result.summarySubmitted);\n\tassert(submitResult.success, \"on-demand summary should submit\");\n\tassert(\n\t\tsubmitResult.data.stage === \"submit\",\n\t\t\"on-demand summary submitted data stage should be submit\",\n\t);\n\tassert(submitResult.data.summaryTree !== undefined, \"summary tree should exist\");\n\n\tconst broadcastResult = await timeoutAwait(result.summaryOpBroadcasted);\n\tassert(broadcastResult.success, \"summary op should be broadcast\");\n\n\tconst ackNackResult = await timeoutAwait(result.receivedSummaryAckOrNack);\n\tassert(ackNackResult.success, \"summary op should be acked\");\n\n\tawait new Promise((resolve) => process.nextTick(resolve));\n\n\treturn {\n\t\tsummaryTree: submitResult.data.summaryTree,\n\t\tsummaryVersion: ackNackResult.data.summaryAckOp.contents.handle,\n\t\tsummaryRefSeq: submitResult.data.referenceSequenceNumber,\n\t};\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export { mockConfigProvider } from "./TestConfigs";
|
|
|
12
12
|
export { createTestContainerRuntimeFactory, TestContainerRuntimeFactory, } from "./testContainerRuntimeFactory";
|
|
13
13
|
export { ChannelFactoryRegistry, TestFluidObject, TestFluidObjectFactory } from "./testFluidObject";
|
|
14
14
|
export { createDocumentId, DataObjectFactoryType, EventAndErrorTrackingLogger, getUnexpectedLogErrorException, IOpProcessingController, ITestContainerConfig, ITestObjectProvider, TestObjectProvider, } from "./testObjectProvider";
|
|
15
|
-
export { createSummarizer, createSummarizerFromFactory, summarizeNow } from "./TestSummaryUtils";
|
|
15
|
+
export { createSummarizer, createSummarizerFromFactory, summarizeNow, createSummarizerWithTestConfig, } from "./TestSummaryUtils";
|
|
16
16
|
export { defaultTimeoutDurationMs, timeoutAwait, timeoutPromise, TimeoutWithError, TimeoutWithValue, } from "./timeoutUtils";
|
|
17
17
|
export { waitForContainerConnection } from "./containerUtils";
|
|
18
18
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,mBAAmB,EACnB,0BAA0B,EAC1B,0BAA0B,GAC1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAChG,OAAO,EAAE,wBAAwB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EACN,iCAAiC,EACjC,2BAA2B,GAC3B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACpG,OAAO,EACN,gBAAgB,EAChB,qBAAqB,EACrB,2BAA2B,EAC3B,8BAA8B,EAC9B,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,GAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,mBAAmB,EACnB,0BAA0B,EAC1B,0BAA0B,GAC1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAChG,OAAO,EAAE,wBAAwB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EACN,iCAAiC,EACjC,2BAA2B,GAC3B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACpG,OAAO,EACN,gBAAgB,EAChB,qBAAqB,EACrB,2BAA2B,EAC3B,8BAA8B,EAC9B,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,GAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACN,gBAAgB,EAChB,2BAA2B,EAC3B,YAAY,EACZ,8BAA8B,GAC9B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACN,wBAAwB,EACxB,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,gBAAgB,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.waitForContainerConnection = exports.timeoutPromise = exports.timeoutAwait = exports.defaultTimeoutDurationMs = exports.summarizeNow = exports.createSummarizerFromFactory = exports.createSummarizer = exports.TestObjectProvider = exports.getUnexpectedLogErrorException = exports.EventAndErrorTrackingLogger = exports.DataObjectFactoryType = exports.createDocumentId = exports.TestFluidObjectFactory = exports.TestFluidObject = exports.TestContainerRuntimeFactory = exports.createTestContainerRuntimeFactory = exports.mockConfigProvider = exports.retryWithEventualValue = exports.createLoader = exports.createAndAttachContainer = exports.LocalCodeLoader = exports.LoaderContainerTracker = exports.wrapDocumentStorageService = exports.wrapDocumentServiceFactory = exports.wrapDocumentService = void 0;
|
|
7
|
+
exports.waitForContainerConnection = exports.timeoutPromise = exports.timeoutAwait = exports.defaultTimeoutDurationMs = exports.createSummarizerWithTestConfig = exports.summarizeNow = exports.createSummarizerFromFactory = exports.createSummarizer = exports.TestObjectProvider = exports.getUnexpectedLogErrorException = exports.EventAndErrorTrackingLogger = exports.DataObjectFactoryType = exports.createDocumentId = exports.TestFluidObjectFactory = exports.TestFluidObject = exports.TestContainerRuntimeFactory = exports.createTestContainerRuntimeFactory = exports.mockConfigProvider = exports.retryWithEventualValue = exports.createLoader = exports.createAndAttachContainer = exports.LocalCodeLoader = exports.LoaderContainerTracker = exports.wrapDocumentStorageService = exports.wrapDocumentServiceFactory = exports.wrapDocumentService = void 0;
|
|
8
8
|
var DriverWrappers_1 = require("./DriverWrappers");
|
|
9
9
|
Object.defineProperty(exports, "wrapDocumentService", { enumerable: true, get: function () { return DriverWrappers_1.wrapDocumentService; } });
|
|
10
10
|
Object.defineProperty(exports, "wrapDocumentServiceFactory", { enumerable: true, get: function () { return DriverWrappers_1.wrapDocumentServiceFactory; } });
|
|
@@ -36,6 +36,7 @@ var TestSummaryUtils_1 = require("./TestSummaryUtils");
|
|
|
36
36
|
Object.defineProperty(exports, "createSummarizer", { enumerable: true, get: function () { return TestSummaryUtils_1.createSummarizer; } });
|
|
37
37
|
Object.defineProperty(exports, "createSummarizerFromFactory", { enumerable: true, get: function () { return TestSummaryUtils_1.createSummarizerFromFactory; } });
|
|
38
38
|
Object.defineProperty(exports, "summarizeNow", { enumerable: true, get: function () { return TestSummaryUtils_1.summarizeNow; } });
|
|
39
|
+
Object.defineProperty(exports, "createSummarizerWithTestConfig", { enumerable: true, get: function () { return TestSummaryUtils_1.createSummarizerWithTestConfig; } });
|
|
39
40
|
var timeoutUtils_1 = require("./timeoutUtils");
|
|
40
41
|
Object.defineProperty(exports, "defaultTimeoutDurationMs", { enumerable: true, get: function () { return timeoutUtils_1.defaultTimeoutDurationMs; } });
|
|
41
42
|
Object.defineProperty(exports, "timeoutAwait", { enumerable: true, get: function () { return timeoutUtils_1.timeoutAwait; } });
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,mDAI0B;AAHzB,qHAAA,mBAAmB,OAAA;AACnB,4HAAA,0BAA0B,OAAA;AAC1B,4HAAA,0BAA0B,OAAA;AAG3B,mEAAkE;AAAzD,gIAAA,sBAAsB,OAAA;AAC/B,qDAAgG;AAAtE,kHAAA,eAAe,OAAA;AACzC,6CAAuE;AAA9D,uHAAA,wBAAwB,OAAA;AAAE,2GAAA,YAAY,OAAA;AAC/C,iCAAiD;AAAxC,+GAAA,sBAAsB,OAAA;AAC/B,6CAAmD;AAA1C,iHAAA,kBAAkB,OAAA;AAC3B,6EAGuC;AAFtC,gJAAA,iCAAiC,OAAA;AACjC,0IAAA,2BAA2B,OAAA;AAE5B,qDAAoG;AAAnE,kHAAA,eAAe,OAAA;AAAE,yHAAA,sBAAsB,OAAA;AACxE,2DAS8B;AAR7B,sHAAA,gBAAgB,OAAA;AAChB,2HAAA,qBAAqB,OAAA;AACrB,iIAAA,2BAA2B,OAAA;AAC3B,oIAAA,8BAA8B,OAAA;AAI9B,wHAAA,kBAAkB,OAAA;AAEnB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,mDAI0B;AAHzB,qHAAA,mBAAmB,OAAA;AACnB,4HAAA,0BAA0B,OAAA;AAC1B,4HAAA,0BAA0B,OAAA;AAG3B,mEAAkE;AAAzD,gIAAA,sBAAsB,OAAA;AAC/B,qDAAgG;AAAtE,kHAAA,eAAe,OAAA;AACzC,6CAAuE;AAA9D,uHAAA,wBAAwB,OAAA;AAAE,2GAAA,YAAY,OAAA;AAC/C,iCAAiD;AAAxC,+GAAA,sBAAsB,OAAA;AAC/B,6CAAmD;AAA1C,iHAAA,kBAAkB,OAAA;AAC3B,6EAGuC;AAFtC,gJAAA,iCAAiC,OAAA;AACjC,0IAAA,2BAA2B,OAAA;AAE5B,qDAAoG;AAAnE,kHAAA,eAAe,OAAA;AAAE,yHAAA,sBAAsB,OAAA;AACxE,2DAS8B;AAR7B,sHAAA,gBAAgB,OAAA;AAChB,2HAAA,qBAAqB,OAAA;AACrB,iIAAA,2BAA2B,OAAA;AAC3B,oIAAA,8BAA8B,OAAA;AAI9B,wHAAA,kBAAkB,OAAA;AAEnB,uDAK4B;AAJ3B,oHAAA,gBAAgB,OAAA;AAChB,+HAAA,2BAA2B,OAAA;AAC3B,gHAAA,YAAY,OAAA;AACZ,kIAAA,8BAA8B,OAAA;AAE/B,+CAMwB;AALvB,wHAAA,wBAAwB,OAAA;AACxB,4GAAA,YAAY,OAAA;AACZ,8GAAA,cAAc,OAAA;AAIf,mDAA8D;AAArD,4HAAA,0BAA0B,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport {\n\twrapDocumentService,\n\twrapDocumentServiceFactory,\n\twrapDocumentStorageService,\n} from \"./DriverWrappers\";\nexport { IProvideTestFluidObject, ITestFluidObject } from \"./interfaces\";\nexport { LoaderContainerTracker } from \"./loaderContainerTracker\";\nexport { fluidEntryPoint, LocalCodeLoader, SupportedExportInterfaces } from \"./localCodeLoader\";\nexport { createAndAttachContainer, createLoader } from \"./localLoader\";\nexport { retryWithEventualValue } from \"./retry\";\nexport { mockConfigProvider } from \"./TestConfigs\";\nexport {\n\tcreateTestContainerRuntimeFactory,\n\tTestContainerRuntimeFactory,\n} from \"./testContainerRuntimeFactory\";\nexport { ChannelFactoryRegistry, TestFluidObject, TestFluidObjectFactory } from \"./testFluidObject\";\nexport {\n\tcreateDocumentId,\n\tDataObjectFactoryType,\n\tEventAndErrorTrackingLogger,\n\tgetUnexpectedLogErrorException,\n\tIOpProcessingController,\n\tITestContainerConfig,\n\tITestObjectProvider,\n\tTestObjectProvider,\n} from \"./testObjectProvider\";\nexport {\n\tcreateSummarizer,\n\tcreateSummarizerFromFactory,\n\tsummarizeNow,\n\tcreateSummarizerWithTestConfig,\n} from \"./TestSummaryUtils\";\nexport {\n\tdefaultTimeoutDurationMs,\n\ttimeoutAwait,\n\ttimeoutPromise,\n\tTimeoutWithError,\n\tTimeoutWithValue,\n} from \"./timeoutUtils\";\nexport { waitForContainerConnection } from \"./containerUtils\";\n"]}
|
|
@@ -39,20 +39,17 @@ export declare class LoaderContainerTracker implements IOpProcessingController {
|
|
|
39
39
|
* Make sure all the tracked containers are synchronized.
|
|
40
40
|
*
|
|
41
41
|
* No isDirty (non-readonly) containers
|
|
42
|
-
*
|
|
43
42
|
* No extra clientId in quorum of any container that is not tracked and still opened.
|
|
44
|
-
*
|
|
45
43
|
* - i.e. no pending Join/Leave message.
|
|
46
|
-
*
|
|
47
44
|
* No unresolved proposal (minSeqNum \>= lastProposalSeqNum)
|
|
48
|
-
*
|
|
49
45
|
* lastSequenceNumber of all container is the same
|
|
50
|
-
*
|
|
51
46
|
* clientSequenceNumberObserved is the same as clientSequenceNumber sent
|
|
52
|
-
*
|
|
53
47
|
* - this overlaps with !isDirty, but include task scheduler ops.
|
|
54
|
-
*
|
|
55
48
|
* - Trailing NoOp is tracked and don't count as pending ops.
|
|
49
|
+
*
|
|
50
|
+
* Containers that are already pause will resume process and paused again once
|
|
51
|
+
* everything is synchronized. Containers that aren't paused will remain unpaused when this
|
|
52
|
+
* function returns.
|
|
56
53
|
*/
|
|
57
54
|
ensureSynchronized(...containers: IContainer[]): Promise<void>;
|
|
58
55
|
/**
|
|
@@ -68,7 +65,8 @@ export declare class LoaderContainerTracker implements IOpProcessingController {
|
|
|
68
65
|
*
|
|
69
66
|
* @param containersToApply - the set of containers to check
|
|
70
67
|
*/
|
|
71
|
-
private
|
|
68
|
+
private needSequenceNumberSynchronize;
|
|
69
|
+
private containerIndexStrings;
|
|
72
70
|
/**
|
|
73
71
|
* Utility to wait for any clientId in quorum that is NOT associated with any container we
|
|
74
72
|
* tracked, indicating there is a pending join or leave op that we need to wait.
|
|
@@ -90,18 +88,37 @@ export declare class LoaderContainerTracker implements IOpProcessingController {
|
|
|
90
88
|
/**
|
|
91
89
|
* Pause all queue activities on the containers given, or all tracked containers
|
|
92
90
|
* Any containers given that is not tracked will be ignored.
|
|
91
|
+
*
|
|
92
|
+
* When a container is paused, it is assumed that we want fine grain control over op
|
|
93
|
+
* sequencing. This function will prepare the container and force it into write mode to
|
|
94
|
+
* avoid missing join messages or change the sequence of event when switching from read to
|
|
95
|
+
* write mode.
|
|
93
96
|
*/
|
|
94
97
|
pauseProcessing(...containers: IContainer[]): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* When a container is paused, it is assumed that we want fine grain control over op
|
|
100
|
+
* sequencing. This function will prepare the container and force it into write mode to
|
|
101
|
+
* avoid missing join messages or change the sequence of event when switching from read to
|
|
102
|
+
* write mode.
|
|
103
|
+
*
|
|
104
|
+
* @param container - the container to pause
|
|
105
|
+
* @param record - the record for the container
|
|
106
|
+
*/
|
|
107
|
+
private pauseContainer;
|
|
95
108
|
/**
|
|
96
109
|
* Pause all queue activities on all tracked containers, and resume only
|
|
97
110
|
* inbound to process ops until it is idle. All queues are left in the paused state
|
|
98
|
-
* after the function
|
|
111
|
+
* after the function.
|
|
112
|
+
*
|
|
113
|
+
* Pausing will switch the container to write mode. See `pauseProcessing`
|
|
99
114
|
*/
|
|
100
115
|
processIncoming(...containers: IContainer[]): Promise<void>;
|
|
101
116
|
/**
|
|
102
117
|
* Pause all queue activities on all tracked containers, and resume only
|
|
103
118
|
* outbound to process ops until it is idle. All queues are left in the paused state
|
|
104
|
-
* after the function
|
|
119
|
+
* after the function.
|
|
120
|
+
*
|
|
121
|
+
* Pausing will switch the container to write mode. See `pauseProcessing`
|
|
105
122
|
*/
|
|
106
123
|
processOutgoing(...containers: IContainer[]): Promise<void>;
|
|
107
124
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loaderContainerTracker.d.ts","sourceRoot":"","sources":["../src/loaderContainerTracker.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAe,WAAW,EAAE,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"loaderContainerTracker.d.ts","sourceRoot":"","sources":["../src/loaderContainerTracker.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAe,WAAW,EAAE,MAAM,uCAAuC,CAAC;AAU7F,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAuB/D,qBAAa,sBAAuB,YAAW,uBAAuB;IAIzD,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;IAmB7D;;;;OAIG;IACH,OAAO,CAAC,YAAY;IA2BpB;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;IAuC1B,OAAO,CAAC,iBAAiB;IAQzB;;OAEG;IACI,KAAK;IAUZ;;;;OAIG;IACU,6BAA6B,CAAC,CAC1C,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,GAAG,UAAU,EAAE,UAAU,EAAE;IAK5B;;;;;;;;;;;;;;;OAeG;IACU,kBAAkB,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA2E3E;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IA8BzB;;;;;OAKG;IACH,OAAO,CAAC,6BAA6B;IAmErC,OAAO,CAAC,qBAAqB;IAO7B;;;;;;;OAOG;YACW,qBAAqB;IAoCnC;;;OAGG;YACW,oBAAoB;IAclC;;OAEG;IACI,gBAAgB,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAoBnD;;;;;;;;OAQG;IACU,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAexD;;;;;;;;OAQG;YACW,cAAc;IAwD5B;;;;;;OAMG;IACU,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAIxD;;;;;;OAMG;IACU,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAIxD;;OAEG;YACW,YAAY;IAgD1B;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IA2BzB;;OAEG;IACH,OAAO,CAAC,UAAU;IAwElB;;;;OAIG;IACH,OAAO,CAAC,aAAa;CAKrB"}
|
|
@@ -9,6 +9,7 @@ const common_utils_1 = require("@fluidframework/common-utils");
|
|
|
9
9
|
const container_loader_1 = require("@fluidframework/container-loader");
|
|
10
10
|
const driver_utils_1 = require("@fluidframework/driver-utils");
|
|
11
11
|
const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
|
|
12
|
+
const containerUtils_1 = require("./containerUtils");
|
|
12
13
|
const debug_1 = require("./debug");
|
|
13
14
|
const timeoutUtils_1 = require("./timeoutUtils");
|
|
14
15
|
const debugOp = debug_1.debug.extend("ops");
|
|
@@ -138,31 +139,32 @@ class LoaderContainerTracker {
|
|
|
138
139
|
* Make sure all the tracked containers are synchronized.
|
|
139
140
|
*
|
|
140
141
|
* No isDirty (non-readonly) containers
|
|
141
|
-
*
|
|
142
142
|
* No extra clientId in quorum of any container that is not tracked and still opened.
|
|
143
|
-
*
|
|
144
143
|
* - i.e. no pending Join/Leave message.
|
|
145
|
-
*
|
|
146
144
|
* No unresolved proposal (minSeqNum \>= lastProposalSeqNum)
|
|
147
|
-
*
|
|
148
145
|
* lastSequenceNumber of all container is the same
|
|
149
|
-
*
|
|
150
146
|
* clientSequenceNumberObserved is the same as clientSequenceNumber sent
|
|
151
|
-
*
|
|
152
147
|
* - this overlaps with !isDirty, but include task scheduler ops.
|
|
153
|
-
*
|
|
154
148
|
* - Trailing NoOp is tracked and don't count as pending ops.
|
|
149
|
+
*
|
|
150
|
+
* Containers that are already pause will resume process and paused again once
|
|
151
|
+
* everything is synchronized. Containers that aren't paused will remain unpaused when this
|
|
152
|
+
* function returns.
|
|
155
153
|
*/
|
|
156
154
|
async ensureSynchronized(...containers) {
|
|
157
155
|
const resumed = this.resumeProcessing(...containers);
|
|
158
|
-
let waitingSequenceNumberSynchronized
|
|
156
|
+
let waitingSequenceNumberSynchronized;
|
|
159
157
|
// eslint-disable-next-line no-constant-condition
|
|
160
158
|
while (true) {
|
|
159
|
+
// yield a turn to allow side effect of resuming or the ops we just processed execute before we check
|
|
160
|
+
await new Promise((resolve) => {
|
|
161
|
+
setTimeout(resolve, 0);
|
|
162
|
+
});
|
|
161
163
|
const containersToApply = this.getContainers(containers);
|
|
162
164
|
if (containersToApply.length === 0) {
|
|
163
165
|
break;
|
|
164
166
|
}
|
|
165
|
-
// Ignore readonly dirty containers, because it can't sent
|
|
167
|
+
// Ignore readonly dirty containers, because it can't sent ops and nothing can be done about it being dirty
|
|
166
168
|
const dirtyContainers = containersToApply.filter((c) => {
|
|
167
169
|
const { deltaManager, isDirty } = c;
|
|
168
170
|
return deltaManager.readOnlyInfo.readonly !== true && isDirty;
|
|
@@ -171,21 +173,23 @@ class LoaderContainerTracker {
|
|
|
171
173
|
// Wait for all the leave messages
|
|
172
174
|
const pendingClients = this.getPendingClients(containersToApply);
|
|
173
175
|
if (pendingClients.length === 0) {
|
|
174
|
-
|
|
176
|
+
const needSync = this.needSequenceNumberSynchronize(containersToApply);
|
|
177
|
+
if (needSync === undefined) {
|
|
175
178
|
// done, we are in sync
|
|
176
179
|
break;
|
|
177
180
|
}
|
|
178
|
-
if (
|
|
179
|
-
//
|
|
180
|
-
waitingSequenceNumberSynchronized =
|
|
181
|
-
debugWait(
|
|
182
|
-
await (0, timeoutUtils_1.timeoutAwait)(this.waitForAnyInboundOps(containersToApply), {
|
|
183
|
-
errorMsg: "Timeout on waiting for sequence number synchronized",
|
|
184
|
-
});
|
|
181
|
+
if (waitingSequenceNumberSynchronized !== needSync.reason) {
|
|
182
|
+
// Don't repeat writing to console if it is the same reason
|
|
183
|
+
waitingSequenceNumberSynchronized = needSync.reason;
|
|
184
|
+
debugWait(needSync.message);
|
|
185
185
|
}
|
|
186
|
+
// Wait for one inbounds ops which might change the state of things
|
|
187
|
+
await (0, timeoutUtils_1.timeoutAwait)(this.waitForAnyInboundOps(containersToApply), {
|
|
188
|
+
errorMsg: `Timeout on ${needSync.message}`,
|
|
189
|
+
});
|
|
186
190
|
}
|
|
187
191
|
else {
|
|
188
|
-
waitingSequenceNumberSynchronized =
|
|
192
|
+
waitingSequenceNumberSynchronized = undefined;
|
|
189
193
|
await (0, timeoutUtils_1.timeoutAwait)(this.waitForPendingClients(pendingClients), {
|
|
190
194
|
errorMsg: "Timeout on waiting for pending join or leave op",
|
|
191
195
|
});
|
|
@@ -193,10 +197,8 @@ class LoaderContainerTracker {
|
|
|
193
197
|
}
|
|
194
198
|
else {
|
|
195
199
|
// Wait for all the containers to be saved
|
|
196
|
-
debugWait(`Waiting container to be saved ${
|
|
197
|
-
|
|
198
|
-
(c) => this.containers.get(c).index)}`);
|
|
199
|
-
waitingSequenceNumberSynchronized = false;
|
|
200
|
+
debugWait(`Waiting container to be saved ${this.containerIndexStrings(dirtyContainers)}`);
|
|
201
|
+
waitingSequenceNumberSynchronized = undefined;
|
|
200
202
|
await Promise.all(dirtyContainers.map(async (c) => Promise.race([
|
|
201
203
|
(0, timeoutUtils_1.timeoutPromise)((resolve) => c.once("saved", () => resolve()), {
|
|
202
204
|
errorMsg: "Timeout on waiting a container to be saved",
|
|
@@ -204,10 +206,6 @@ class LoaderContainerTracker {
|
|
|
204
206
|
new Promise((resolve) => c.once("closed", resolve)),
|
|
205
207
|
])));
|
|
206
208
|
}
|
|
207
|
-
// yield a turn to allow side effect of the ops we just processed execute before we check again
|
|
208
|
-
await new Promise((resolve) => {
|
|
209
|
-
setTimeout(resolve, 0);
|
|
210
|
-
});
|
|
211
209
|
}
|
|
212
210
|
// Pause all container that was resumed
|
|
213
211
|
// don't call pause if resumed is empty and pause everything, which is not what we want
|
|
@@ -255,42 +253,62 @@ class LoaderContainerTracker {
|
|
|
255
253
|
*
|
|
256
254
|
* @param containersToApply - the set of containers to check
|
|
257
255
|
*/
|
|
258
|
-
|
|
256
|
+
needSequenceNumberSynchronize(containersToApply) {
|
|
257
|
+
// If there is a pending proposal, wait for it to be accepted
|
|
258
|
+
const minSeqNum = containersToApply[0].deltaManager.minimumSequenceNumber;
|
|
259
|
+
if (minSeqNum < this.lastProposalSeqNum) {
|
|
260
|
+
return {
|
|
261
|
+
reason: "Proposal",
|
|
262
|
+
message: `waiting for MSN to advance to proposal at sequence number ${this.lastProposalSeqNum}`,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
259
265
|
// clientSequenceNumber check detects ops in flight, both on the wire and in the outbound queue
|
|
260
266
|
// We need both client sequence number and isDirty check because:
|
|
261
267
|
// - Currently isDirty flag ignores ops for task scheduler, so we need the client sequence number check
|
|
262
268
|
// - But isDirty flags include ops during forceReadonly and disconnected, because we don't submit
|
|
263
269
|
// the ops in the first place, clientSequenceNumber is not assigned
|
|
264
|
-
const
|
|
270
|
+
const containerWithInflightOps = containersToApply.filter((container) => {
|
|
265
271
|
if (container.deltaManager.readOnlyInfo.readonly === true) {
|
|
266
272
|
// Ignore readonly container. the clientSeqNum and clientSeqNumObserved might be out of sync
|
|
267
273
|
// because we transition to readonly when outbound is not empty or the in transit op got lost
|
|
268
|
-
return
|
|
274
|
+
return false;
|
|
269
275
|
}
|
|
270
276
|
// Note that in read only mode, the op won't be submitted
|
|
271
277
|
let deltaManager = container.deltaManager;
|
|
272
278
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
273
279
|
const { trailingNoOps } = this.containers.get(container);
|
|
274
|
-
// Back-compat: clientSequenceNumber
|
|
280
|
+
// Back-compat: lastSubmittedClientId/clientSequenceNumber/clientSequenceNumberObserved moved to ConnectionManager in 0.53
|
|
275
281
|
if (!("clientSequenceNumber" in deltaManager)) {
|
|
276
282
|
deltaManager = deltaManager.connectionManager;
|
|
277
283
|
}
|
|
278
284
|
(0, common_utils_1.assert)("clientSequenceNumber" in deltaManager, "no clientSequenceNumber");
|
|
279
285
|
(0, common_utils_1.assert)("clientSequenceNumberObserved" in deltaManager, "no clientSequenceNumber");
|
|
280
|
-
|
|
281
|
-
|
|
286
|
+
// If last submittedClientId isn't the current clientId, then we haven't send any ops
|
|
287
|
+
return (deltaManager.lastSubmittedClientId === container.clientId &&
|
|
288
|
+
deltaManager.clientSequenceNumber !==
|
|
289
|
+
deltaManager.clientSequenceNumberObserved + trailingNoOps);
|
|
282
290
|
});
|
|
283
|
-
if (
|
|
284
|
-
return
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
// There is an unresolved proposal
|
|
289
|
-
return false;
|
|
291
|
+
if (containerWithInflightOps.length !== 0) {
|
|
292
|
+
return {
|
|
293
|
+
reason: "InflightOps",
|
|
294
|
+
message: `waiting for containers with inflight ops: ${this.containerIndexStrings(containerWithInflightOps)}`,
|
|
295
|
+
};
|
|
290
296
|
}
|
|
291
297
|
// Check to see if all the container has process the same number of ops.
|
|
292
|
-
const
|
|
293
|
-
|
|
298
|
+
const maxSeqNum = Math.max(...containersToApply.map((c) => c.deltaManager.lastSequenceNumber));
|
|
299
|
+
const containerWithPendingIncoming = containersToApply.filter((c) => c.deltaManager.lastSequenceNumber !== maxSeqNum);
|
|
300
|
+
if (containerWithPendingIncoming.length !== 0) {
|
|
301
|
+
return {
|
|
302
|
+
reason: "Pending",
|
|
303
|
+
message: `waiting for containers with pending incoming ops up to sequence number ${maxSeqNum}: ${this.containerIndexStrings(containerWithPendingIncoming)}`,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
return undefined;
|
|
307
|
+
}
|
|
308
|
+
containerIndexStrings(containers) {
|
|
309
|
+
return containers.map(
|
|
310
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
311
|
+
(c) => this.containers.get(c).index);
|
|
294
312
|
}
|
|
295
313
|
/**
|
|
296
314
|
* Utility to wait for any clientId in quorum that is NOT associated with any container we
|
|
@@ -352,6 +370,7 @@ class LoaderContainerTracker {
|
|
|
352
370
|
const containersToApply = this.getContainers(containers);
|
|
353
371
|
for (const container of containersToApply) {
|
|
354
372
|
const record = this.containers.get(container);
|
|
373
|
+
(0, common_utils_1.assert)((record === null || record === void 0 ? void 0 : record.pauseP) === undefined, "Cannot resume container while pausing is in progress");
|
|
355
374
|
if ((record === null || record === void 0 ? void 0 : record.paused) === true) {
|
|
356
375
|
debugWait(`${record.index}: container resumed`);
|
|
357
376
|
container.deltaManager.inbound.resume();
|
|
@@ -365,25 +384,86 @@ class LoaderContainerTracker {
|
|
|
365
384
|
/**
|
|
366
385
|
* Pause all queue activities on the containers given, or all tracked containers
|
|
367
386
|
* Any containers given that is not tracked will be ignored.
|
|
387
|
+
*
|
|
388
|
+
* When a container is paused, it is assumed that we want fine grain control over op
|
|
389
|
+
* sequencing. This function will prepare the container and force it into write mode to
|
|
390
|
+
* avoid missing join messages or change the sequence of event when switching from read to
|
|
391
|
+
* write mode.
|
|
368
392
|
*/
|
|
369
393
|
async pauseProcessing(...containers) {
|
|
370
|
-
const
|
|
394
|
+
const waitP = [];
|
|
371
395
|
const containersToApply = this.getContainers(containers);
|
|
372
396
|
for (const container of containersToApply) {
|
|
373
397
|
const record = this.containers.get(container);
|
|
374
398
|
if (record !== undefined && !record.paused) {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
record.
|
|
399
|
+
if (record.pauseP === undefined) {
|
|
400
|
+
record.pauseP = this.pauseContainer(container, record);
|
|
401
|
+
}
|
|
402
|
+
waitP.push(record.pauseP);
|
|
379
403
|
}
|
|
380
404
|
}
|
|
381
|
-
await Promise.all(
|
|
405
|
+
await Promise.all(waitP);
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* When a container is paused, it is assumed that we want fine grain control over op
|
|
409
|
+
* sequencing. This function will prepare the container and force it into write mode to
|
|
410
|
+
* avoid missing join messages or change the sequence of event when switching from read to
|
|
411
|
+
* write mode.
|
|
412
|
+
*
|
|
413
|
+
* @param container - the container to pause
|
|
414
|
+
* @param record - the record for the container
|
|
415
|
+
*/
|
|
416
|
+
async pauseContainer(container, record) {
|
|
417
|
+
debugWait(`${record.index}: pausing container`);
|
|
418
|
+
(0, common_utils_1.assert)(!container.deltaManager.outbound.paused, "Container should not be paused yet");
|
|
419
|
+
(0, common_utils_1.assert)(!container.deltaManager.inbound.paused, "Container should not be paused yet");
|
|
420
|
+
// Pause outbound
|
|
421
|
+
debugWait(`${record.index}: pausing container outbound queues`);
|
|
422
|
+
await container.deltaManager.outbound.pause();
|
|
423
|
+
// Ensure the container is connected first.
|
|
424
|
+
if (container.connectionState !== container_loader_1.ConnectionState.Connected) {
|
|
425
|
+
debugWait(`${record.index}: Wait for container connection`);
|
|
426
|
+
await (0, containerUtils_1.waitForContainerConnection)(container);
|
|
427
|
+
}
|
|
428
|
+
// Check if the container is in write mode
|
|
429
|
+
if (!container.deltaManager.active) {
|
|
430
|
+
let proposalP;
|
|
431
|
+
if (container.deltaManager.outbound.idle) {
|
|
432
|
+
// Need to generate an op to force write mode
|
|
433
|
+
debugWait(`${record.index}: container force write connection`);
|
|
434
|
+
const maybeContainer = container;
|
|
435
|
+
const codeProposal = maybeContainer.getLoadedCodeDetails
|
|
436
|
+
? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
437
|
+
container.getLoadedCodeDetails()
|
|
438
|
+
: container.chaincodePackage;
|
|
439
|
+
proposalP = container.proposeCodeDetails(codeProposal);
|
|
440
|
+
}
|
|
441
|
+
// Wait for nack
|
|
442
|
+
debugWait(`${record.index}: Wait for container disconnect`);
|
|
443
|
+
container.deltaManager.outbound.resume();
|
|
444
|
+
await new Promise((resolve) => container.once("disconnected", resolve));
|
|
445
|
+
const accepted = proposalP ? await proposalP : false;
|
|
446
|
+
(0, common_utils_1.assert)(!accepted, "A proposal in read mode should be rejected");
|
|
447
|
+
await container.deltaManager.outbound.pause();
|
|
448
|
+
// Ensure the container is reconnect.
|
|
449
|
+
if (container.connectionState !== container_loader_1.ConnectionState.Connected) {
|
|
450
|
+
debugWait(`${record.index}: Wait for container reconnection`);
|
|
451
|
+
await (0, containerUtils_1.waitForContainerConnection)(container);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
debugWait(`${record.index}: pausing container inbound queues`);
|
|
455
|
+
// Pause inbound
|
|
456
|
+
await container.deltaManager.inbound.pause();
|
|
457
|
+
debugWait(`${record.index}: container paused`);
|
|
458
|
+
record.pauseP = undefined;
|
|
459
|
+
record.paused = true;
|
|
382
460
|
}
|
|
383
461
|
/**
|
|
384
462
|
* Pause all queue activities on all tracked containers, and resume only
|
|
385
463
|
* inbound to process ops until it is idle. All queues are left in the paused state
|
|
386
|
-
* after the function
|
|
464
|
+
* after the function.
|
|
465
|
+
*
|
|
466
|
+
* Pausing will switch the container to write mode. See `pauseProcessing`
|
|
387
467
|
*/
|
|
388
468
|
async processIncoming(...containers) {
|
|
389
469
|
return this.processQueue(containers, (container) => container.deltaManager.inbound);
|
|
@@ -391,7 +471,9 @@ class LoaderContainerTracker {
|
|
|
391
471
|
/**
|
|
392
472
|
* Pause all queue activities on all tracked containers, and resume only
|
|
393
473
|
* outbound to process ops until it is idle. All queues are left in the paused state
|
|
394
|
-
* after the function
|
|
474
|
+
* after the function.
|
|
475
|
+
*
|
|
476
|
+
* Pausing will switch the container to write mode. See `pauseProcessing`
|
|
395
477
|
*/
|
|
396
478
|
async processOutgoing(...containers) {
|
|
397
479
|
return this.processQueue(containers, (container) => container.deltaManager.outbound);
|
|
@@ -406,6 +488,7 @@ class LoaderContainerTracker {
|
|
|
406
488
|
const inflightTracker = new Map();
|
|
407
489
|
const cleanup = [];
|
|
408
490
|
for (const container of containersToApply) {
|
|
491
|
+
(0, common_utils_1.assert)(container.deltaManager.active, "Container should be connected in write mode already");
|
|
409
492
|
const queue = getQueue(container);
|
|
410
493
|
// track the outgoing ops (if any) to make sure they make the round trip to at least to the same client
|
|
411
494
|
// to make sure they are sequenced.
|