@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
@@ -4,9 +4,8 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.getUnexpectedLogErrorException = exports.TestObjectProvider = exports.EventAndErrorTrackingLogger = exports.createDocumentId = exports.DataObjectFactoryType = void 0;
7
+ exports.getUnexpectedLogErrorException = exports.TestObjectProviderWithVersionedLoad = exports.TestObjectProvider = exports.EventAndErrorTrackingLogger = exports.createDocumentId = exports.DataObjectFactoryType = void 0;
8
8
  const container_loader_1 = require("@fluidframework/container-loader");
9
- const driver_utils_1 = require("@fluidframework/driver-utils");
10
9
  const uuid_1 = require("uuid");
11
10
  const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
12
11
  const loaderContainerTracker_1 = require("./loaderContainerTracker");
@@ -16,11 +15,17 @@ const defaultCodeDetails = {
16
15
  package: "defaultTestPackage",
17
16
  config: {},
18
17
  };
18
+ /**
19
+ * @internal
20
+ */
19
21
  var DataObjectFactoryType;
20
22
  (function (DataObjectFactoryType) {
21
23
  DataObjectFactoryType[DataObjectFactoryType["Primed"] = 0] = "Primed";
22
24
  DataObjectFactoryType[DataObjectFactoryType["Test"] = 1] = "Test";
23
- })(DataObjectFactoryType = exports.DataObjectFactoryType || (exports.DataObjectFactoryType = {}));
25
+ })(DataObjectFactoryType || (exports.DataObjectFactoryType = DataObjectFactoryType = {}));
26
+ /**
27
+ * @internal
28
+ */
24
29
  const createDocumentId = () => (0, uuid_1.v4)();
25
30
  exports.createDocumentId = createDocumentId;
26
31
  /**
@@ -34,18 +39,20 @@ function getDocumentIdStrategy(type) {
34
39
  return {
35
40
  get: () => documentId,
36
41
  update: () => { },
37
- reset: () => { documentId = (0, exports.createDocumentId)(); },
42
+ reset: () => {
43
+ documentId = (0, exports.createDocumentId)();
44
+ },
38
45
  };
39
46
  default:
40
47
  return {
41
48
  get: () => documentId,
42
49
  update: (resolvedUrl) => {
43
- var _a;
44
50
  // Extract the document ID from the resolved container's URL and reset the ID property
45
- (0, driver_utils_1.ensureFluidResolvedUrl)(resolvedUrl);
46
- documentId = (_a = resolvedUrl.id) !== null && _a !== void 0 ? _a : documentId;
51
+ documentId = resolvedUrl?.id ?? documentId;
52
+ },
53
+ reset: () => {
54
+ documentId = (0, exports.createDocumentId)();
47
55
  },
48
- reset: () => { documentId = (0, exports.createDocumentId)(); },
49
56
  };
50
57
  }
51
58
  }
@@ -54,11 +61,24 @@ function getDocumentIdStrategy(type) {
54
61
  * It also tracks all unexpected errors.
55
62
  * At any point you call reportAndClearTrackedEvents which will provide all unexpected errors, and
56
63
  * any expected events that have not occurred.
64
+ * @internal
57
65
  */
58
- class EventAndErrorTrackingLogger extends telemetry_utils_1.TelemetryLogger {
66
+ class EventAndErrorTrackingLogger {
59
67
  constructor(baseLogger) {
60
- super();
61
68
  this.baseLogger = baseLogger;
69
+ /**
70
+ * Even if these error events are logged, tests should still be allowed to pass
71
+ * Additionally, if downgrade is true, then log as generic (e.g. to avoid polluting the e2e test logs)
72
+ */
73
+ this.allowedErrors = [
74
+ // This log was removed in current version as unnecessary, but it's still present in previous versions
75
+ {
76
+ eventName: "fluid:telemetry:Container:NoRealStorageInDetachedContainer",
77
+ downgrade: true,
78
+ },
79
+ // This log's category changes depending on the op latency. test results shouldn't be affected but if we see lots we'd like an alert from the logs.
80
+ { eventName: "fluid:telemetry:OpPerf:OpRoundtripTime" },
81
+ ];
62
82
  this.expectedEvents = [];
63
83
  this.unexpectedErrors = [];
64
84
  }
@@ -66,15 +86,14 @@ class EventAndErrorTrackingLogger extends telemetry_utils_1.TelemetryLogger {
66
86
  if (this.expectedEvents.length !== 0) {
67
87
  // we don't have to error here. just no reason not to. given the events must be
68
88
  // ordered it could be tricky to figure out problems around multiple registrations.
69
- throw new Error("Expected events already registered.\n"
70
- + "Call reportAndClearTrackedEvents to clear them before registering more");
89
+ throw new Error("Expected events already registered.\n" +
90
+ "Call reportAndClearTrackedEvents to clear them before registering more");
71
91
  }
72
92
  this.expectedEvents.push(...orderedExpectedEvents.map((event, index) => ({ index, event })));
73
93
  }
74
94
  send(event) {
75
- var _a;
76
- const ee = (_a = this.expectedEvents[0]) === null || _a === void 0 ? void 0 : _a.event;
77
- if ((ee === null || ee === void 0 ? void 0 : ee.eventName) === event.eventName) {
95
+ const ee = this.expectedEvents[0]?.event;
96
+ if (ee?.eventName === event.eventName) {
78
97
  let matches = true;
79
98
  for (const key of Object.keys(ee)) {
80
99
  if (ee[key] !== event[key]) {
@@ -95,7 +114,14 @@ class EventAndErrorTrackingLogger extends telemetry_utils_1.TelemetryLogger {
95
114
  }
96
115
  }
97
116
  if (event.category === "error") {
98
- this.unexpectedErrors.push(event);
117
+ // Check to see if this error is allowed and if its category should be downgraded
118
+ const allowedError = this.allowedErrors.find(({ eventName }) => eventName === event.eventName);
119
+ if (allowedError === undefined) {
120
+ this.unexpectedErrors.push(event);
121
+ }
122
+ else if (allowedError.downgrade) {
123
+ event.category = "generic";
124
+ }
99
125
  }
100
126
  this.baseLogger.send(event);
101
127
  }
@@ -111,6 +137,7 @@ class EventAndErrorTrackingLogger extends telemetry_utils_1.TelemetryLogger {
111
137
  exports.EventAndErrorTrackingLogger = EventAndErrorTrackingLogger;
112
138
  /**
113
139
  * Shared base class for test object provider. Contain code for loader and container creation and loading
140
+ * @internal
114
141
  */
115
142
  class TestObjectProvider {
116
143
  /**
@@ -118,76 +145,104 @@ class TestObjectProvider {
118
145
  * @param createFluidEntryPoint - callback to create a fluidEntryPoint, with an optional set of channel name
119
146
  * and factory for TestFluidObject
120
147
  */
121
- constructor(LoaderConstructor, driver, createFluidEntryPoint) {
148
+ constructor(LoaderConstructor,
149
+ /**
150
+ * {@inheritDoc ITestObjectProvider.driver}
151
+ */
152
+ driver,
153
+ /**
154
+ * {@inheritDoc ITestObjectProvider.createFluidEntryPoint}
155
+ */
156
+ createFluidEntryPoint) {
122
157
  this.LoaderConstructor = LoaderConstructor;
123
158
  this.driver = driver;
124
159
  this.createFluidEntryPoint = createFluidEntryPoint;
160
+ /**
161
+ * {@inheritDoc ITestObjectProvider."type"}
162
+ */
163
+ this.type = "TestObjectProvider";
125
164
  this._loaderContainerTracker = new loaderContainerTracker_1.LoaderContainerTracker();
126
165
  // Since documentId doesn't change we can only create/make one container. Call the load functions instead.
127
166
  this._documentCreated = false;
128
167
  this._documentIdStrategy = getDocumentIdStrategy(driver.type);
129
168
  }
169
+ /**
170
+ * {@inheritDoc ITestObjectProvider.logger}
171
+ */
130
172
  get logger() {
131
173
  if (this._logger === undefined) {
132
- this._logger = new EventAndErrorTrackingLogger(telemetry_utils_1.ChildLogger.create(getTestLogger === null || getTestLogger === void 0 ? void 0 : getTestLogger(), undefined, {
133
- all: {
134
- driverType: this.driver.type,
135
- driverEndpointName: this.driver.endpointName,
136
- driverTenantName: this.driver.tenantName,
137
- driverUserIndex: this.driver.userIndex,
174
+ this._logger = new EventAndErrorTrackingLogger((0, telemetry_utils_1.createChildLogger)({
175
+ logger: getTestLogger?.(),
176
+ properties: {
177
+ all: {
178
+ driverType: this.driver.type,
179
+ driverEndpointName: this.driver.endpointName,
180
+ driverTenantName: this.driver.tenantName,
181
+ driverUserIndex: this.driver.userIndex,
182
+ },
138
183
  },
139
184
  }));
140
185
  }
141
186
  return this._logger;
142
187
  }
188
+ set logger(logger) {
189
+ this._logger = logger;
190
+ }
191
+ /**
192
+ * {@inheritDoc ITestObjectProvider.documentServiceFactory}
193
+ */
143
194
  get documentServiceFactory() {
144
195
  if (!this._documentServiceFactory) {
145
196
  this._documentServiceFactory = this.driver.createDocumentServiceFactory();
146
197
  }
147
198
  return this._documentServiceFactory;
148
199
  }
200
+ /**
201
+ * {@inheritDoc ITestObjectProvider.urlResolver}
202
+ */
149
203
  get urlResolver() {
150
204
  if (!this._urlResolver) {
151
205
  this._urlResolver = this.driver.createUrlResolver();
152
206
  }
153
207
  return this._urlResolver;
154
208
  }
209
+ /**
210
+ * {@inheritDoc ITestObjectProvider.documentId}
211
+ */
155
212
  get documentId() {
156
213
  return this._documentIdStrategy.get();
157
214
  }
215
+ /**
216
+ * {@inheritDoc ITestObjectProvider.defaultCodeDetails}
217
+ */
158
218
  get defaultCodeDetails() {
159
219
  return defaultCodeDetails;
160
220
  }
221
+ /**
222
+ * {@inheritDoc ITestObjectProvider.opProcessingController}
223
+ */
161
224
  get opProcessingController() {
162
225
  return this._loaderContainerTracker;
163
226
  }
164
227
  /**
165
- * Create a loader. Containers created/loaded through this loader will be added to the OpProcessingController.
166
- *
167
- * Only the version of the loader will vary based on compat config. The version of
168
- * containerRuntime/dataRuntime used in fluidEntryPoint will be used as is from what is passed in.
169
- *
170
- * @param packageEntries - list of code details and fluidEntryPoint pairs.
228
+ * {@inheritDoc ITestObjectProvider.createLoader}
171
229
  */
172
230
  createLoader(packageEntries, loaderProps) {
173
- var _a, _b, _c;
174
- const multiSinkLogger = new telemetry_utils_1.MultiSinkLogger();
175
- multiSinkLogger.addLogger(this.logger);
176
- if ((loaderProps === null || loaderProps === void 0 ? void 0 : loaderProps.logger) !== undefined) {
177
- multiSinkLogger.addLogger(loaderProps.logger);
178
- }
179
- const loader = new this.LoaderConstructor(Object.assign(Object.assign({}, loaderProps), { logger: multiSinkLogger, codeLoader: (_a = loaderProps === null || loaderProps === void 0 ? void 0 : loaderProps.codeLoader) !== null && _a !== void 0 ? _a : new localCodeLoader_1.LocalCodeLoader(packageEntries), urlResolver: (_b = loaderProps === null || loaderProps === void 0 ? void 0 : loaderProps.urlResolver) !== null && _b !== void 0 ? _b : this.urlResolver, documentServiceFactory: (_c = loaderProps === null || loaderProps === void 0 ? void 0 : loaderProps.documentServiceFactory) !== null && _c !== void 0 ? _c : this.documentServiceFactory }));
231
+ const logger = (0, telemetry_utils_1.createMultiSinkLogger)({
232
+ loggers: [this.logger, loaderProps?.logger],
233
+ });
234
+ const loader = new this.LoaderConstructor({
235
+ ...loaderProps,
236
+ logger,
237
+ codeLoader: loaderProps?.codeLoader ?? new localCodeLoader_1.LocalCodeLoader(packageEntries),
238
+ urlResolver: loaderProps?.urlResolver ?? this.urlResolver,
239
+ documentServiceFactory: loaderProps?.documentServiceFactory ?? this.documentServiceFactory,
240
+ });
180
241
  this._loaderContainerTracker.add(loader);
181
242
  return loader;
182
243
  }
183
244
  /**
184
- * Create a container using a default document id and code details.
185
- * Container created is automatically added to the OpProcessingController to manage op flow
186
- *
187
- * Only the version of the loader will vary based on compat config. The version of
188
- * containerRuntime/dataRuntime used in fluidEntryPoint will be used as is from what is passed in.
189
- *
190
- * @param packageEntries - list of code details and fluidEntryPoint pairs.
245
+ * {@inheritDoc ITestObjectProvider.createContainer}
191
246
  */
192
247
  async createContainer(entryPoint, loaderProps) {
193
248
  if (this._documentCreated) {
@@ -201,22 +256,27 @@ class TestObjectProvider {
201
256
  this._documentIdStrategy.update(container.resolvedUrl);
202
257
  return container;
203
258
  }
259
+ /**
260
+ * {@inheritDoc ITestObjectProvider.loadContainer}
261
+ */
204
262
  async loadContainer(entryPoint, loaderProps, requestHeader) {
205
263
  const loader = this.createLoader([[defaultCodeDetails, entryPoint]], loaderProps);
206
- return loader.resolve({ url: await this.driver.createContainerUrl(this.documentId), headers: requestHeader });
264
+ return this.resolveContainer(loader, requestHeader);
265
+ }
266
+ async resolveContainer(loader, headers) {
267
+ return loader.resolve({
268
+ url: await this.driver.createContainerUrl(this.documentId),
269
+ headers,
270
+ });
207
271
  }
208
272
  /**
209
- * Make a test loader. Containers created/loaded through this loader will be added to the OpProcessingController.
210
- * The version of the loader/containerRuntime/dataRuntime may vary based on compat config of the current run
211
- * @param testContainerConfig - optional configuring the test Container
273
+ * {@inheritDoc ITestObjectProvider.makeTestLoader}
212
274
  */
213
275
  makeTestLoader(testContainerConfig) {
214
- return this.createLoader([[defaultCodeDetails, this.createFluidEntryPoint(testContainerConfig)]], testContainerConfig === null || testContainerConfig === void 0 ? void 0 : testContainerConfig.loaderProps);
276
+ return this.createLoader([[defaultCodeDetails, this.createFluidEntryPoint(testContainerConfig)]], testContainerConfig?.loaderProps);
215
277
  }
216
278
  /**
217
- * Make a container using a default document id and code details
218
- * Container loaded is automatically added to the OpProcessingController to manage op flow
219
- * @param testContainerConfig - optional configuring the test Container
279
+ * {@inheritDoc ITestObjectProvider.makeTestContainer}
220
280
  */
221
281
  async makeTestContainer(testContainerConfig) {
222
282
  if (this._documentCreated) {
@@ -231,20 +291,17 @@ class TestObjectProvider {
231
291
  return container;
232
292
  }
233
293
  /**
234
- * Load a container using a default document id and code details.
235
- * IContainer loaded is automatically added to the OpProcessingController to manage op flow
236
- * @param testContainerConfig - optional configuring the test Container
237
- * @param requestHeader - optional headers to be supplied to the loader
294
+ * {@inheritDoc ITestObjectProvider.loadTestContainer}
238
295
  */
239
296
  async loadTestContainer(testContainerConfig, requestHeader) {
240
297
  const loader = this.makeTestLoader(testContainerConfig);
241
- const container = await loader.resolve({
242
- url: await this.driver.createContainerUrl(this.documentId),
243
- headers: requestHeader,
244
- });
298
+ const container = await this.resolveContainer(loader, requestHeader);
245
299
  await this.waitContainerToCatchUp(container);
246
300
  return container;
247
301
  }
302
+ /**
303
+ * {@inheritDoc ITestObjectProvider.reset}
304
+ */
248
305
  reset() {
249
306
  this._loaderContainerTracker.reset();
250
307
  this._documentServiceFactory = undefined;
@@ -257,6 +314,9 @@ class TestObjectProvider {
257
314
  this._logger = undefined;
258
315
  this._documentCreated = false;
259
316
  }
317
+ /**
318
+ * {@inheritDoc ITestObjectProvider.ensureSynchronized}
319
+ */
260
320
  async ensureSynchronized() {
261
321
  return this._loaderContainerTracker.ensureSynchronized();
262
322
  }
@@ -270,25 +330,281 @@ class TestObjectProvider {
270
330
  }
271
331
  return (0, container_loader_1.waitContainerToCatchUp)(container);
272
332
  }
333
+ /**
334
+ * {@inheritDoc ITestObjectProvider.updateDocumentId}
335
+ */
273
336
  updateDocumentId(resolvedUrl) {
274
337
  this._documentIdStrategy.update(resolvedUrl);
275
338
  }
339
+ /**
340
+ * {@inheritDoc ITestObjectProvider.resetLoaderContainerTracker}
341
+ */
276
342
  resetLoaderContainerTracker(syncSummarizerClients = false) {
277
343
  this._loaderContainerTracker.reset();
278
344
  this._loaderContainerTracker = new loaderContainerTracker_1.LoaderContainerTracker(syncSummarizerClients);
279
345
  }
280
346
  }
281
347
  exports.TestObjectProvider = TestObjectProvider;
348
+ /**
349
+ * Implements {@link ITestObjectProvider}, but uses different versions to create and load containers.
350
+ *
351
+ * @internal
352
+ */
353
+ class TestObjectProviderWithVersionedLoad {
354
+ constructor(LoaderConstructorForCreating, LoaderConstructorForLoading, driverForCreating, driverForLoading, createFluidEntryPointForCreating, createFluidEntryPointForLoading) {
355
+ this.LoaderConstructorForCreating = LoaderConstructorForCreating;
356
+ this.LoaderConstructorForLoading = LoaderConstructorForLoading;
357
+ this.driverForCreating = driverForCreating;
358
+ this.driverForLoading = driverForLoading;
359
+ this.createFluidEntryPointForCreating = createFluidEntryPointForCreating;
360
+ this.createFluidEntryPointForLoading = createFluidEntryPointForLoading;
361
+ /**
362
+ * {@inheritDoc ITestObjectProvider."type"}
363
+ */
364
+ this.type = "TestObjectProviderWithVersionedLoad";
365
+ this._loaderContainerTracker = new loaderContainerTracker_1.LoaderContainerTracker();
366
+ // Since documentId doesn't change we can only create/make one container. Call the load functions instead.
367
+ this._documentCreated = false;
368
+ /**
369
+ * `_loadCount` is used to alternate which version we load the next container with.
370
+ * loadCount is even then we will load with the "create" version, and if odd we load with the "load" version.
371
+ * After each test we will reset loadCount to 0 to ensure we always create the first container with the create version.
372
+ *
373
+ * Note: This will only affect tests that load a container more than two times.
374
+ */
375
+ this._loadCount = 0;
376
+ this._documentIdStrategy = getDocumentIdStrategy(driverForCreating.type);
377
+ }
378
+ /**
379
+ * {@inheritDoc ITestObjectProvider.logger}
380
+ */
381
+ get logger() {
382
+ if (this._logger === undefined) {
383
+ this._logger = new EventAndErrorTrackingLogger((0, telemetry_utils_1.createChildLogger)({
384
+ logger: getTestLogger?.(),
385
+ }));
386
+ }
387
+ return this._logger;
388
+ }
389
+ /**
390
+ * {@inheritDoc ITestObjectProvider.documentServiceFactory}
391
+ */
392
+ get documentServiceFactory() {
393
+ if (!this._documentServiceFactory) {
394
+ this._documentServiceFactory = this.driverForCreating.createDocumentServiceFactory();
395
+ }
396
+ return this._documentServiceFactory;
397
+ }
398
+ /**
399
+ * {@inheritDoc ITestObjectProvider.urlResolver}
400
+ */
401
+ get urlResolver() {
402
+ if (!this._urlResolver) {
403
+ this._urlResolver = this.driverForCreating.createUrlResolver();
404
+ }
405
+ return this._urlResolver;
406
+ }
407
+ /**
408
+ * {@inheritDoc ITestObjectProvider.documentId}
409
+ */
410
+ get documentId() {
411
+ return this._documentIdStrategy.get();
412
+ }
413
+ /**
414
+ * {@inheritDoc ITestObjectProvider.defaultCodeDetails}
415
+ */
416
+ get defaultCodeDetails() {
417
+ return defaultCodeDetails;
418
+ }
419
+ /**
420
+ * {@inheritDoc ITestObjectProvider.opProcessingController}
421
+ */
422
+ get opProcessingController() {
423
+ return this._loaderContainerTracker;
424
+ }
425
+ /**
426
+ * {@inheritDoc ITestObjectProvider.driver}
427
+ */
428
+ get driver() {
429
+ return this.nextLoaderShouldCreate() ? this.driverForCreating : this.driverForLoading;
430
+ }
431
+ /**
432
+ * {@inheritDoc ITestObjectProvider.createFluidEntryPoint}
433
+ */
434
+ get createFluidEntryPoint() {
435
+ return this.nextLoaderShouldCreate()
436
+ ? this.createFluidEntryPointForCreating
437
+ : this.createFluidEntryPointForLoading;
438
+ }
439
+ createLoaderForCreating(packageEntries, loaderProps) {
440
+ const logger = (0, telemetry_utils_1.createMultiSinkLogger)({
441
+ loggers: [this.logger, loaderProps?.logger],
442
+ });
443
+ const loader = new this.LoaderConstructorForCreating({
444
+ ...loaderProps,
445
+ logger,
446
+ codeLoader: loaderProps?.codeLoader ?? new localCodeLoader_1.LocalCodeLoader(packageEntries),
447
+ urlResolver: loaderProps?.urlResolver ?? this.urlResolver,
448
+ documentServiceFactory: loaderProps?.documentServiceFactory ?? this.documentServiceFactory,
449
+ });
450
+ this._loaderContainerTracker.add(loader);
451
+ return loader;
452
+ }
453
+ createLoaderForLoading(packageEntries, loaderProps) {
454
+ const logger = (0, telemetry_utils_1.createMultiSinkLogger)({
455
+ loggers: [this.logger, loaderProps?.logger],
456
+ });
457
+ const loader = new this.LoaderConstructorForLoading({
458
+ ...loaderProps,
459
+ logger,
460
+ codeLoader: loaderProps?.codeLoader ?? new localCodeLoader_1.LocalCodeLoader(packageEntries),
461
+ urlResolver: loaderProps?.urlResolver ?? this.urlResolver,
462
+ documentServiceFactory: loaderProps?.documentServiceFactory ?? this.documentServiceFactory,
463
+ });
464
+ this._loaderContainerTracker.add(loader);
465
+ return loader;
466
+ }
467
+ /**
468
+ * {@inheritDoc ITestObjectProvider.createLoader}
469
+ */
470
+ createLoader(packageEntries, loaderProps) {
471
+ return this.nextLoaderShouldCreate(/** increment */ true)
472
+ ? this.createLoaderForCreating(packageEntries, loaderProps)
473
+ : this.createLoaderForLoading(packageEntries, loaderProps);
474
+ }
475
+ /**
476
+ * {@inheritDoc ITestObjectProvider.createContainer}
477
+ */
478
+ async createContainer(entryPoint, loaderProps) {
479
+ if (this._documentCreated) {
480
+ throw new Error("Only one container/document can be created. To load the container/document use loadContainer");
481
+ }
482
+ const loader = this.createLoader([[defaultCodeDetails, entryPoint]], loaderProps);
483
+ const container = await (0, localLoader_1.createAndAttachContainer)(defaultCodeDetails, loader, this.driverForCreating.createCreateNewRequest(this.documentId));
484
+ this._documentCreated = true;
485
+ // r11s driver will generate a new ID for the new container.
486
+ // update the document ID with the actual ID of the attached container.
487
+ this._documentIdStrategy.update(container.resolvedUrl);
488
+ return container;
489
+ }
490
+ /**
491
+ * {@inheritDoc ITestObjectProvider.loadContainer}
492
+ */
493
+ async loadContainer(entryPoint, loaderProps, requestHeader) {
494
+ const driver = this.nextLoaderShouldCreate()
495
+ ? this.driverForCreating
496
+ : this.driverForLoading;
497
+ const loader = this.createLoader([[defaultCodeDetails, entryPoint]], loaderProps);
498
+ return this.resolveContainer(loader, requestHeader, driver);
499
+ }
500
+ async resolveContainer(loader, headers, driver) {
501
+ return loader.resolve({
502
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
503
+ url: await driver.createContainerUrl(this.documentId),
504
+ headers,
505
+ });
506
+ }
507
+ /**
508
+ * {@inheritDoc ITestObjectProvider.makeTestLoader}
509
+ */
510
+ makeTestLoader(testContainerConfig) {
511
+ return this.createLoader([[defaultCodeDetails, this.createFluidEntryPoint(testContainerConfig)]], testContainerConfig?.loaderProps);
512
+ }
513
+ /**
514
+ * {@inheritDoc ITestObjectProvider.makeTestContainer}
515
+ */
516
+ async makeTestContainer(testContainerConfig) {
517
+ if (this._documentCreated) {
518
+ throw new Error("Only one container/document can be created. To load the container/document use loadTestContainer");
519
+ }
520
+ const loader = this.createLoader([[defaultCodeDetails, this.createFluidEntryPoint(testContainerConfig)]], testContainerConfig?.loaderProps);
521
+ const container = await (0, localLoader_1.createAndAttachContainer)(defaultCodeDetails, loader, this.driverForCreating.createCreateNewRequest(this.documentId));
522
+ this._documentCreated = true;
523
+ // r11s driver will generate a new ID for the new container.
524
+ // update the document ID with the actual ID of the attached container.
525
+ this._documentIdStrategy.update(container.resolvedUrl);
526
+ return container;
527
+ }
528
+ /**
529
+ * {@inheritDoc ITestObjectProvider.loadTestContainer}
530
+ */
531
+ async loadTestContainer(testContainerConfig, requestHeader) {
532
+ // Keep track of which Loader we are about to use so we can pass the correct driver through
533
+ const driver = this.nextLoaderShouldCreate()
534
+ ? this.driverForCreating
535
+ : this.driverForLoading;
536
+ const loader = this.makeTestLoader(testContainerConfig);
537
+ const container = await this.resolveContainer(loader, requestHeader, driver);
538
+ await this.waitContainerToCatchUp(container);
539
+ return container;
540
+ }
541
+ /**
542
+ * {@inheritDoc ITestObjectProvider.reset}
543
+ */
544
+ reset() {
545
+ this._loadCount = 0;
546
+ this._loaderContainerTracker.reset();
547
+ this._logger = undefined;
548
+ this._documentServiceFactory = undefined;
549
+ this._urlResolver = undefined;
550
+ this._documentIdStrategy.reset();
551
+ const logError = getUnexpectedLogErrorException(this._logger);
552
+ if (logError) {
553
+ throw logError;
554
+ }
555
+ this._documentCreated = false;
556
+ }
557
+ /**
558
+ * {@inheritDoc ITestObjectProvider.ensureSynchronized}
559
+ */
560
+ async ensureSynchronized() {
561
+ return this._loaderContainerTracker.ensureSynchronized();
562
+ }
563
+ async waitContainerToCatchUp(container) {
564
+ // The original waitContainerToCatchUp() from container loader uses either Container.resume()
565
+ // or Container.connect() as part of its implementation. However, resume() was deprecated
566
+ // and eventually replaced with connect(). To avoid issues during LTS compatibility testing
567
+ // with older container versions issues, we use resume() when connect() is unavailable.
568
+ if (container.connect === undefined) {
569
+ container.connect = container.resume;
570
+ }
571
+ return (0, container_loader_1.waitContainerToCatchUp)(container);
572
+ }
573
+ /**
574
+ * {@inheritDoc ITestObjectProvider.updateDocumentId}
575
+ */
576
+ updateDocumentId(resolvedUrl) {
577
+ this._documentIdStrategy.update(resolvedUrl);
578
+ }
579
+ /**
580
+ * {@inheritDoc ITestObjectProvider.resetLoaderContainerTracker}
581
+ */
582
+ resetLoaderContainerTracker(syncSummarizerClients = false) {
583
+ this._loaderContainerTracker.reset();
584
+ this._loaderContainerTracker = new loaderContainerTracker_1.LoaderContainerTracker(syncSummarizerClients);
585
+ }
586
+ nextLoaderShouldCreate(increment = false) {
587
+ const shouldCreate = this._loadCount % 2 === 0;
588
+ if (increment) {
589
+ this._loadCount++;
590
+ }
591
+ return shouldCreate;
592
+ }
593
+ }
594
+ exports.TestObjectProviderWithVersionedLoad = TestObjectProviderWithVersionedLoad;
595
+ /**
596
+ * @internal
597
+ */
282
598
  function getUnexpectedLogErrorException(logger, prefix) {
283
599
  if (logger === undefined) {
284
600
  return;
285
601
  }
286
602
  const results = logger.reportAndClearTrackedEvents();
287
603
  if (results.unexpectedErrors.length > 0) {
288
- return new Error(`${prefix !== null && prefix !== void 0 ? prefix : ""}Unexpected Errors in Logs:\n${JSON.stringify(results.unexpectedErrors, undefined, 2)}`);
604
+ return new Error(`${prefix ?? ""}Unexpected Errors in Logs:\n${JSON.stringify(results.unexpectedErrors, undefined, 2)}`);
289
605
  }
290
606
  if (results.expectedNotFound.length > 0) {
291
- return new Error(`${prefix !== null && prefix !== void 0 ? prefix : ""}Expected Events not found:\n${JSON.stringify(results.expectedNotFound, undefined, 2)}`);
607
+ return new Error(`${prefix ?? ""}Expected Events not found:\n${JSON.stringify(results.expectedNotFound, undefined, 2)}`);
292
608
  }
293
609
  }
294
610
  exports.getUnexpectedLogErrorException = getUnexpectedLogErrorException;