@fluidframework/test-utils 1.4.0-115997 → 2.0.0-dev-rc.1.0.0.224419

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 (98) hide show
  1. package/.eslintrc.js +8 -7
  2. package/.mocharc.js +12 -0
  3. package/CHANGELOG.md +177 -0
  4. package/README.md +44 -14
  5. package/api-extractor-lint.json +4 -0
  6. package/api-extractor.json +2 -2
  7. package/api-report/test-utils.api.md +395 -0
  8. package/dist/DriverWrappers.d.ts +32 -0
  9. package/dist/DriverWrappers.d.ts.map +1 -0
  10. package/dist/DriverWrappers.js +57 -0
  11. package/dist/DriverWrappers.js.map +1 -0
  12. package/dist/TestConfigs.d.ts +10 -0
  13. package/dist/TestConfigs.d.ts.map +1 -0
  14. package/dist/TestConfigs.js +17 -0
  15. package/dist/TestConfigs.js.map +1 -0
  16. package/dist/TestSummaryUtils.d.ts +61 -0
  17. package/dist/TestSummaryUtils.d.ts.map +1 -0
  18. package/dist/TestSummaryUtils.js +135 -0
  19. package/dist/TestSummaryUtils.js.map +1 -0
  20. package/dist/containerUtils.d.ts +46 -0
  21. package/dist/containerUtils.d.ts.map +1 -0
  22. package/dist/containerUtils.js +85 -0
  23. package/dist/containerUtils.js.map +1 -0
  24. package/dist/index.d.ts +14 -9
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +43 -19
  27. package/dist/index.js.map +1 -1
  28. package/dist/interfaces.d.ts +6 -0
  29. package/dist/interfaces.d.ts.map +1 -1
  30. package/dist/interfaces.js.map +1 -1
  31. package/dist/loaderContainerTracker.d.ts +39 -15
  32. package/dist/loaderContainerTracker.d.ts.map +1 -1
  33. package/dist/loaderContainerTracker.js +214 -86
  34. package/dist/loaderContainerTracker.js.map +1 -1
  35. package/dist/localCodeLoader.d.ts +9 -2
  36. package/dist/localCodeLoader.d.ts.map +1 -1
  37. package/dist/localCodeLoader.js +18 -17
  38. package/dist/localCodeLoader.js.map +1 -1
  39. package/dist/localLoader.d.ts +3 -2
  40. package/dist/localLoader.d.ts.map +1 -1
  41. package/dist/localLoader.js +2 -0
  42. package/dist/localLoader.js.map +1 -1
  43. package/dist/packageVersion.d.ts +1 -1
  44. package/dist/packageVersion.d.ts.map +1 -1
  45. package/dist/packageVersion.js +1 -1
  46. package/dist/packageVersion.js.map +1 -1
  47. package/dist/retry.d.ts +1 -0
  48. package/dist/retry.d.ts.map +1 -1
  49. package/dist/retry.js +3 -2
  50. package/dist/retry.js.map +1 -1
  51. package/dist/test-utils-alpha.d.ts +305 -0
  52. package/dist/test-utils-beta.d.ts +202 -0
  53. package/dist/test-utils-public.d.ts +202 -0
  54. package/dist/test-utils-untrimmed.d.ts +1001 -0
  55. package/dist/testContainerRuntimeFactory.d.ts +4 -2
  56. package/dist/testContainerRuntimeFactory.d.ts.map +1 -1
  57. package/dist/testContainerRuntimeFactory.js +67 -12
  58. package/dist/testContainerRuntimeFactory.js.map +1 -1
  59. package/dist/testContainerRuntimeFactoryWithDefaultDataStore.d.ts +23 -0
  60. package/dist/testContainerRuntimeFactoryWithDefaultDataStore.d.ts.map +1 -0
  61. package/dist/testContainerRuntimeFactoryWithDefaultDataStore.js +32 -0
  62. package/dist/testContainerRuntimeFactoryWithDefaultDataStore.js.map +1 -0
  63. package/dist/testFluidObject.d.ts +30 -12
  64. package/dist/testFluidObject.d.ts.map +1 -1
  65. package/dist/testFluidObject.js +74 -43
  66. package/dist/testFluidObject.js.map +1 -1
  67. package/dist/testObjectProvider.d.ts +298 -41
  68. package/dist/testObjectProvider.d.ts.map +1 -1
  69. package/dist/testObjectProvider.js +377 -61
  70. package/dist/testObjectProvider.js.map +1 -1
  71. package/dist/timeoutUtils.d.ts +42 -0
  72. package/dist/timeoutUtils.d.ts.map +1 -1
  73. package/dist/timeoutUtils.js +142 -9
  74. package/dist/timeoutUtils.js.map +1 -1
  75. package/dist/tsdoc-metadata.json +11 -0
  76. package/lib/test-utils-alpha.d.ts +305 -0
  77. package/lib/test-utils-beta.d.ts +202 -0
  78. package/lib/test-utils-public.d.ts +202 -0
  79. package/lib/test-utils-untrimmed.d.ts +1001 -0
  80. package/package.json +106 -72
  81. package/prettier.config.cjs +8 -0
  82. package/src/DriverWrappers.ts +83 -0
  83. package/src/TestConfigs.ts +17 -0
  84. package/src/TestSummaryUtils.ts +210 -0
  85. package/src/containerUtils.ts +90 -0
  86. package/src/index.ts +47 -9
  87. package/src/interfaces.ts +16 -7
  88. package/src/loaderContainerTracker.ts +754 -534
  89. package/src/localCodeLoader.ts +87 -86
  90. package/src/localLoader.ts +27 -26
  91. package/src/packageVersion.ts +1 -1
  92. package/src/retry.ts +33 -26
  93. package/src/testContainerRuntimeFactory.ts +152 -59
  94. package/src/testContainerRuntimeFactoryWithDefaultDataStore.ts +61 -0
  95. package/src/testFluidObject.ts +190 -147
  96. package/src/testObjectProvider.ts +931 -372
  97. package/src/timeoutUtils.ts +226 -37
  98. package/tsconfig.json +9 -12
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/test-utils",
3
- "version": "1.4.0-115997",
3
+ "version": "2.0.0-dev-rc.1.0.0.224419",
4
4
  "description": "Utilities for Fluid tests",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -12,38 +12,18 @@
12
12
  "author": "Microsoft and contributors",
13
13
  "sideEffects": false,
14
14
  "main": "dist/index.js",
15
- "module": "lib/index.js",
16
15
  "types": "dist/index.d.ts",
17
- "scripts": {
18
- "build": "npm run build:genver && concurrently npm:build:compile npm:lint && npm run build:docs",
19
- "build:compile": "npm run tsc && npm run typetests:gen && npm run build:test",
20
- "build:compile:min": "npm run build:compile",
21
- "build:docs": "api-extractor run --local --typescript-compiler-folder ../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/doc-models/* ../../../_api-extractor-temp/",
22
- "build:full": "npm run build",
23
- "build:full:compile": "npm run build:compile",
24
- "build:genver": "gen-version",
25
- "build:test": "tsc --project ./src/test/tsconfig.json",
26
- "ci:build:docs": "api-extractor run --typescript-compiler-folder ../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/* ../../../_api-extractor-temp/",
27
- "clean": "rimraf dist lib *.tsbuildinfo *.build.log",
28
- "eslint": "eslint --format stylish src",
29
- "eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
30
- "lint": "npm run eslint",
31
- "lint:fix": "npm run eslint:fix",
32
- "tsc": "tsc",
33
- "typetests:gen": "flub generate typetests --generate --dir . --no-generateInName",
34
- "typetests:prepare": "flub generate typetests --prepare --dir . --pin"
35
- },
36
- "nyc": {
16
+ "c8": {
37
17
  "all": true,
38
18
  "cache-dir": "nyc/.cache",
39
19
  "exclude": [
40
- "src/test/**/*.ts",
41
- "dist/test/**/*.js"
20
+ "src/test/**/*.*ts",
21
+ "dist/test/**/*.*js"
42
22
  ],
43
23
  "exclude-after-remap": false,
44
24
  "include": [
45
- "src/**/*.ts",
46
- "dist/**/*.js"
25
+ "src/**/*.*ts",
26
+ "dist/**/*.*js"
47
27
  ],
48
28
  "report-dir": "nyc/report",
49
29
  "reporter": [
@@ -54,57 +34,111 @@
54
34
  "temp-directory": "nyc/.nyc_output"
55
35
  },
56
36
  "dependencies": {
57
- "@fluidframework/aqueduct": "1.4.0-115997",
58
- "@fluidframework/common-definitions": "^0.20.1",
59
- "@fluidframework/common-utils": "^0.32.1",
60
- "@fluidframework/container-definitions": "1.4.0-115997",
61
- "@fluidframework/container-loader": "1.4.0-115997",
62
- "@fluidframework/container-runtime": "1.4.0-115997",
63
- "@fluidframework/container-runtime-definitions": "1.4.0-115997",
64
- "@fluidframework/core-interfaces": "1.4.0-115997",
65
- "@fluidframework/datastore": "1.4.0-115997",
66
- "@fluidframework/datastore-definitions": "1.4.0-115997",
67
- "@fluidframework/driver-definitions": "1.4.0-115997",
68
- "@fluidframework/driver-utils": "1.4.0-115997",
69
- "@fluidframework/local-driver": "1.4.0-115997",
70
- "@fluidframework/map": "1.4.0-115997",
71
- "@fluidframework/protocol-definitions": "^0.1028.2000",
72
- "@fluidframework/request-handler": "1.4.0-115997",
73
- "@fluidframework/routerlicious-driver": "1.4.0-115997",
74
- "@fluidframework/runtime-definitions": "1.4.0-115997",
75
- "@fluidframework/runtime-utils": "1.4.0-115997",
76
- "@fluidframework/telemetry-utils": "1.4.0-115997",
77
- "@fluidframework/test-driver-definitions": "1.4.0-115997",
78
- "@fluidframework/test-runtime-utils": "1.4.0-115997",
79
- "debug": "^4.1.1",
80
- "uuid": "^8.3.1"
37
+ "@fluidframework/aqueduct": "2.0.0-dev-rc.1.0.0.224419",
38
+ "@fluidframework/container-definitions": "2.0.0-dev-rc.1.0.0.224419",
39
+ "@fluidframework/container-loader": "2.0.0-dev-rc.1.0.0.224419",
40
+ "@fluidframework/container-runtime": "2.0.0-dev-rc.1.0.0.224419",
41
+ "@fluidframework/container-runtime-definitions": "2.0.0-dev-rc.1.0.0.224419",
42
+ "@fluidframework/core-interfaces": "2.0.0-dev-rc.1.0.0.224419",
43
+ "@fluidframework/core-utils": "2.0.0-dev-rc.1.0.0.224419",
44
+ "@fluidframework/datastore": "2.0.0-dev-rc.1.0.0.224419",
45
+ "@fluidframework/datastore-definitions": "2.0.0-dev-rc.1.0.0.224419",
46
+ "@fluidframework/driver-definitions": "2.0.0-dev-rc.1.0.0.224419",
47
+ "@fluidframework/driver-utils": "2.0.0-dev-rc.1.0.0.224419",
48
+ "@fluidframework/local-driver": "2.0.0-dev-rc.1.0.0.224419",
49
+ "@fluidframework/map": "2.0.0-dev-rc.1.0.0.224419",
50
+ "@fluidframework/protocol-definitions": "^3.1.0-223007",
51
+ "@fluidframework/request-handler": "2.0.0-dev-rc.1.0.0.224419",
52
+ "@fluidframework/routerlicious-driver": "2.0.0-dev-rc.1.0.0.224419",
53
+ "@fluidframework/runtime-definitions": "2.0.0-dev-rc.1.0.0.224419",
54
+ "@fluidframework/runtime-utils": "2.0.0-dev-rc.1.0.0.224419",
55
+ "@fluidframework/telemetry-utils": "2.0.0-dev-rc.1.0.0.224419",
56
+ "@fluidframework/test-driver-definitions": "2.0.0-dev-rc.1.0.0.224419",
57
+ "@fluidframework/test-runtime-utils": "2.0.0-dev-rc.1.0.0.224419",
58
+ "best-random": "^1.0.0",
59
+ "debug": "^4.3.4",
60
+ "uuid": "^9.0.0"
81
61
  },
82
62
  "devDependencies": {
83
- "@fluidframework/build-common": "^0.24.0",
84
- "@fluidframework/build-tools": "^0.6.0-110101",
85
- "@fluidframework/eslint-config-fluid": "^0.28.2000",
86
- "@fluidframework/test-utils-previous": "npm:@fluidframework/test-utils@1.3.1",
87
- "@microsoft/api-extractor": "^7.22.2",
88
- "@rushstack/eslint-config": "^2.5.1",
63
+ "@arethetypeswrong/cli": "^0.13.3",
64
+ "@fluid-tools/build-cli": "0.29.0-222379",
65
+ "@fluidframework/build-common": "^2.0.3",
66
+ "@fluidframework/build-tools": "0.29.0-222379",
67
+ "@fluidframework/eslint-config-fluid": "^3.1.0",
68
+ "@fluidframework/mocha-test-setup": "2.0.0-dev-rc.1.0.0.224419",
69
+ "@fluidframework/test-utils-previous": "npm:@fluidframework/test-utils@2.0.0-internal.7.2.0",
70
+ "@microsoft/api-extractor": "^7.38.3",
71
+ "@types/debug": "^4.1.5",
89
72
  "@types/diff": "^3.5.1",
90
73
  "@types/mocha": "^9.1.1",
91
- "@types/node": "^14.18.0",
92
- "@types/random-js": "^1.0.31",
93
- "concurrently": "^6.2.0",
94
- "copyfiles": "^2.1.0",
74
+ "@types/node": "^18.19.0",
75
+ "@types/uuid": "^9.0.2",
76
+ "c8": "^7.7.1",
77
+ "copyfiles": "^2.4.1",
78
+ "cross-env": "^7.0.3",
95
79
  "diff": "^3.5.0",
96
- "eslint": "~8.6.0",
97
- "mocha": "^10.0.0",
98
- "nyc": "^15.0.0",
99
- "random-js": "^1.0.8",
100
- "rimraf": "^2.6.2",
101
- "typescript": "~4.5.5",
102
- "typescript-formatter": "7.1.0"
80
+ "eslint": "~8.50.0",
81
+ "mocha": "^10.2.0",
82
+ "mocha-json-output-reporter": "^2.0.1",
83
+ "mocha-multi-reporters": "^1.5.1",
84
+ "moment": "^2.21.0",
85
+ "prettier": "~3.0.3",
86
+ "rimraf": "^4.4.0",
87
+ "typescript": "~5.1.6"
88
+ },
89
+ "fluidBuild": {
90
+ "tasks": {
91
+ "build:docs": {
92
+ "dependsOn": [
93
+ "...",
94
+ "api-extractor:commonjs",
95
+ "api-extractor:esnext"
96
+ ],
97
+ "script": false
98
+ }
99
+ }
103
100
  },
104
101
  "typeValidation": {
105
- "version": "1.4.0",
106
- "baselineRange": "~1.3.0",
107
- "baselineVersion": "1.3.1",
108
- "broken": {}
102
+ "broken": {
103
+ "ClassDeclaration_TestFluidObject": {
104
+ "backCompat": false
105
+ },
106
+ "InterfaceDeclaration_ITestObjectProvider": {
107
+ "backCompat": false,
108
+ "forwardCompat": false
109
+ },
110
+ "ClassDeclaration_TestObjectProvider": {
111
+ "backCompat": false,
112
+ "forwardCompat": false
113
+ }
114
+ }
115
+ },
116
+ "scripts": {
117
+ "api": "fluid-build . --task api",
118
+ "api-extractor:commonjs": "api-extractor run --local",
119
+ "api-extractor:esnext": "copyfiles -u 1 \"dist/**/*-@(alpha|beta|public|untrimmed).d.ts\" lib",
120
+ "build": "fluid-build . --task build",
121
+ "build:compile": "fluid-build . --task compile",
122
+ "build:compile:min": "npm run build:compile",
123
+ "build:docs": "fluid-build . --task api",
124
+ "build:genver": "gen-version",
125
+ "build:test": "tsc --project ./src/test/tsconfig.json",
126
+ "check:are-the-types-wrong": "attw --pack",
127
+ "check:release-tags": "api-extractor run --local --config ./api-extractor-lint.json",
128
+ "ci:build:docs": "api-extractor run",
129
+ "clean": "rimraf --glob dist lib \"**/*.tsbuildinfo\" \"**/*.build.log\" _api-extractor-temp nyc",
130
+ "eslint": "eslint --format stylish src",
131
+ "eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
132
+ "format": "npm run prettier:fix",
133
+ "lint": "npm run prettier && npm run check:release-tags && npm run eslint",
134
+ "lint:fix": "npm run prettier:fix && npm run eslint:fix",
135
+ "prettier": "prettier --check . --cache --ignore-path ../../../.prettierignore",
136
+ "prettier:fix": "prettier --write . --cache --ignore-path ../../../.prettierignore",
137
+ "test": "npm run test:mocha",
138
+ "test:mocha": "mocha --recursive \"dist/test/*.spec.*js\" --exit --project src/test/tsconfig.json -r node_modules/@fluidframework/mocha-test-setup",
139
+ "test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
140
+ "tsc": "tsc",
141
+ "typetests:gen": "fluid-type-test-generator",
142
+ "typetests:prepare": "flub typetests --dir . --reset --previous --normalize"
109
143
  }
110
- }
144
+ }
@@ -0,0 +1,8 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ module.exports = {
7
+ ...require("@fluidframework/build-common/prettier.config.cjs"),
8
+ };
@@ -0,0 +1,83 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
7
+ import {
8
+ IDocumentService,
9
+ IDocumentServiceFactory,
10
+ IDocumentStorageService,
11
+ IResolvedUrl,
12
+ ISummaryContext,
13
+ } from "@fluidframework/driver-definitions";
14
+ import { ISummaryTree } from "@fluidframework/protocol-definitions";
15
+
16
+ /**
17
+ * Wraps the given IDocumentStorageService to override the `uploadSummaryWithContext` method. It calls the
18
+ * `uploadSummaryCb` whenever a summary is uploaded by the client. The summary context can be updated in the
19
+ * callback before it is uploaded to the server.
20
+ * @internal
21
+ */
22
+ export function wrapDocumentStorageService(
23
+ innerDocStorageService: IDocumentStorageService,
24
+ uploadSummaryCb: (summaryTree: ISummaryTree, context: ISummaryContext) => ISummaryContext,
25
+ ) {
26
+ const outerDocStorageService = Object.create(innerDocStorageService) as IDocumentStorageService;
27
+ outerDocStorageService.uploadSummaryWithContext = async (
28
+ summary: ISummaryTree,
29
+ context: ISummaryContext,
30
+ ): Promise<string> => {
31
+ const newContext = uploadSummaryCb(summary, context);
32
+ return innerDocStorageService.uploadSummaryWithContext(summary, newContext);
33
+ };
34
+ return outerDocStorageService;
35
+ }
36
+
37
+ /**
38
+ * Wraps the given IDocumentService to override the `connectToStorage` method. The intent is to plumb the
39
+ * `uploadSummaryCb` to the IDocumentStorageService so that it is called whenever a summary is uploaded by
40
+ * the client.
41
+ * The document storage service that is created in `connectToStorage` is wrapped by calling `wrapDocumentStorageService`
42
+ * to pass in the `uploadSummaryCb`.
43
+ * @internal
44
+ */
45
+ export function wrapDocumentService(
46
+ innerDocService: IDocumentService,
47
+ uploadSummaryCb: (summaryTree: ISummaryTree, context: ISummaryContext) => ISummaryContext,
48
+ ) {
49
+ const outerDocService = Object.create(innerDocService) as IDocumentService;
50
+ outerDocService.connectToStorage = async (): Promise<IDocumentStorageService> => {
51
+ const storageService = await innerDocService.connectToStorage();
52
+ return wrapDocumentStorageService(storageService, uploadSummaryCb);
53
+ };
54
+ return outerDocService;
55
+ }
56
+
57
+ /**
58
+ * Wraps the given IDocumentServiceFactory to override the `createDocumentService` method. The intent is to plumb
59
+ * the `uploadSummaryCb` all the way to the IDocumentStorageService so that it is called whenever a summary is
60
+ * uploaded by the client.
61
+ * The document service that is created in `createDocumentService` is wrapped by calling `wrapDocumentService` to
62
+ * pass in the `uploadSummaryCb`.
63
+ * @internal
64
+ */
65
+ export function wrapDocumentServiceFactory(
66
+ innerDocServiceFactory: IDocumentServiceFactory,
67
+ uploadSummaryCb: (summaryTree: ISummaryTree, context: ISummaryContext) => ISummaryContext,
68
+ ) {
69
+ const outerDocServiceFactory = Object.create(innerDocServiceFactory) as IDocumentServiceFactory;
70
+ outerDocServiceFactory.createDocumentService = async (
71
+ resolvedUrl: IResolvedUrl,
72
+ logger?: ITelemetryBaseLogger,
73
+ clientIsSummarizer?: boolean,
74
+ ): Promise<IDocumentService> => {
75
+ const documentService = await innerDocServiceFactory.createDocumentService(
76
+ resolvedUrl,
77
+ logger,
78
+ clientIsSummarizer,
79
+ );
80
+ return wrapDocumentService(documentService, uploadSummaryCb);
81
+ };
82
+ return outerDocServiceFactory;
83
+ }
@@ -0,0 +1,17 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { ConfigTypes, IConfigProviderBase } from "@fluidframework/core-interfaces";
7
+
8
+ /**
9
+ * @internal
10
+ */
11
+ export const mockConfigProvider = (
12
+ settings: Record<string, ConfigTypes> = {},
13
+ ): IConfigProviderBase => {
14
+ return {
15
+ getRawConfig: (name: string): ConfigTypes => settings[name],
16
+ };
17
+ };
@@ -0,0 +1,210 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { ContainerRuntimeFactoryWithDefaultDataStore } from "@fluidframework/aqueduct";
7
+ import { assert } from "@fluidframework/core-utils";
8
+ import { IContainer, IHostLoader, LoaderHeader } from "@fluidframework/container-definitions";
9
+ import {
10
+ IOnDemandSummarizeOptions,
11
+ ISummarizer,
12
+ ISummaryRuntimeOptions,
13
+ } from "@fluidframework/container-runtime";
14
+ import {
15
+ ITelemetryBaseLogger,
16
+ FluidObject,
17
+ IRequest,
18
+ IConfigProviderBase,
19
+ } from "@fluidframework/core-interfaces";
20
+ import { DriverHeader } from "@fluidframework/driver-definitions";
21
+ import {
22
+ IFluidDataStoreFactory,
23
+ NamedFluidDataStoreRegistryEntries,
24
+ } from "@fluidframework/runtime-definitions";
25
+ import { ISummaryTree } from "@fluidframework/protocol-definitions";
26
+ import { ITestContainerConfig, ITestObjectProvider } from "./testObjectProvider";
27
+ import { mockConfigProvider } from "./TestConfigs";
28
+ import { waitForContainerConnection } from "./containerUtils";
29
+ import { timeoutAwait } from "./timeoutUtils";
30
+ import { createContainerRuntimeFactoryWithDefaultDataStore } from "./testContainerRuntimeFactoryWithDefaultDataStore";
31
+
32
+ const summarizerClientType = "summarizer";
33
+
34
+ async function createSummarizerCore(
35
+ container: IContainer,
36
+ loader: IHostLoader,
37
+ summaryVersion?: string,
38
+ ) {
39
+ const absoluteUrl = await container.getAbsoluteUrl("");
40
+ if (absoluteUrl === undefined) {
41
+ throw new Error("URL could not be resolved");
42
+ }
43
+
44
+ const request: IRequest = {
45
+ headers: {
46
+ [LoaderHeader.cache]: false,
47
+ [LoaderHeader.clientDetails]: {
48
+ capabilities: { interactive: false },
49
+ type: summarizerClientType,
50
+ },
51
+ [DriverHeader.summarizingClient]: true,
52
+ [LoaderHeader.version]: summaryVersion,
53
+ },
54
+ url: absoluteUrl,
55
+ };
56
+ const summarizerContainer = await loader.resolve(request);
57
+ await waitForContainerConnection(summarizerContainer);
58
+
59
+ const fluidObject: FluidObject<ISummarizer> | undefined =
60
+ await summarizerContainer.getEntryPoint();
61
+ if (fluidObject?.ISummarizer === undefined) {
62
+ throw new Error("Fluid object does not implement ISummarizer");
63
+ }
64
+
65
+ return {
66
+ container: summarizerContainer,
67
+ summarizer: fluidObject.ISummarizer,
68
+ };
69
+ }
70
+
71
+ const defaultSummaryOptions: ISummaryRuntimeOptions = {
72
+ summaryConfigOverrides: {
73
+ state: "disableHeuristics",
74
+ maxAckWaitTime: 20000, // Some of the AFR tests take a long time to ack.
75
+ maxOpsSinceLastSummary: 7000,
76
+ initialSummarizerDelayMs: 0,
77
+ },
78
+ };
79
+
80
+ /**
81
+ * Creates a summarizer client from the given container and data store factory, and returns the summarizer client's
82
+ * IContainer and ISummarizer.
83
+ * The ISummarizer can be used to generate on-demand summaries. The IContainer can be used to fetch data stores, etc.
84
+ * @internal
85
+ */
86
+ export async function createSummarizerFromFactory(
87
+ provider: ITestObjectProvider,
88
+ container: IContainer,
89
+ dataStoreFactory: IFluidDataStoreFactory,
90
+ summaryVersion?: string,
91
+ containerRuntimeFactoryType = ContainerRuntimeFactoryWithDefaultDataStore,
92
+ registryEntries?: NamedFluidDataStoreRegistryEntries,
93
+ logger?: ITelemetryBaseLogger,
94
+ configProvider: IConfigProviderBase = mockConfigProvider(),
95
+ ): Promise<{ container: IContainer; summarizer: ISummarizer }> {
96
+ const runtimeFactory = createContainerRuntimeFactoryWithDefaultDataStore(
97
+ containerRuntimeFactoryType,
98
+ {
99
+ defaultFactory: dataStoreFactory,
100
+ registryEntries: registryEntries ?? [
101
+ [dataStoreFactory.type, Promise.resolve(dataStoreFactory)],
102
+ ],
103
+ runtimeOptions: { summaryOptions: defaultSummaryOptions },
104
+ },
105
+ );
106
+
107
+ const loader = provider.createLoader([[provider.defaultCodeDetails, runtimeFactory]], {
108
+ configProvider,
109
+ logger,
110
+ });
111
+ return createSummarizerCore(container, loader, summaryVersion);
112
+ }
113
+
114
+ /**
115
+ * Creates a summarizer client from the given container and returns the summarizer client's IContainer and ISummarizer.
116
+ * The ISummarizer can be used to generate on-demand summaries. The IContainer can be used to fetch data stores, etc.
117
+ *
118
+ * Can pass in a test config provider to enable/disable features.
119
+ * @internal
120
+ */
121
+ export async function createSummarizer(
122
+ provider: ITestObjectProvider,
123
+ container: IContainer,
124
+ config?: ITestContainerConfig,
125
+ summaryVersion?: string,
126
+ logger?: ITelemetryBaseLogger,
127
+ ): Promise<{ container: IContainer; summarizer: ISummarizer }> {
128
+ const testContainerConfig: ITestContainerConfig = {
129
+ ...config,
130
+ runtimeOptions: {
131
+ ...config?.runtimeOptions,
132
+ summaryOptions: config?.runtimeOptions?.summaryOptions ?? defaultSummaryOptions,
133
+ },
134
+ loaderProps: {
135
+ ...config?.loaderProps,
136
+ configProvider: config?.loaderProps?.configProvider ?? mockConfigProvider(),
137
+ logger,
138
+ },
139
+ };
140
+ const loader = provider.makeTestLoader(testContainerConfig);
141
+ return createSummarizerCore(container, loader, summaryVersion);
142
+ }
143
+
144
+ /**
145
+ * Summarizes on demand and returns the summary tree, the version number and the reference sequence number of the
146
+ * submitted summary.
147
+ *
148
+ * @param summarizer - The ISummarizer to use to summarize on demand
149
+ * @param inputs - Either the reason string or the full IOnDemandSummarizeOptions.
150
+ * Defaults to the reason "end-to-end test".
151
+ * @internal
152
+ */
153
+ export async function summarizeNow(
154
+ summarizer: ISummarizer,
155
+ inputs: string | IOnDemandSummarizeOptions = "end-to-end test",
156
+ ): Promise<SummaryInfo> {
157
+ const options: IOnDemandSummarizeOptions =
158
+ typeof inputs === "string" ? { reason: inputs } : inputs;
159
+ const result = summarizer.summarizeOnDemand(options);
160
+
161
+ const submitResult = await timeoutAwait(result.summarySubmitted);
162
+ if (!submitResult.success) {
163
+ if (typeof submitResult.error !== "string") {
164
+ submitResult.error.data = submitResult.data;
165
+ }
166
+ throw submitResult.error;
167
+ }
168
+ assert(
169
+ submitResult.data.stage === "submit",
170
+ "on-demand summary submitted data stage should be submit",
171
+ );
172
+ assert(submitResult.data.summaryTree !== undefined, "summary tree should exist");
173
+
174
+ const broadcastResult = await timeoutAwait(result.summaryOpBroadcasted);
175
+ if (!broadcastResult.success) {
176
+ throw broadcastResult.error;
177
+ }
178
+
179
+ const ackNackResult = await timeoutAwait(result.receivedSummaryAckOrNack);
180
+ if (!ackNackResult.success) {
181
+ throw ackNackResult.error;
182
+ }
183
+
184
+ await new Promise((resolve) => process.nextTick(resolve));
185
+
186
+ return {
187
+ summaryTree: submitResult.data.summaryTree,
188
+ summaryVersion: ackNackResult.data.summaryAckOp.contents.handle,
189
+ summaryRefSeq: submitResult.data.referenceSequenceNumber,
190
+ };
191
+ }
192
+
193
+ /**
194
+ * Summary information containing the summary tree, summary version, and summary sequence number.
195
+ * @internal
196
+ */
197
+ export interface SummaryInfo {
198
+ /**
199
+ * The summary tree generated
200
+ */
201
+ summaryTree: ISummaryTree;
202
+ /**
203
+ * Handle of the completed summary
204
+ */
205
+ summaryVersion: string;
206
+ /**
207
+ * Reference sequence number of the current summary generation
208
+ */
209
+ summaryRefSeq: number;
210
+ }
@@ -0,0 +1,90 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { IContainer } from "@fluidframework/container-definitions";
7
+ import { ConnectionState } from "@fluidframework/container-loader";
8
+ import { IResponse } from "@fluidframework/core-interfaces";
9
+ import { assert } from "@fluidframework/core-utils";
10
+ import { IDataStore } from "@fluidframework/runtime-definitions";
11
+ import { PromiseExecutor, timeoutPromise, TimeoutWithError } from "./timeoutUtils";
12
+
13
+ /**
14
+ * Utility function to wait for the specified Container to be in Connected state.
15
+ * If the Container is already connected, the Promise returns immediately; otherwise it resolves when the Container emits
16
+ * its 'connected' event.
17
+ * If failOnContainerClose === true, the returned Promise will be rejected if the container emits a 'closed' event
18
+ * before a 'connected' event.
19
+ * @param container - The container to wait for.
20
+ * @param failOnContainerClose - If true, the returned Promise will be rejected if the container emits a 'closed' event
21
+ * before a 'connected' event.
22
+ * Defaults to true.
23
+ * @param timeoutOptions - Options related to the behavior of the timeout.
24
+ * If provided, the returned Promise will reject if the container hasn't emitted relevant events in timeoutOptions.durationMs.
25
+ * If not provided, the Promise will wait indefinitely for the Container to emit its 'connected' (or 'closed', if
26
+ * failOnContainerClose === true) event.
27
+ *
28
+ * @returns A Promise that either:
29
+ * - Resolves when the specified container emits a 'connected' event (or immediately if the Container is already connected).
30
+ * - Rejects if failOnContainerClose === true and the container emits a 'closed' event before a 'connected' event.
31
+ * - Rejects after timeoutOptions.durationMs if timeoutOptions !== undefined and the container does not emit relevant
32
+ * events, within that timeframe.
33
+ * @internal
34
+ */
35
+ export async function waitForContainerConnection(
36
+ container: IContainer,
37
+ failOnContainerClose: boolean = true,
38
+ timeoutOptions?: TimeoutWithError,
39
+ ): Promise<void> {
40
+ if (container.connectionState !== ConnectionState.Connected) {
41
+ const executor: PromiseExecutor = (resolve, reject) => {
42
+ container.once("connected", () => resolve());
43
+ if (failOnContainerClose) {
44
+ container.once("closed", (error) => reject(error));
45
+ }
46
+ };
47
+
48
+ return timeoutOptions === undefined
49
+ ? new Promise(executor)
50
+ : timeoutPromise(executor, timeoutOptions);
51
+ }
52
+ }
53
+
54
+ /**
55
+ * This function should ONLY be used for back compat purposes
56
+ * LTS versions of the Loader/Container will not have the "getEntryPoint" method, so we need to fallback to "request"
57
+ * This function can be removed once LTS version of Loader moves to 2.0.0-internal.7.0.0
58
+ * @internal
59
+ */
60
+ export async function getContainerEntryPointBackCompat<T>(container: IContainer): Promise<T> {
61
+ if (container.getEntryPoint !== undefined) {
62
+ const entryPoint = await container.getEntryPoint();
63
+ // Note: We need to also check if the result of `getEntryPoint()` is defined. This is because when running
64
+ // cross version compat testing scenarios, if we create with 1.X container and load with 2.X then the
65
+ // function container.getEntryPoint will be defined for the 2.X container. However, it will not return undefined
66
+ // since the container's runtime will be on version 1.X, which does not have an entry point defined.
67
+ if (entryPoint !== undefined) {
68
+ return entryPoint as T;
69
+ }
70
+ }
71
+ const response: IResponse = await (container as any).request({ url: "/" });
72
+ assert(response.status === 200, "requesting '/' should return default data object");
73
+ return response.value as T;
74
+ }
75
+
76
+ /**
77
+ * This function should ONLY be used for back compat purposes
78
+ * Older supported versions of IDataStore do not have the "entryPoint" property, so we need to fallback to "request"
79
+ * This function can be removed once back-compat support for IDataStore moves to 2.0.0-internal.7.0.0
80
+ *
81
+ * @internal
82
+ */
83
+ export async function getDataStoreEntryPointBackCompat<T>(dataStore: IDataStore): Promise<T> {
84
+ if (dataStore.entryPoint !== undefined) {
85
+ return dataStore.entryPoint.get() as Promise<T>;
86
+ }
87
+ const response: IResponse = await (dataStore as any).request({ url: "" });
88
+ assert(response.status === 200, "empty request should return data object");
89
+ return response.value as T;
90
+ }