@fluidframework/test-utils 2.0.0-dev.2.3.0.115467 → 2.0.0-dev.3.1.0.125672

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 (68) hide show
  1. package/.eslintrc.js +8 -10
  2. package/README.md +41 -11
  3. package/api-extractor.json +2 -2
  4. package/dist/DriverWrappers.d.ts.map +1 -1
  5. package/dist/DriverWrappers.js.map +1 -1
  6. package/dist/TestConfigs.d.ts.map +1 -1
  7. package/dist/TestConfigs.js +3 -2
  8. package/dist/TestConfigs.js.map +1 -1
  9. package/dist/TestSummaryUtils.d.ts +8 -3
  10. package/dist/TestSummaryUtils.d.ts.map +1 -1
  11. package/dist/TestSummaryUtils.js +23 -23
  12. package/dist/TestSummaryUtils.js.map +1 -1
  13. package/dist/containerUtils.d.ts +38 -0
  14. package/dist/containerUtils.d.ts.map +1 -0
  15. package/dist/containerUtils.js +58 -0
  16. package/dist/containerUtils.js.map +1 -0
  17. package/dist/index.d.ts +5 -4
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +4 -3
  20. package/dist/index.js.map +1 -1
  21. package/dist/interfaces.d.ts.map +1 -1
  22. package/dist/interfaces.js.map +1 -1
  23. package/dist/loaderContainerTracker.d.ts +0 -4
  24. package/dist/loaderContainerTracker.d.ts.map +1 -1
  25. package/dist/loaderContainerTracker.js +39 -38
  26. package/dist/loaderContainerTracker.js.map +1 -1
  27. package/dist/localCodeLoader.d.ts.map +1 -1
  28. package/dist/localCodeLoader.js.map +1 -1
  29. package/dist/localLoader.d.ts.map +1 -1
  30. package/dist/localLoader.js.map +1 -1
  31. package/dist/packageVersion.d.ts +1 -1
  32. package/dist/packageVersion.js +1 -1
  33. package/dist/packageVersion.js.map +1 -1
  34. package/dist/retry.d.ts.map +1 -1
  35. package/dist/retry.js.map +1 -1
  36. package/dist/testContainerRuntimeFactory.d.ts +2 -2
  37. package/dist/testContainerRuntimeFactory.d.ts.map +1 -1
  38. package/dist/testContainerRuntimeFactory.js +3 -3
  39. package/dist/testContainerRuntimeFactory.js.map +1 -1
  40. package/dist/testFluidObject.d.ts.map +1 -1
  41. package/dist/testFluidObject.js +7 -3
  42. package/dist/testFluidObject.js.map +1 -1
  43. package/dist/testObjectProvider.d.ts +2 -0
  44. package/dist/testObjectProvider.d.ts.map +1 -1
  45. package/dist/testObjectProvider.js +15 -10
  46. package/dist/testObjectProvider.js.map +1 -1
  47. package/dist/timeoutUtils.d.ts +11 -0
  48. package/dist/timeoutUtils.d.ts.map +1 -1
  49. package/dist/timeoutUtils.js +121 -11
  50. package/dist/timeoutUtils.js.map +1 -1
  51. package/package.json +38 -30
  52. package/prettier.config.cjs +1 -1
  53. package/src/DriverWrappers.ts +40 -37
  54. package/src/TestConfigs.ts +9 -7
  55. package/src/TestSummaryUtils.ts +126 -120
  56. package/src/containerUtils.ts +61 -0
  57. package/src/index.ts +27 -21
  58. package/src/interfaces.ts +10 -7
  59. package/src/loaderContainerTracker.ts +627 -576
  60. package/src/localCodeLoader.ts +85 -77
  61. package/src/localLoader.ts +24 -24
  62. package/src/packageVersion.ts +1 -1
  63. package/src/retry.ts +31 -25
  64. package/src/testContainerRuntimeFactory.ts +59 -56
  65. package/src/testFluidObject.ts +168 -152
  66. package/src/testObjectProvider.ts +433 -383
  67. package/src/timeoutUtils.ts +196 -39
  68. package/tsconfig.json +9 -12
package/.eslintrc.js CHANGED
@@ -4,13 +4,11 @@
4
4
  */
5
5
 
6
6
  module.exports = {
7
- "extends": [
8
- require.resolve("@fluidframework/eslint-config-fluid"), "prettier"
9
- ],
10
- "parserOptions": {
11
- "project": ["./tsconfig.json", "./src/test/tsconfig.json"]
12
- },
13
- "rules": {
14
- "import/no-nodejs-modules": "off",
15
- }
16
- }
7
+ extends: [require.resolve("@fluidframework/eslint-config-fluid/minimal"), "prettier"],
8
+ parserOptions: {
9
+ project: ["./tsconfig.json", "./src/test/tsconfig.json"],
10
+ },
11
+ rules: {
12
+ "import/no-nodejs-modules": "off",
13
+ },
14
+ };
package/README.md CHANGED
@@ -7,6 +7,7 @@ This package contains utilities for writing end-to-end tests in Fluid Framework.
7
7
  `LocalCodeLoader` in `localCodeLoader.ts` is a simple code loader that can load a Fluid package with a given entry point. It can be used to load multiple different Fluid packages with different sources (`IFluidCodeDetails`).
8
8
 
9
9
  It should be created by passing in a list of source to entry point mapping. Then entry point can be an `IFluidDataStoreFactory`, `IRuntimeFactory` or a `fluidExport`:
10
+
10
11
  ```typeScript
11
12
  // The fluidEntryPoint type.
12
13
  export type fluidEntryPoint = Partial<IProvideRuntimeFactory & IProvideFluidDataStoreFactory & IFluidModule>;
@@ -14,9 +15,11 @@ export type fluidEntryPoint = Partial<IProvideRuntimeFactory & IProvideFluidData
14
15
  // Constructor for LocalCodeLoader.
15
16
  constructor(packageEntries: Iterable<[IFluidCodeDetails, fluidEntryPoint]>);
16
17
  ```
18
+
17
19
  On load, it retrieves the `fluidEntryPoint` matching the package in the `IFluidCodeDetails` and loads it.
18
20
 
19
21
  ## Local Loader
22
+
20
23
  `localLoader.ts` contains couple of methods:
21
24
 
22
25
  ### `createLocalLoader`
@@ -24,6 +27,7 @@ On load, it retrieves the `fluidEntryPoint` matching the package in the `IFluidC
24
27
  This method creates a simple `Loader` that can be used to resolve a Container or request a Fluid object.
25
28
 
26
29
  It should be created with a list of source to entry point mappings (of type `fluidEntryPoint` as explained in [LocalCodeLoader](#Local-Code-Loader) section above), an `ILocalDeltaConnectionServer` and an `IUrlResolver`:
30
+
27
31
  ```typeScript
28
32
  export function createLocalLoader(
29
33
  packageEntries: Iterable<[
@@ -34,8 +38,9 @@ export function createLocalLoader(
34
38
  urlResolver: IUrlResolver,
35
39
  ): ILoader;
36
40
  ```
37
- - It creates a `LocalCodeLoader` using the `fluidEntryPoint` list to load Container code.
38
- - It creates a `DocumentServiceFactory` which serves as the driver layer between the container and the server.
41
+
42
+ - It creates a `LocalCodeLoader` using the `fluidEntryPoint` list to load Container code.
43
+ - It creates a `DocumentServiceFactory` which serves as the driver layer between the container and the server.
39
44
 
40
45
  ### `createAndAttachContainer`
41
46
 
@@ -44,10 +49,10 @@ helper method on the url resolver passed to the loader to generate the `attachRe
44
49
 
45
50
  ```typescript
46
51
  export async function createAndAttachContainer(
47
- source: IFluidCodeDetails,
48
- loader: ILoader,
49
- attachRequest: IRequest,
50
- ): Promise<IContainer>
52
+ source: IFluidCodeDetails,
53
+ loader: ILoader,
54
+ attachRequest: IRequest,
55
+ ): Promise<IContainer>;
51
56
  ```
52
57
 
53
58
  The usual flow is to create a `LocalLoader` by calling `createLocalLoader` and then using it to call `createAndAttachContainer`. However, this should work with any `ILoader`.
@@ -58,6 +63,7 @@ The usual flow is to create a `LocalLoader` by calling `createLocalLoader` and t
58
63
  It can be used to create a Fluid object (TestFluidObject) with a given set of DDSes which can then be retrieved later as required.
59
64
 
60
65
  For example, if you need a Fluid object with couple of SharedStrings, a SharedDirectory and a SparseMatrix, create a `TestFluidObjectFactory` as follows and use this factory to create the Fluid object:
66
+
61
67
  ```typeScript
62
68
  new TestFluidObjectFactory([
63
69
  [ "sharedString1" /* id */, SharedString.getFactory() ],
@@ -68,6 +74,7 @@ new TestFluidObjectFactory([
68
74
  ```
69
75
 
70
76
  The `TestFluidObject` will then create the above DDSes when initializing and they can then be retrieved by calling `getSharedObject` on it and providing the `id` that was used to create it:
77
+
71
78
  ```typeScript
72
79
  const sharedString1 = testFluidObject.getSharedObject<SharedString>("sharedString1");
73
80
  const sharedString1 = testFluidObject.getSharedObject<SharedString>("sharedString2");
@@ -78,6 +85,7 @@ const matrix = testFluidObject.getSharedObject<SparseMatrix>("matrix");
78
85
  > If you want a DDS to be part of the registry so that it can be created later but don't want `TestFluidObject` to create it during initialization, use `id` as `undefined` in the `TestFluidObjectFactory` creation.
79
86
 
80
87
  ## Op Processing Controller
88
+
81
89
  `OpProcessingController` provides control over op processing in the tests. It lets you pause and resume the op processing in the containers / fluid objects. It also lets you wait until the ops have been processed by them and the server.
82
90
 
83
91
  `OpProcessingController` should be created by passing in the `ILocalDeltaConnectionServer` that is used in the test. You can then register the Fluid objects / containers whose ops you want to control with it.
@@ -89,50 +97,71 @@ You can use the `OpProcessingController` to wait for all that to happen by calli
89
97
  ## Usage
90
98
 
91
99
  The typical usage for testing a Fluid object is as follows:
100
+
92
101
  1. Create a `LocalDeltaConnectionServer`:
102
+
93
103
  ```typescript
94
104
  const deltaConnectionServer: ILocalDeltaConnectionServer = LocalDeltaConnectionServer.create();
95
105
  ```
96
106
 
97
107
  2. Create a `LocalResolver`:
108
+
98
109
  ```typescript
99
110
  const urlResolver: IUrlResolver = new LocalResolver();
100
111
  ```
101
112
 
102
113
  3. Create an `IFluidCodeDetails` and a `TestFluidObjectFactory` which will serve as the Fluid entry point (code details to factory mapping):
114
+
103
115
  ```typescript
104
116
  const codeDetails: IFluidCodeDetails = {
105
- package: "sharedStringTestPackage",
106
- config: {},
117
+ package: "sharedStringTestPackage",
118
+ config: {},
107
119
  };
108
120
  const entryPoint = new TestFluidObjectFactory([["sharedString", SharedString.getFactory()]]);
109
121
  ```
122
+
110
123
  > This can replaced by any `IFluidDataStoreFactory` or `IRuntimeFactory`. When the loader is asked to resolve a Container with the above code details, it will load the above factory.
111
124
 
112
125
  4. Create a local `Loader`:
126
+
113
127
  ```typescript
114
- const loader: ILoader = createLocalLoader([[codeDetails, entryPoint]], deltaConnectionServer, urlResolver);
128
+ const loader: ILoader = createLocalLoader(
129
+ [[codeDetails, entryPoint]],
130
+ deltaConnectionServer,
131
+ urlResolver,
132
+ );
115
133
  ```
116
134
 
117
135
  5. Create and attach a `Container` by giving it a `documentId` which is used as a URL to resolve the container:
136
+
118
137
  ```typescript
119
138
  const documentId = "testDocument";
120
139
  const container = await createAndAttachContainer(
121
- codeDetails, loader, urlResolver.createCreateNewRequest(documentId))
140
+ codeDetails,
141
+ loader,
142
+ urlResolver.createCreateNewRequest(documentId),
143
+ );
122
144
  ```
145
+
123
146
  > We used the same `IFluidCodeDetails` that was used to create the `Loader` in step 3.
124
147
 
125
148
  6. Get the `Fluid object (TestFluidObject)` by using `requestFluidObject` API in `@fluidframework/runtime-utils`. Then get the `DDS` to test:
149
+
126
150
  ```typescript
127
151
  const fluidObject = await requestFluidObject<ITestFluidObject>(container, "default"); // "default" represent the default Fluid object.
128
152
  const sharedString = await fluidObject.getSharedObject<SharedString>("sharedString");
129
153
  ```
154
+
130
155
  > The `ITestFluidObject` would have already created a `SharedString` based off the parameters we provided when creating the `TestFluidObjectFactory` in step 2.
131
156
 
132
157
  7. To truly test collaboration, create a second `Loader`, `Container`, `fluid object` and `DDS` which will serve as a remote client:
133
158
  ```typescript
134
159
  const documentUrl = `fluid-test://localhost/${documentId}`;
135
- const loader2: ILoader = createLocalLoader([[codeDetails, entryPoint]], deltaConnectionServer, urlResolver);
160
+ const loader2: ILoader = createLocalLoader(
161
+ [[codeDetails, entryPoint]],
162
+ deltaConnectionServer,
163
+ urlResolver,
164
+ );
136
165
  const container2 = await loader2.resolver({ url: documentUrl });
137
166
  const fluidObject = await requestFluidObject<ITestFluidObject>(container2, "default");
138
167
  const sharedString2 = await fluidObject2.getSharedObject<SharedString>("sharedString");
@@ -146,6 +175,7 @@ These steps are demonstrated in the image below:
146
175
  > Note that the LocalDriver is created by the `createLocalLoader` method and does not need to explicitly created.
147
176
 
148
177
  ## Example
178
+
149
179
  The above usage is taken from [SharedStringTest](../end-to-end-tests/src/test/sharedStringEndToEndTests.spec.ts) which is a very basic example of how to use these utils.
150
180
 
151
181
  There are a number of other examples (some a little more complex) in the same [directory](../end-to-end-tests/src/test).
@@ -1,4 +1,4 @@
1
1
  {
2
- "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
3
- "extends": "@fluidframework/build-common/api-extractor-common-report.json"
2
+ "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
3
+ "extends": "@fluidframework/build-common/api-extractor-common-report.json"
4
4
  }
@@ -1 +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"}
1
+ {"version":3,"file":"DriverWrappers.d.ts","sourceRoot":"","sources":["../src/DriverWrappers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACN,gBAAgB,EAChB,uBAAuB,EACvB,uBAAuB,EAEvB,eAAe,EACf,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAEpE;;;;GAIG;AACH,wBAAgB,0BAA0B,CACzC,sBAAsB,EAAE,uBAAuB,EAC/C,eAAe,EAAE,CAAC,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,eAAe,KAAK,eAAe,2BAWzF;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAClC,eAAe,EAAE,gBAAgB,EACjC,eAAe,EAAE,CAAC,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,eAAe,KAAK,eAAe,oBAQzF;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACzC,sBAAsB,EAAE,uBAAuB,EAC/C,eAAe,EAAE,CAAC,WAAW,EAAE,YAAY,EAAE,OAAO,EAAE,eAAe,KAAK,eAAe,2BAgBzF"}
@@ -1 +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"]}
1
+ {"version":3,"file":"DriverWrappers.js","sourceRoot":"","sources":["../src/DriverWrappers.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAYH;;;;GAIG;AACH,SAAgB,0BAA0B,CACzC,sBAA+C,EAC/C,eAAyF;IAEzF,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAA4B,CAAC;IAChG,sBAAsB,CAAC,wBAAwB,GAAG,KAAK,EACtD,OAAqB,EACrB,OAAwB,EACN,EAAE;QACpB,MAAM,UAAU,GAAG,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACrD,OAAO,sBAAsB,CAAC,wBAAwB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAC7E,CAAC,CAAC;IACF,OAAO,sBAAsB,CAAC;AAC/B,CAAC;AAbD,gEAaC;AAED;;;;;;GAMG;AACH,SAAgB,mBAAmB,CAClC,eAAiC,EACjC,eAAyF;IAEzF,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,eAAe,CAAqB,CAAC;IAC3E,eAAe,CAAC,gBAAgB,GAAG,KAAK,IAAsC,EAAE;QAC/E,MAAM,cAAc,GAAG,MAAM,eAAe,CAAC,gBAAgB,EAAE,CAAC;QAChE,OAAO,0BAA0B,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;IACpE,CAAC,CAAC;IACF,OAAO,eAAe,CAAC;AACxB,CAAC;AAVD,kDAUC;AAED;;;;;;GAMG;AACH,SAAgB,0BAA0B,CACzC,sBAA+C,EAC/C,eAAyF;IAEzF,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAA4B,CAAC;IAChG,sBAAsB,CAAC,qBAAqB,GAAG,KAAK,EACnD,WAAyB,EACzB,MAA6B,EAC7B,kBAA4B,EACA,EAAE;QAC9B,MAAM,eAAe,GAAG,MAAM,sBAAsB,CAAC,qBAAqB,CACzE,WAAW,EACX,MAAM,EACN,kBAAkB,CAClB,CAAC;QACF,OAAO,mBAAmB,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;IAC9D,CAAC,CAAC;IACF,OAAO,sBAAsB,CAAC;AAC/B,CAAC;AAlBD,gEAkBC","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\tIDocumentService,\n\tIDocumentServiceFactory,\n\tIDocumentStorageService,\n\tIResolvedUrl,\n\tISummaryContext,\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\tinnerDocStorageService: IDocumentStorageService,\n\tuploadSummaryCb: (summaryTree: ISummaryTree, context: ISummaryContext) => ISummaryContext,\n) {\n\tconst outerDocStorageService = Object.create(innerDocStorageService) as IDocumentStorageService;\n\touterDocStorageService.uploadSummaryWithContext = async (\n\t\tsummary: ISummaryTree,\n\t\tcontext: ISummaryContext,\n\t): Promise<string> => {\n\t\tconst newContext = uploadSummaryCb(summary, context);\n\t\treturn innerDocStorageService.uploadSummaryWithContext(summary, newContext);\n\t};\n\treturn 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\tinnerDocService: IDocumentService,\n\tuploadSummaryCb: (summaryTree: ISummaryTree, context: ISummaryContext) => ISummaryContext,\n) {\n\tconst outerDocService = Object.create(innerDocService) as IDocumentService;\n\touterDocService.connectToStorage = async (): Promise<IDocumentStorageService> => {\n\t\tconst storageService = await innerDocService.connectToStorage();\n\t\treturn wrapDocumentStorageService(storageService, uploadSummaryCb);\n\t};\n\treturn 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\tinnerDocServiceFactory: IDocumentServiceFactory,\n\tuploadSummaryCb: (summaryTree: ISummaryTree, context: ISummaryContext) => ISummaryContext,\n) {\n\tconst outerDocServiceFactory = Object.create(innerDocServiceFactory) as IDocumentServiceFactory;\n\touterDocServiceFactory.createDocumentService = async (\n\t\tresolvedUrl: IResolvedUrl,\n\t\tlogger?: ITelemetryBaseLogger,\n\t\tclientIsSummarizer?: boolean,\n\t): Promise<IDocumentService> => {\n\t\tconst documentService = await innerDocServiceFactory.createDocumentService(\n\t\t\tresolvedUrl,\n\t\t\tlogger,\n\t\t\tclientIsSummarizer,\n\t\t);\n\t\treturn wrapDocumentService(documentService, uploadSummaryCb);\n\t};\n\treturn outerDocServiceFactory;\n}\n"]}
@@ -1 +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"}
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,cACpB,OAAO,MAAM,EAAE,WAAW,CAAC,KACnC,mBAMF,CAAC"}
@@ -5,11 +5,12 @@
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.mockConfigProvider = void 0;
8
- exports.mockConfigProvider = ((settings = {}) => {
8
+ const mockConfigProvider = (settings = {}) => {
9
9
  settings["Fluid.GarbageCollection.TrackGCState"] = "true";
10
10
  settings["Fluid.GarbageCollection.WriteDataAtRoot"] = "true";
11
11
  return {
12
12
  getRawConfig: (name) => settings[name],
13
13
  };
14
- });
14
+ };
15
+ exports.mockConfigProvider = mockConfigProvider;
15
16
  //# sourceMappingURL=TestConfigs.js.map
@@ -1 +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"]}
1
+ {"version":3,"file":"TestConfigs.js","sourceRoot":"","sources":["../src/TestConfigs.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAII,MAAM,kBAAkB,GAAG,CACjC,WAAwC,EAAE,EACpB,EAAE;IACxB,QAAQ,CAAC,sCAAsC,CAAC,GAAG,MAAM,CAAC;IAC1D,QAAQ,CAAC,yCAAyC,CAAC,GAAG,MAAM,CAAC;IAC7D,OAAO;QACN,YAAY,EAAE,CAAC,IAAY,EAAe,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC;KAC3D,CAAC;AACH,CAAC,CAAC;AARW,QAAA,kBAAkB,sBAQ7B","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 = (\n\tsettings: Record<string, ConfigTypes> = {},\n): IConfigProviderBase => {\n\tsettings[\"Fluid.GarbageCollection.TrackGCState\"] = \"true\";\n\tsettings[\"Fluid.GarbageCollection.WriteDataAtRoot\"] = \"true\";\n\treturn {\n\t\tgetRawConfig: (name: string): ConfigTypes => settings[name],\n\t};\n};\n"]}
@@ -7,16 +7,21 @@ import { IContainer } from "@fluidframework/container-definitions";
7
7
  import { IGCRuntimeOptions, ISummarizer } from "@fluidframework/container-runtime";
8
8
  import { IFluidDataStoreFactory, NamedFluidDataStoreRegistryEntries } from "@fluidframework/runtime-definitions";
9
9
  import { IConfigProviderBase } from "@fluidframework/telemetry-utils";
10
+ import { ITelemetryBaseLogger } from "@fluidframework/common-definitions";
10
11
  import { ITestObjectProvider } from "./testObjectProvider";
11
12
  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 createSummarizerWithContainer(provider: ITestObjectProvider, absoluteUrl: string | undefined, summaryVersion?: string, gcOptions?: IGCRuntimeOptions, configProvider?: IConfigProviderBase): Promise<{
13
+ export declare function createSummarizer(provider: ITestObjectProvider, container: IContainer, summaryVersion?: string, gcOptions?: IGCRuntimeOptions, configProvider?: IConfigProviderBase, logger?: ITelemetryBaseLogger): Promise<ISummarizer>;
14
+ export declare function createSummarizerWithContainer(provider: ITestObjectProvider, absoluteUrl: string | undefined, summaryVersion?: string, gcOptions?: IGCRuntimeOptions, configProvider?: IConfigProviderBase, logger?: ITelemetryBaseLogger): Promise<{
14
15
  container: IContainer;
15
16
  summarizer: ISummarizer;
16
17
  }>;
18
+ /**
19
+ * Summarizes on demand and returns the summary tree, the version number and the reference sequence number of the
20
+ * submitted summary.
21
+ */
17
22
  export declare function summarizeNow(summarizer: ISummarizer, reason?: string): Promise<{
18
23
  summaryTree: import("@fluidframework/protocol-definitions").ISummaryTree;
19
24
  summaryVersion: string;
25
+ summaryRefSeq: number;
20
26
  }>;
21
- export declare function waitForContainerConnection(container: IContainer): Promise<void>;
22
27
  //# sourceMappingURL=TestSummaryUtils.d.ts.map
@@ -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;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;AAgDjF,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,CAStB;AAED,wBAAsB,6BAA6B,CAC/C,QAAQ,EAAE,mBAAmB,EAC7B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,cAAc,CAAC,EAAE,MAAM,EACvB,SAAS,CAAC,EAAE,iBAAiB,EAC7B,cAAc,GAAE,mBAA0C,GAC3D,OAAO,CAAC;IAAE,SAAS,EAAE,UAAU,CAAC;IAAC,UAAU,EAAE,WAAW,CAAC;CAAE,CAAC,CAU9D;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"}
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,EAAwB,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAqDjF,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,GAClD,OAAO,CAAC,WAAW,CAAC,CAgBtB;AAED,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,WAAW,CAAC,CAYtB;AAED,wBAAsB,6BAA6B,CAClD,QAAQ,EAAE,mBAAmB,EAC7B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,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;AACD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,UAAU,EAAE,WAAW,EAAE,MAAM,GAAE,MAA0B;;;;GAwB7F"}
@@ -4,14 +4,15 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.waitForContainerConnection = exports.summarizeNow = exports.createSummarizerWithContainer = exports.createSummarizer = exports.createSummarizerFromFactory = void 0;
7
+ exports.summarizeNow = exports.createSummarizerWithContainer = 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");
11
- const container_loader_1 = require("@fluidframework/container-loader");
12
11
  const driver_definitions_1 = require("@fluidframework/driver-definitions");
13
12
  const runtime_utils_1 = require("@fluidframework/runtime-utils");
14
13
  const TestConfigs_1 = require("./TestConfigs");
14
+ const containerUtils_1 = require("./containerUtils");
15
+ const timeoutUtils_1 = require("./timeoutUtils");
15
16
  const summarizerClientType = "summarizer";
16
17
  async function createSummarizerCore(absoluteUrl, loader, summaryVersion) {
17
18
  if (absoluteUrl === undefined) {
@@ -25,14 +26,15 @@ async function createSummarizerCore(absoluteUrl, loader, summaryVersion) {
25
26
  type: summarizerClientType,
26
27
  },
27
28
  [driver_definitions_1.DriverHeader.summarizingClient]: true,
28
- [container_definitions_1.LoaderHeader.reconnect]: false,
29
29
  [container_definitions_1.LoaderHeader.version]: summaryVersion,
30
30
  },
31
31
  url: absoluteUrl,
32
32
  };
33
33
  const summarizerContainer = await loader.resolve(request);
34
- await waitForContainerConnection(summarizerContainer);
35
- const fluidObject = await (0, runtime_utils_1.requestFluidObject)(summarizerContainer, { url: "_summarizer" });
34
+ await (0, containerUtils_1.waitForContainerConnection)(summarizerContainer);
35
+ const fluidObject = await (0, runtime_utils_1.requestFluidObject)(summarizerContainer, {
36
+ url: "_summarizer",
37
+ });
36
38
  if (fluidObject.ISummarizer === undefined) {
37
39
  throw new Error("Fluid object does not implement ISummarizer");
38
40
  }
@@ -47,57 +49,55 @@ const defaultSummaryOptions = {
47
49
  maxAckWaitTime: 10000,
48
50
  maxOpsSinceLastSummary: 7000,
49
51
  initialSummarizerDelayMs: 0,
50
- summarizerClientElection: false,
51
52
  },
52
53
  };
53
54
  async function createSummarizerFromFactory(provider, container, dataStoreFactory, summaryVersion, containerRuntimeFactoryType = aqueduct_1.ContainerRuntimeFactoryWithDefaultDataStore, registryEntries) {
54
55
  const innerRequestHandler = async (request, runtime) => runtime.IFluidHandleContext.resolveHandle(request);
55
- const runtimeFactory = new containerRuntimeFactoryType(dataStoreFactory, registryEntries !== null && registryEntries !== void 0 ? registryEntries : [
56
- [dataStoreFactory.type, Promise.resolve(dataStoreFactory)],
57
- ], undefined, [innerRequestHandler], { summaryOptions: defaultSummaryOptions });
58
- const loader = provider.createLoader([[provider.defaultCodeDetails, runtimeFactory]], { configProvider: (0, TestConfigs_1.mockConfigProvider)() });
56
+ const runtimeFactory = new containerRuntimeFactoryType(dataStoreFactory, registryEntries !== null && registryEntries !== void 0 ? registryEntries : [[dataStoreFactory.type, Promise.resolve(dataStoreFactory)]], undefined, [innerRequestHandler], { summaryOptions: defaultSummaryOptions });
57
+ const loader = provider.createLoader([[provider.defaultCodeDetails, runtimeFactory]], {
58
+ configProvider: (0, TestConfigs_1.mockConfigProvider)(),
59
+ });
59
60
  const absoluteUrl = await container.getAbsoluteUrl("");
60
61
  return (await createSummarizerCore(absoluteUrl, loader, summaryVersion)).summarizer;
61
62
  }
62
63
  exports.createSummarizerFromFactory = createSummarizerFromFactory;
63
- async function createSummarizer(provider, container, summaryVersion, gcOptions, configProvider = (0, TestConfigs_1.mockConfigProvider)()) {
64
+ async function createSummarizer(provider, container, summaryVersion, gcOptions, configProvider = (0, TestConfigs_1.mockConfigProvider)(), logger) {
64
65
  const absoluteUrl = await container.getAbsoluteUrl("");
65
- return (await createSummarizerWithContainer(provider, absoluteUrl, summaryVersion, gcOptions, configProvider)).summarizer;
66
+ return (await createSummarizerWithContainer(provider, absoluteUrl, summaryVersion, gcOptions, configProvider, logger)).summarizer;
66
67
  }
67
68
  exports.createSummarizer = createSummarizer;
68
- async function createSummarizerWithContainer(provider, absoluteUrl, summaryVersion, gcOptions, configProvider = (0, TestConfigs_1.mockConfigProvider)()) {
69
+ async function createSummarizerWithContainer(provider, absoluteUrl, summaryVersion, gcOptions, configProvider = (0, TestConfigs_1.mockConfigProvider)(), logger) {
69
70
  const testContainerConfig = {
70
71
  runtimeOptions: {
71
72
  summaryOptions: defaultSummaryOptions,
72
73
  gcOptions,
73
74
  },
74
- loaderProps: { configProvider },
75
+ loaderProps: { configProvider, logger },
75
76
  };
76
77
  const loader = provider.makeTestLoader(testContainerConfig);
77
78
  return createSummarizerCore(absoluteUrl, loader, summaryVersion);
78
79
  }
79
80
  exports.createSummarizerWithContainer = createSummarizerWithContainer;
81
+ /**
82
+ * Summarizes on demand and returns the summary tree, the version number and the reference sequence number of the
83
+ * submitted summary.
84
+ */
80
85
  async function summarizeNow(summarizer, reason = "end-to-end test") {
81
86
  const result = summarizer.summarizeOnDemand({ reason });
82
- const submitResult = await result.summarySubmitted;
87
+ const submitResult = await (0, timeoutUtils_1.timeoutAwait)(result.summarySubmitted);
83
88
  (0, common_utils_1.assert)(submitResult.success, "on-demand summary should submit");
84
89
  (0, common_utils_1.assert)(submitResult.data.stage === "submit", "on-demand summary submitted data stage should be submit");
85
90
  (0, common_utils_1.assert)(submitResult.data.summaryTree !== undefined, "summary tree should exist");
86
- const broadcastResult = await result.summaryOpBroadcasted;
91
+ const broadcastResult = await (0, timeoutUtils_1.timeoutAwait)(result.summaryOpBroadcasted);
87
92
  (0, common_utils_1.assert)(broadcastResult.success, "summary op should be broadcast");
88
- const ackNackResult = await result.receivedSummaryAckOrNack;
93
+ const ackNackResult = await (0, timeoutUtils_1.timeoutAwait)(result.receivedSummaryAckOrNack);
89
94
  (0, common_utils_1.assert)(ackNackResult.success, "summary op should be acked");
90
95
  await new Promise((resolve) => process.nextTick(resolve));
91
96
  return {
92
97
  summaryTree: submitResult.data.summaryTree,
93
98
  summaryVersion: ackNackResult.data.summaryAckOp.contents.handle,
99
+ summaryRefSeq: submitResult.data.referenceSequenceNumber,
94
100
  };
95
101
  }
96
102
  exports.summarizeNow = summarizeNow;
97
- async function waitForContainerConnection(container) {
98
- if (container.connectionState !== container_loader_1.ConnectionState.Connected) {
99
- return new Promise((resolve) => container.once("connected", () => resolve()));
100
- }
101
- }
102
- exports.waitForContainerConnection = waitForContainerConnection;
103
103
  //# sourceMappingURL=TestSummaryUtils.js.map
@@ -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 { 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(absoluteUrl: string | undefined, loader: IHostLoader, summaryVersion?: string) {\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\n return {\n container: summarizerContainer,\n summarizer: fluidObject.ISummarizer,\n };\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 const absoluteUrl = await container.getAbsoluteUrl(\"\");\n return (await createSummarizerCore(absoluteUrl, loader, summaryVersion)).summarizer;\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 absoluteUrl = await container.getAbsoluteUrl(\"\");\n return (await createSummarizerWithContainer(\n provider,\n absoluteUrl,\n summaryVersion,\n gcOptions,\n configProvider,\n )).summarizer;\n}\n\nexport async function createSummarizerWithContainer(\n provider: ITestObjectProvider,\n absoluteUrl: string | undefined,\n summaryVersion?: string,\n gcOptions?: IGCRuntimeOptions,\n configProvider: IConfigProviderBase = mockConfigProvider(),\n): Promise<{ container: IContainer; summarizer: ISummarizer; }> {\n const testContainerConfig: ITestContainerConfig = {\n runtimeOptions: {\n summaryOptions: defaultSummaryOptions,\n gcOptions,\n },\n loaderProps: { configProvider },\n };\n const loader = provider.makeTestLoader(testContainerConfig);\n return createSummarizerCore(absoluteUrl, 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"]}
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\tabsoluteUrl: string | undefined,\n\tloader: IHostLoader,\n\tsummaryVersion?: string,\n) {\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 = await requestFluidObject<FluidObject<ISummarizer>>(summarizerContainer, {\n\t\turl: \"_summarizer\",\n\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\nexport async function createSummarizerFromFactory(\n\tprovider: ITestObjectProvider,\n\tcontainer: IContainer,\n\tdataStoreFactory: IFluidDataStoreFactory,\n\tsummaryVersion?: string,\n\tcontainerRuntimeFactoryType = ContainerRuntimeFactoryWithDefaultDataStore,\n\tregistryEntries?: NamedFluidDataStoreRegistryEntries,\n): Promise<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});\n\tconst absoluteUrl = await container.getAbsoluteUrl(\"\");\n\treturn (await createSummarizerCore(absoluteUrl, loader, summaryVersion)).summarizer;\n}\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<ISummarizer> {\n\tconst absoluteUrl = await container.getAbsoluteUrl(\"\");\n\treturn (\n\t\tawait createSummarizerWithContainer(\n\t\t\tprovider,\n\t\t\tabsoluteUrl,\n\t\t\tsummaryVersion,\n\t\t\tgcOptions,\n\t\t\tconfigProvider,\n\t\t\tlogger,\n\t\t)\n\t).summarizer;\n}\n\nexport async function createSummarizerWithContainer(\n\tprovider: ITestObjectProvider,\n\tabsoluteUrl: string | undefined,\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(absoluteUrl, loader, summaryVersion);\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"]}
@@ -0,0 +1,38 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ import { IContainer } from "@fluidframework/container-definitions";
6
+ import { Container } from "@fluidframework/container-loader";
7
+ import { TimeoutWithError } from "./timeoutUtils";
8
+ /**
9
+ * Waits for the specified container to emit a 'connected' event.
10
+ *
11
+ * @deprecated Use waitForContainerConnection instead.
12
+ * Note that an upcoming release will change the default parameters on that function to:
13
+ * - failOnContainerClose = true
14
+ * - timeoutOptions.durationMs = 1s
15
+ */
16
+ export declare function ensureContainerConnected(container: Container): Promise<void>;
17
+ /**
18
+ * Utility function to wait for the specified Container to be in Connected state.
19
+ * If the Container is already connected, the Promise returns immediately; otherwise it resolves when the Container emits
20
+ * its 'connected' event.
21
+ * If failOnContainerClose === true, the returned Promise will be rejected if the container emits a 'closed' event
22
+ * before a 'connected' event.
23
+ * @param container - The container to wait for.
24
+ * @param failOnContainerClose - If true, the returned Promise will be rejected if the container emits a 'closed' event
25
+ * before a 'connected' event.
26
+ * Defaults to false (but this will change in an upcoming version).
27
+ * @param timeoutOptions - Options related to the behavior of the timeout.
28
+ * If not provided, no timeout will be applied and the promise will wait indefinitely for the Container to emit its
29
+ * 'connected' (or 'closed, if failOnContainerClose === true) event.
30
+ * @returns A Promise that resolves when the specified container emits a 'connected' event (or immediately if the
31
+ * Container is already connected).
32
+ * If failOnContainerClose === true and the container emits a 'closed' event before a 'connected' event, the Promise
33
+ * is rejected with the error from the 'closed' event, if any.
34
+ * If timeoutOptions is provided, the Promise will reject if the container hasn't emmited a relevant event before
35
+ * timeoutOptions.durationMs (which defaults to 250ms if left undefined).
36
+ */
37
+ export declare function waitForContainerConnection(container: IContainer, failOnContainerClose?: boolean, timeoutOptions?: TimeoutWithError): Promise<void>;
38
+ //# sourceMappingURL=containerUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"containerUtils.d.ts","sourceRoot":"","sources":["../src/containerUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAmB,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAC9E,OAAO,EAAmC,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEnF;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAIlF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,0BAA0B,CAC/C,SAAS,EAAE,UAAU,EACrB,oBAAoB,GAAE,OAAe,EACrC,cAAc,CAAC,EAAE,gBAAgB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAaf"}
@@ -0,0 +1,58 @@
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.ensureContainerConnected = void 0;
8
+ const container_loader_1 = require("@fluidframework/container-loader");
9
+ const timeoutUtils_1 = require("./timeoutUtils");
10
+ /**
11
+ * Waits for the specified container to emit a 'connected' event.
12
+ *
13
+ * @deprecated Use waitForContainerConnection instead.
14
+ * Note that an upcoming release will change the default parameters on that function to:
15
+ * - failOnContainerClose = true
16
+ * - timeoutOptions.durationMs = 1s
17
+ */
18
+ async function ensureContainerConnected(container) {
19
+ if (!container.connected) {
20
+ return (0, timeoutUtils_1.timeoutPromise)((resolve) => container.once("connected", () => resolve()));
21
+ }
22
+ }
23
+ exports.ensureContainerConnected = ensureContainerConnected;
24
+ /**
25
+ * Utility function to wait for the specified Container to be in Connected state.
26
+ * If the Container is already connected, the Promise returns immediately; otherwise it resolves when the Container emits
27
+ * its 'connected' event.
28
+ * If failOnContainerClose === true, the returned Promise will be rejected if the container emits a 'closed' event
29
+ * before a 'connected' event.
30
+ * @param container - The container to wait for.
31
+ * @param failOnContainerClose - If true, the returned Promise will be rejected if the container emits a 'closed' event
32
+ * before a 'connected' event.
33
+ * Defaults to false (but this will change in an upcoming version).
34
+ * @param timeoutOptions - Options related to the behavior of the timeout.
35
+ * If not provided, no timeout will be applied and the promise will wait indefinitely for the Container to emit its
36
+ * 'connected' (or 'closed, if failOnContainerClose === true) event.
37
+ * @returns A Promise that resolves when the specified container emits a 'connected' event (or immediately if the
38
+ * Container is already connected).
39
+ * If failOnContainerClose === true and the container emits a 'closed' event before a 'connected' event, the Promise
40
+ * is rejected with the error from the 'closed' event, if any.
41
+ * If timeoutOptions is provided, the Promise will reject if the container hasn't emmited a relevant event before
42
+ * timeoutOptions.durationMs (which defaults to 250ms if left undefined).
43
+ */
44
+ async function waitForContainerConnection(container, failOnContainerClose = false, timeoutOptions) {
45
+ if (container.connectionState !== container_loader_1.ConnectionState.Connected) {
46
+ const executor = (resolve, reject) => {
47
+ container.once("connected", () => resolve());
48
+ if (failOnContainerClose) {
49
+ container.once("closed", (error) => reject(error));
50
+ }
51
+ };
52
+ return timeoutOptions === undefined
53
+ ? new Promise(executor)
54
+ : (0, timeoutUtils_1.timeoutPromise)(executor, timeoutOptions);
55
+ }
56
+ }
57
+ exports.waitForContainerConnection = waitForContainerConnection;
58
+ //# sourceMappingURL=containerUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"containerUtils.js","sourceRoot":"","sources":["../src/containerUtils.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,uEAA8E;AAC9E,iDAAmF;AAEnF;;;;;;;GAOG;AACI,KAAK,UAAU,wBAAwB,CAAC,SAAoB;IAClE,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE;QACzB,OAAO,IAAA,6BAAc,EAAC,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;KACjF;AACF,CAAC;AAJD,4DAIC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACI,KAAK,UAAU,0BAA0B,CAC/C,SAAqB,EACrB,uBAAgC,KAAK,EACrC,cAAiC;IAEjC,IAAI,SAAS,CAAC,eAAe,KAAK,kCAAe,CAAC,SAAS,EAAE;QAC5D,MAAM,QAAQ,GAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrD,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YAC7C,IAAI,oBAAoB,EAAE;gBACzB,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;aACnD;QACF,CAAC,CAAC;QAEF,OAAO,cAAc,KAAK,SAAS;YAClC,CAAC,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC;YACvB,CAAC,CAAC,IAAA,6BAAc,EAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;KAC5C;AACF,CAAC;AAjBD,gEAiBC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { IContainer } from \"@fluidframework/container-definitions\";\nimport { ConnectionState, Container } from \"@fluidframework/container-loader\";\nimport { PromiseExecutor, timeoutPromise, TimeoutWithError } from \"./timeoutUtils\";\n\n/**\n * Waits for the specified container to emit a 'connected' event.\n *\n * @deprecated Use waitForContainerConnection instead.\n * Note that an upcoming release will change the default parameters on that function to:\n * - failOnContainerClose = true\n * - timeoutOptions.durationMs = 1s\n */\nexport async function ensureContainerConnected(container: Container): Promise<void> {\n\tif (!container.connected) {\n\t\treturn timeoutPromise((resolve) => container.once(\"connected\", () => resolve()));\n\t}\n}\n\n/**\n * Utility function to wait for the specified Container to be in Connected state.\n * If the Container is already connected, the Promise returns immediately; otherwise it resolves when the Container emits\n * its 'connected' event.\n * If failOnContainerClose === true, the returned Promise will be rejected if the container emits a 'closed' event\n * before a 'connected' event.\n * @param container - The container to wait for.\n * @param failOnContainerClose - If true, the returned Promise will be rejected if the container emits a 'closed' event\n * before a 'connected' event.\n * Defaults to false (but this will change in an upcoming version).\n * @param timeoutOptions - Options related to the behavior of the timeout.\n * If not provided, no timeout will be applied and the promise will wait indefinitely for the Container to emit its\n * 'connected' (or 'closed, if failOnContainerClose === true) event.\n * @returns A Promise that resolves when the specified container emits a 'connected' event (or immediately if the\n * Container is already connected).\n * If failOnContainerClose === true and the container emits a 'closed' event before a 'connected' event, the Promise\n * is rejected with the error from the 'closed' event, if any.\n * If timeoutOptions is provided, the Promise will reject if the container hasn't emmited a relevant event before\n * timeoutOptions.durationMs (which defaults to 250ms if left undefined).\n */\nexport async function waitForContainerConnection(\n\tcontainer: IContainer,\n\tfailOnContainerClose: boolean = false,\n\ttimeoutOptions?: TimeoutWithError,\n): Promise<void> {\n\tif (container.connectionState !== ConnectionState.Connected) {\n\t\tconst executor: PromiseExecutor = (resolve, reject) => {\n\t\t\tcontainer.once(\"connected\", () => resolve());\n\t\t\tif (failOnContainerClose) {\n\t\t\t\tcontainer.once(\"closed\", (error) => reject(error));\n\t\t\t}\n\t\t};\n\n\t\treturn timeoutOptions === undefined\n\t\t\t? new Promise(executor)\n\t\t\t: timeoutPromise(executor, timeoutOptions);\n\t}\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -2,16 +2,17 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- export { wrapDocumentService, wrapDocumentServiceFactory, wrapDocumentStorageService } from "./DriverWrappers";
5
+ export { wrapDocumentService, wrapDocumentServiceFactory, wrapDocumentStorageService, } from "./DriverWrappers";
6
6
  export { IProvideTestFluidObject, ITestFluidObject } from "./interfaces";
7
7
  export { LoaderContainerTracker } from "./loaderContainerTracker";
8
8
  export { fluidEntryPoint, LocalCodeLoader, SupportedExportInterfaces } from "./localCodeLoader";
9
9
  export { createAndAttachContainer, createLoader } from "./localLoader";
10
10
  export { retryWithEventualValue } from "./retry";
11
11
  export { mockConfigProvider } from "./TestConfigs";
12
- export { createTestContainerRuntimeFactory, TestContainerRuntimeFactory } from "./testContainerRuntimeFactory";
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, createSummarizerWithContainer, summarizeNow, waitForContainerConnection, } from "./TestSummaryUtils";
16
- export { defaultTimeoutDurationMs, ensureContainerConnected, timeoutAwait, timeoutPromise, TimeoutWithError, TimeoutWithValue, } from "./timeoutUtils";
15
+ export { createSummarizer, createSummarizerFromFactory, createSummarizerWithContainer, summarizeNow, } from "./TestSummaryUtils";
16
+ export { defaultTimeoutDurationMs, timeoutAwait, timeoutPromise, TimeoutWithError, TimeoutWithValue, } from "./timeoutUtils";
17
+ export { ensureContainerConnected, waitForContainerConnection } from "./containerUtils";
17
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC/G,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,EAAE,iCAAiC,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAC/G,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACpG,OAAO,EACH,gBAAgB,EAChB,qBAAqB,EACrB,2BAA2B,EAC3B,8BAA8B,EAC9B,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,GACrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACH,gBAAgB,EAChB,2BAA2B,EAC3B,6BAA6B,EAC7B,YAAY,EACZ,0BAA0B,GAC7B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACH,wBAAwB,EACxB,wBAAwB,EACxB,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,gBAAgB,GACnB,MAAM,gBAAgB,CAAC"}
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,6BAA6B,EAC7B,YAAY,GACZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACN,wBAAwB,EACxB,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,gBAAgB,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC"}