@fluidframework/test-utils 2.0.0-rc.1.0.6 → 2.0.0-rc.2.0.1

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 (151) hide show
  1. package/{.eslintrc.js → .eslintrc.cjs} +4 -1
  2. package/{.mocharc.js → .mocharc.cjs} +1 -1
  3. package/CHANGELOG.md +34 -0
  4. package/README.md +1 -1
  5. package/api-extractor-cjs.json +8 -0
  6. package/api-extractor-lint.json +1 -1
  7. package/api-extractor.json +1 -1
  8. package/api-report/test-utils.api.md +27 -9
  9. package/dist/DriverWrappers.d.ts +3 -0
  10. package/dist/DriverWrappers.d.ts.map +1 -1
  11. package/dist/DriverWrappers.js +3 -0
  12. package/dist/DriverWrappers.js.map +1 -1
  13. package/dist/TestConfigs.d.ts +14 -1
  14. package/dist/TestConfigs.d.ts.map +1 -1
  15. package/dist/TestConfigs.js +14 -3
  16. package/dist/TestConfigs.js.map +1 -1
  17. package/dist/TestSummaryUtils.d.ts +7 -2
  18. package/dist/TestSummaryUtils.d.ts.map +1 -1
  19. package/dist/TestSummaryUtils.js +39 -14
  20. package/dist/TestSummaryUtils.js.map +1 -1
  21. package/dist/containerUtils.d.ts +1 -1
  22. package/dist/containerUtils.d.ts.map +1 -1
  23. package/dist/containerUtils.js +2 -2
  24. package/dist/containerUtils.js.map +1 -1
  25. package/dist/debug.js +2 -2
  26. package/dist/debug.js.map +1 -1
  27. package/dist/index.d.ts +14 -14
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +44 -43
  30. package/dist/index.js.map +1 -1
  31. package/dist/loaderContainerTracker.d.ts +1 -1
  32. package/dist/loaderContainerTracker.d.ts.map +1 -1
  33. package/dist/loaderContainerTracker.js +11 -11
  34. package/dist/loaderContainerTracker.js.map +1 -1
  35. package/dist/localLoader.d.ts +1 -1
  36. package/dist/localLoader.d.ts.map +1 -1
  37. package/dist/localLoader.js +2 -2
  38. package/dist/localLoader.js.map +1 -1
  39. package/dist/package.json +3 -0
  40. package/dist/packageVersion.d.ts +1 -1
  41. package/dist/packageVersion.js +1 -1
  42. package/dist/packageVersion.js.map +1 -1
  43. package/dist/test-utils-alpha.d.ts +7 -3
  44. package/dist/test-utils-beta.d.ts +9 -3
  45. package/dist/test-utils-public.d.ts +9 -3
  46. package/dist/test-utils-untrimmed.d.ts +59 -14
  47. package/dist/testContainerRuntimeFactory.d.ts.map +1 -1
  48. package/dist/testContainerRuntimeFactory.js +9 -2
  49. package/dist/testContainerRuntimeFactory.js.map +1 -1
  50. package/dist/testFluidObject.d.ts +1 -1
  51. package/dist/testFluidObject.d.ts.map +1 -1
  52. package/dist/testFluidObject.js.map +1 -1
  53. package/dist/testObjectProvider.d.ts +34 -11
  54. package/dist/testObjectProvider.d.ts.map +1 -1
  55. package/dist/testObjectProvider.js +71 -38
  56. package/dist/testObjectProvider.js.map +1 -1
  57. package/dist/timeoutUtils.d.ts.map +1 -1
  58. package/dist/timeoutUtils.js.map +1 -1
  59. package/dist/tsdoc-metadata.json +1 -1
  60. package/lib/DriverWrappers.d.ts +35 -0
  61. package/lib/DriverWrappers.d.ts.map +1 -0
  62. package/lib/DriverWrappers.js +54 -0
  63. package/lib/DriverWrappers.js.map +1 -0
  64. package/lib/TestConfigs.d.ts +23 -0
  65. package/lib/TestConfigs.d.ts.map +1 -0
  66. package/lib/TestConfigs.js +24 -0
  67. package/lib/TestConfigs.js.map +1 -0
  68. package/lib/TestSummaryUtils.d.ts +66 -0
  69. package/lib/TestSummaryUtils.d.ts.map +1 -0
  70. package/lib/TestSummaryUtils.js +153 -0
  71. package/lib/TestSummaryUtils.js.map +1 -0
  72. package/lib/containerUtils.d.ts +46 -0
  73. package/lib/containerUtils.d.ts.map +1 -0
  74. package/lib/containerUtils.js +79 -0
  75. package/lib/containerUtils.js.map +1 -0
  76. package/lib/debug.d.ts +7 -0
  77. package/lib/debug.d.ts.map +1 -0
  78. package/lib/debug.js +9 -0
  79. package/lib/debug.js.map +1 -0
  80. package/lib/index.d.ts +19 -0
  81. package/lib/index.d.ts.map +1 -0
  82. package/lib/index.js +18 -0
  83. package/lib/index.js.map +1 -0
  84. package/lib/interfaces.d.ts +25 -0
  85. package/lib/interfaces.d.ts.map +1 -0
  86. package/lib/interfaces.js +6 -0
  87. package/lib/interfaces.js.map +1 -0
  88. package/lib/loaderContainerTracker.d.ts +144 -0
  89. package/lib/loaderContainerTracker.d.ts.map +1 -0
  90. package/lib/loaderContainerTracker.js +631 -0
  91. package/lib/loaderContainerTracker.js.map +1 -0
  92. package/lib/localCodeLoader.d.ts +31 -0
  93. package/lib/localCodeLoader.d.ts.map +1 -0
  94. package/lib/localCodeLoader.js +73 -0
  95. package/lib/localCodeLoader.js.map +1 -0
  96. package/lib/localLoader.d.ts +26 -0
  97. package/lib/localLoader.d.ts.map +1 -0
  98. package/lib/localLoader.js +37 -0
  99. package/lib/localLoader.js.map +1 -0
  100. package/lib/packageVersion.d.ts +9 -0
  101. package/lib/packageVersion.d.ts.map +1 -0
  102. package/lib/packageVersion.js +9 -0
  103. package/lib/packageVersion.js.map +1 -0
  104. package/lib/retry.d.ts +18 -0
  105. package/lib/retry.d.ts.map +1 -0
  106. package/lib/retry.js +37 -0
  107. package/lib/retry.js.map +1 -0
  108. package/lib/test/timeoutUtils.spec.js +165 -0
  109. package/lib/test/timeoutUtils.spec.js.map +1 -0
  110. package/lib/test/types/validateTestUtilsPrevious.generated.js +90 -0
  111. package/lib/test/types/validateTestUtilsPrevious.generated.js.map +1 -0
  112. package/lib/test-utils-alpha.d.ts +309 -0
  113. package/lib/test-utils-beta.d.ts +208 -0
  114. package/lib/test-utils-public.d.ts +208 -0
  115. package/lib/test-utils-untrimmed.d.ts +1046 -0
  116. package/lib/testContainerRuntimeFactory.d.ts +46 -0
  117. package/lib/testContainerRuntimeFactory.d.ts.map +1 -0
  118. package/lib/testContainerRuntimeFactory.js +113 -0
  119. package/lib/testContainerRuntimeFactory.js.map +1 -0
  120. package/lib/testContainerRuntimeFactoryWithDefaultDataStore.d.ts +23 -0
  121. package/lib/testContainerRuntimeFactoryWithDefaultDataStore.d.ts.map +1 -0
  122. package/lib/testContainerRuntimeFactoryWithDefaultDataStore.js +28 -0
  123. package/lib/testContainerRuntimeFactoryWithDefaultDataStore.js.map +1 -0
  124. package/lib/testFluidObject.d.ts +92 -0
  125. package/lib/testFluidObject.d.ts.map +1 -0
  126. package/lib/testFluidObject.js +159 -0
  127. package/lib/testFluidObject.js.map +1 -0
  128. package/lib/testObjectProvider.d.ts +435 -0
  129. package/lib/testObjectProvider.d.ts.map +1 -0
  130. package/lib/testObjectProvider.js +636 -0
  131. package/lib/testObjectProvider.js.map +1 -0
  132. package/lib/timeoutUtils.d.ts +60 -0
  133. package/lib/timeoutUtils.d.ts.map +1 -0
  134. package/lib/timeoutUtils.js +164 -0
  135. package/lib/timeoutUtils.js.map +1 -0
  136. package/package.json +105 -38
  137. package/src/DriverWrappers.ts +3 -0
  138. package/src/TestConfigs.ts +25 -3
  139. package/src/TestSummaryUtils.ts +36 -12
  140. package/src/containerUtils.ts +1 -1
  141. package/src/debug.ts +1 -1
  142. package/src/index.ts +19 -14
  143. package/src/loaderContainerTracker.ts +5 -5
  144. package/src/localLoader.ts +1 -1
  145. package/src/packageVersion.ts +1 -1
  146. package/src/testContainerRuntimeFactory.ts +12 -2
  147. package/src/testFluidObject.ts +1 -1
  148. package/src/testObjectProvider.ts +99 -34
  149. package/src/timeoutUtils.ts +1 -0
  150. package/tsconfig.cjs.json +7 -0
  151. package/tsconfig.json +3 -4
@@ -0,0 +1,636 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ import { waitContainerToCatchUp as waitContainerToCatchUp_original, } from "@fluidframework/container-loader";
6
+ import { v4 as uuid } from "uuid";
7
+ import { createChildLogger, createMultiSinkLogger, } from "@fluidframework/telemetry-utils";
8
+ import { LoaderContainerTracker } from "./loaderContainerTracker.js";
9
+ import { LocalCodeLoader } from "./localCodeLoader.js";
10
+ import { createAndAttachContainer } from "./localLoader.js";
11
+ const defaultCodeDetails = {
12
+ package: "defaultTestPackage",
13
+ config: {},
14
+ };
15
+ /**
16
+ * @internal
17
+ */
18
+ export var DataObjectFactoryType;
19
+ (function (DataObjectFactoryType) {
20
+ DataObjectFactoryType[DataObjectFactoryType["Primed"] = 0] = "Primed";
21
+ DataObjectFactoryType[DataObjectFactoryType["Test"] = 1] = "Test";
22
+ })(DataObjectFactoryType || (DataObjectFactoryType = {}));
23
+ /**
24
+ * @internal
25
+ */
26
+ export const createDocumentId = () => uuid();
27
+ /**
28
+ * Document ID is treated differently by test drivers. The key difference is in generating
29
+ * a new container ID and accessing the container in multi-instance test cases.
30
+ */
31
+ function getDocumentIdStrategy(type) {
32
+ let documentId = createDocumentId();
33
+ switch (type) {
34
+ case "odsp":
35
+ return {
36
+ get: () => documentId,
37
+ update: () => { },
38
+ reset: () => {
39
+ documentId = createDocumentId();
40
+ },
41
+ };
42
+ default:
43
+ return {
44
+ get: () => documentId,
45
+ update: (resolvedUrl) => {
46
+ // Extract the document ID from the resolved container's URL and reset the ID property
47
+ documentId = resolvedUrl?.id ?? documentId;
48
+ },
49
+ reset: () => {
50
+ documentId = createDocumentId();
51
+ },
52
+ };
53
+ }
54
+ }
55
+ /**
56
+ * This class tracks events. It allows specifying expected events, which will be looked for in order.
57
+ * It also tracks all unexpected errors.
58
+ * At any point you call reportAndClearTrackedEvents which will provide all unexpected errors, and
59
+ * any expected events that have not occurred.
60
+ * @internal
61
+ */
62
+ export class EventAndErrorTrackingLogger {
63
+ constructor(baseLogger) {
64
+ this.baseLogger = baseLogger;
65
+ /**
66
+ * Even if these error events are logged, tests should still be allowed to pass
67
+ * Additionally, if downgrade is true, then log as generic (e.g. to avoid polluting the e2e test logs)
68
+ */
69
+ this.allowedErrors = [
70
+ // This log was removed in current version as unnecessary, but it's still present in previous versions
71
+ {
72
+ eventName: "fluid:telemetry:Container:NoRealStorageInDetachedContainer",
73
+ downgrade: true,
74
+ },
75
+ // 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.
76
+ { eventName: "fluid:telemetry:OpPerf:OpRoundtripTime" },
77
+ ];
78
+ this.expectedEvents = [];
79
+ this.unexpectedErrors = [];
80
+ }
81
+ registerExpectedEvent(...orderedExpectedEvents) {
82
+ if (this.expectedEvents.length !== 0) {
83
+ // we don't have to error here. just no reason not to. given the events must be
84
+ // ordered it could be tricky to figure out problems around multiple registrations.
85
+ throw new Error("Expected events already registered.\n" +
86
+ "Call reportAndClearTrackedEvents to clear them before registering more");
87
+ }
88
+ this.expectedEvents.push(...orderedExpectedEvents.map((event, index) => ({ index, event })));
89
+ }
90
+ send(event) {
91
+ const ee = this.expectedEvents[0]?.event;
92
+ if (ee?.eventName === event.eventName) {
93
+ let matches = true;
94
+ for (const key of Object.keys(ee)) {
95
+ if (ee[key] !== event[key]) {
96
+ matches = false;
97
+ break;
98
+ }
99
+ }
100
+ if (matches) {
101
+ // we found an expected event
102
+ // so remove it from the list of expected events
103
+ // and if it is an error, change it to generic
104
+ // this helps keep our telemetry clear of
105
+ // expected errors.
106
+ this.expectedEvents.shift();
107
+ if (event.category === "error") {
108
+ event.category = "generic";
109
+ }
110
+ }
111
+ }
112
+ if (event.category === "error") {
113
+ // Check to see if this error is allowed and if its category should be downgraded
114
+ const allowedError = this.allowedErrors.find(({ eventName }) => eventName === event.eventName);
115
+ if (allowedError === undefined) {
116
+ this.unexpectedErrors.push(event);
117
+ }
118
+ else if (allowedError.downgrade) {
119
+ event.category = "generic";
120
+ }
121
+ }
122
+ this.baseLogger.send(event);
123
+ }
124
+ reportAndClearTrackedEvents() {
125
+ const expectedNotFound = this.expectedEvents.splice(0, this.expectedEvents.length);
126
+ const unexpectedErrors = this.unexpectedErrors.splice(0, this.unexpectedErrors.length);
127
+ return {
128
+ expectedNotFound,
129
+ unexpectedErrors,
130
+ };
131
+ }
132
+ }
133
+ /**
134
+ * Shared base class for test object provider. Contain code for loader and container creation and loading
135
+ * @internal
136
+ */
137
+ export class TestObjectProvider {
138
+ /**
139
+ * Manage objects for loading and creating container, including the driver, loader, and OpProcessingController
140
+ * @param createFluidEntryPoint - callback to create a fluidEntryPoint, with an optional set of channel name
141
+ * and factory for TestFluidObject
142
+ */
143
+ constructor(LoaderConstructor,
144
+ /**
145
+ * {@inheritDoc ITestObjectProvider.driver}
146
+ */
147
+ driver,
148
+ /**
149
+ * {@inheritDoc ITestObjectProvider.createFluidEntryPoint}
150
+ */
151
+ createFluidEntryPoint) {
152
+ this.LoaderConstructor = LoaderConstructor;
153
+ this.driver = driver;
154
+ this.createFluidEntryPoint = createFluidEntryPoint;
155
+ /**
156
+ * {@inheritDoc ITestObjectProvider."type"}
157
+ */
158
+ this.type = "TestObjectProvider";
159
+ this._loaderContainerTracker = new LoaderContainerTracker();
160
+ // Since documentId doesn't change we can only create/make one container. Call the load functions instead.
161
+ this._documentCreated = false;
162
+ this._documentIdStrategy = getDocumentIdStrategy(driver.type);
163
+ }
164
+ /**
165
+ * {@inheritDoc ITestObjectProvider.logger}
166
+ */
167
+ get logger() {
168
+ if (this._logger === undefined) {
169
+ this._logger = new EventAndErrorTrackingLogger(createChildLogger({
170
+ logger: getTestLogger?.(),
171
+ properties: {
172
+ all: {
173
+ driverType: this.driver.type,
174
+ driverEndpointName: this.driver.endpointName,
175
+ driverTenantName: this.driver.tenantName,
176
+ driverUserIndex: this.driver.userIndex,
177
+ },
178
+ },
179
+ }));
180
+ }
181
+ return this._logger;
182
+ }
183
+ set logger(logger) {
184
+ this._logger = logger;
185
+ }
186
+ /**
187
+ * {@inheritDoc ITestObjectProvider.documentServiceFactory}
188
+ */
189
+ get documentServiceFactory() {
190
+ if (!this._documentServiceFactory) {
191
+ this._documentServiceFactory = this.driver.createDocumentServiceFactory();
192
+ }
193
+ return this._documentServiceFactory;
194
+ }
195
+ /**
196
+ * {@inheritDoc ITestObjectProvider.urlResolver}
197
+ */
198
+ get urlResolver() {
199
+ if (!this._urlResolver) {
200
+ this._urlResolver = this.driver.createUrlResolver();
201
+ }
202
+ return this._urlResolver;
203
+ }
204
+ /**
205
+ * {@inheritDoc ITestObjectProvider.documentId}
206
+ */
207
+ get documentId() {
208
+ return this._documentIdStrategy.get();
209
+ }
210
+ /**
211
+ * {@inheritDoc ITestObjectProvider.defaultCodeDetails}
212
+ */
213
+ get defaultCodeDetails() {
214
+ return defaultCodeDetails;
215
+ }
216
+ /**
217
+ * {@inheritDoc ITestObjectProvider.opProcessingController}
218
+ */
219
+ get opProcessingController() {
220
+ return this._loaderContainerTracker;
221
+ }
222
+ /**
223
+ * {@inheritDoc ITestObjectProvider.createLoader}
224
+ */
225
+ createLoader(packageEntries, loaderProps) {
226
+ const logger = createMultiSinkLogger({
227
+ loggers: [this.logger, loaderProps?.logger],
228
+ });
229
+ const loader = new this.LoaderConstructor({
230
+ ...loaderProps,
231
+ logger,
232
+ codeLoader: loaderProps?.codeLoader ?? new LocalCodeLoader(packageEntries),
233
+ urlResolver: loaderProps?.urlResolver ?? this.urlResolver,
234
+ documentServiceFactory: loaderProps?.documentServiceFactory ?? this.documentServiceFactory,
235
+ });
236
+ this._loaderContainerTracker.add(loader);
237
+ return loader;
238
+ }
239
+ /**
240
+ * {@inheritDoc ITestObjectProvider.createContainer}
241
+ */
242
+ async createContainer(entryPoint, loaderProps) {
243
+ if (this._documentCreated) {
244
+ throw new Error("Only one container/document can be created. To load the container/document use loadContainer");
245
+ }
246
+ const loader = this.createLoader([[defaultCodeDetails, entryPoint]], loaderProps);
247
+ const container = await createAndAttachContainer(defaultCodeDetails, loader, this.driver.createCreateNewRequest(this.documentId));
248
+ this._documentCreated = true;
249
+ // r11s driver will generate a new ID for the new container.
250
+ // update the document ID with the actual ID of the attached container.
251
+ this._documentIdStrategy.update(container.resolvedUrl);
252
+ return container;
253
+ }
254
+ /**
255
+ * {@inheritdoc ITestObjectProvider.createDetachedContainer}
256
+ */
257
+ async createDetachedContainer(entryPoint, loaderProps) {
258
+ if (this._documentCreated) {
259
+ throw new Error("Only one container/document can be created. To load the container/document use loadContainer");
260
+ }
261
+ const loader = this.createLoader([[defaultCodeDetails, entryPoint]], loaderProps);
262
+ return loader.createDetachedContainer(defaultCodeDetails);
263
+ }
264
+ /**
265
+ * {@inheritdoc ITestObjectProvider.attachDetachedContainer}
266
+ */
267
+ async attachDetachedContainer(container) {
268
+ if (this._documentCreated) {
269
+ throw new Error("Only one container/document can be created. To load the container/document use loadContainer");
270
+ }
271
+ await container.attach(this.driver.createCreateNewRequest(this.documentId));
272
+ this._documentCreated = true;
273
+ this._documentIdStrategy.update(container.resolvedUrl);
274
+ }
275
+ /**
276
+ * {@inheritDoc ITestObjectProvider.loadContainer}
277
+ */
278
+ async loadContainer(entryPoint, loaderProps, requestHeader) {
279
+ const loader = this.createLoader([[defaultCodeDetails, entryPoint]], loaderProps);
280
+ return this.resolveContainer(loader, requestHeader);
281
+ }
282
+ async resolveContainer(loader, headers) {
283
+ return loader.resolve({
284
+ url: await this.driver.createContainerUrl(this.documentId),
285
+ headers,
286
+ });
287
+ }
288
+ /**
289
+ * {@inheritDoc ITestObjectProvider.makeTestLoader}
290
+ */
291
+ makeTestLoader(testContainerConfig) {
292
+ return this.createLoader([[defaultCodeDetails, this.createFluidEntryPoint(testContainerConfig)]], testContainerConfig?.loaderProps);
293
+ }
294
+ /**
295
+ * {@inheritDoc ITestObjectProvider.makeTestContainer}
296
+ */
297
+ async makeTestContainer(testContainerConfig) {
298
+ if (this._documentCreated) {
299
+ throw new Error("Only one container/document can be created. To load the container/document use loadTestContainer");
300
+ }
301
+ const loader = this.makeTestLoader(testContainerConfig);
302
+ const container = await createAndAttachContainer(defaultCodeDetails, loader, this.driver.createCreateNewRequest(this.documentId));
303
+ this._documentCreated = true;
304
+ // r11s driver will generate a new ID for the new container.
305
+ // update the document ID with the actual ID of the attached container.
306
+ this._documentIdStrategy.update(container.resolvedUrl);
307
+ return container;
308
+ }
309
+ /**
310
+ * {@inheritDoc ITestObjectProvider.loadTestContainer}
311
+ */
312
+ async loadTestContainer(testContainerConfig, requestHeader) {
313
+ const loader = this.makeTestLoader(testContainerConfig);
314
+ const container = await this.resolveContainer(loader, requestHeader);
315
+ await this.waitContainerToCatchUp(container);
316
+ return container;
317
+ }
318
+ /**
319
+ * {@inheritDoc ITestObjectProvider.reset}
320
+ */
321
+ reset() {
322
+ this._loaderContainerTracker.reset();
323
+ this._documentServiceFactory = undefined;
324
+ this._urlResolver = undefined;
325
+ this._documentIdStrategy.reset();
326
+ const logError = getUnexpectedLogErrorException(this._logger);
327
+ if (logError) {
328
+ throw logError;
329
+ }
330
+ this._logger = undefined;
331
+ this._documentCreated = false;
332
+ }
333
+ /**
334
+ * {@inheritDoc ITestObjectProvider.ensureSynchronized}
335
+ */
336
+ async ensureSynchronized() {
337
+ return this._loaderContainerTracker.ensureSynchronized();
338
+ }
339
+ async waitContainerToCatchUp(container) {
340
+ // The original waitContainerToCatchUp() from container loader uses either Container.resume()
341
+ // or Container.connect() as part of its implementation. However, resume() was deprecated
342
+ // and eventually replaced with connect(). To avoid issues during LTS compatibility testing
343
+ // with older container versions issues, we use resume() when connect() is unavailable.
344
+ if (container.connect === undefined) {
345
+ container.connect = container.resume;
346
+ }
347
+ return waitContainerToCatchUp_original(container);
348
+ }
349
+ /**
350
+ * {@inheritDoc ITestObjectProvider.updateDocumentId}
351
+ */
352
+ updateDocumentId(resolvedUrl) {
353
+ this._documentIdStrategy.update(resolvedUrl);
354
+ }
355
+ /**
356
+ * {@inheritDoc ITestObjectProvider.resetLoaderContainerTracker}
357
+ */
358
+ resetLoaderContainerTracker(syncSummarizerClients = false) {
359
+ this._loaderContainerTracker.reset();
360
+ this._loaderContainerTracker = new LoaderContainerTracker(syncSummarizerClients);
361
+ }
362
+ }
363
+ /**
364
+ * Implements {@link ITestObjectProvider}, but uses different versions to create and load containers.
365
+ *
366
+ * @internal
367
+ */
368
+ export class TestObjectProviderWithVersionedLoad {
369
+ constructor(LoaderConstructorForCreating, LoaderConstructorForLoading, driverForCreating, driverForLoading, createFluidEntryPointForCreating, createFluidEntryPointForLoading) {
370
+ this.LoaderConstructorForCreating = LoaderConstructorForCreating;
371
+ this.LoaderConstructorForLoading = LoaderConstructorForLoading;
372
+ this.driverForCreating = driverForCreating;
373
+ this.driverForLoading = driverForLoading;
374
+ this.createFluidEntryPointForCreating = createFluidEntryPointForCreating;
375
+ this.createFluidEntryPointForLoading = createFluidEntryPointForLoading;
376
+ /**
377
+ * {@inheritDoc ITestObjectProvider."type"}
378
+ */
379
+ this.type = "TestObjectProviderWithVersionedLoad";
380
+ this._loaderContainerTracker = new LoaderContainerTracker();
381
+ // Since documentId doesn't change we can only create/make one container. Call the load functions instead.
382
+ this._documentCreated = false;
383
+ /**
384
+ * Used to determine which APIs to use when creating a loader.
385
+ *
386
+ * The first load will always use the create APIs, and then useCreateApi will be set to false to ensure all
387
+ * subsequent loads use the load APIs.
388
+ */
389
+ this.useCreateApi = true;
390
+ this._documentIdStrategy = getDocumentIdStrategy(driverForCreating.type);
391
+ }
392
+ /**
393
+ * {@inheritDoc ITestObjectProvider.logger}
394
+ */
395
+ get logger() {
396
+ if (this._logger === undefined) {
397
+ this._logger = new EventAndErrorTrackingLogger(createChildLogger({
398
+ logger: getTestLogger?.(),
399
+ }));
400
+ }
401
+ return this._logger;
402
+ }
403
+ /**
404
+ * {@inheritDoc ITestObjectProvider.documentServiceFactory}
405
+ */
406
+ get documentServiceFactory() {
407
+ if (!this._documentServiceFactory) {
408
+ this._documentServiceFactory = this.driverForCreating.createDocumentServiceFactory();
409
+ }
410
+ return this._documentServiceFactory;
411
+ }
412
+ /**
413
+ * {@inheritDoc ITestObjectProvider.urlResolver}
414
+ */
415
+ get urlResolver() {
416
+ if (!this._urlResolver) {
417
+ this._urlResolver = this.driverForCreating.createUrlResolver();
418
+ }
419
+ return this._urlResolver;
420
+ }
421
+ /**
422
+ * {@inheritDoc ITestObjectProvider.documentId}
423
+ */
424
+ get documentId() {
425
+ return this._documentIdStrategy.get();
426
+ }
427
+ /**
428
+ * {@inheritDoc ITestObjectProvider.defaultCodeDetails}
429
+ */
430
+ get defaultCodeDetails() {
431
+ return defaultCodeDetails;
432
+ }
433
+ /**
434
+ * {@inheritDoc ITestObjectProvider.opProcessingController}
435
+ */
436
+ get opProcessingController() {
437
+ return this._loaderContainerTracker;
438
+ }
439
+ /**
440
+ * {@inheritDoc ITestObjectProvider.driver}
441
+ */
442
+ get driver() {
443
+ return this.useCreateApi ? this.driverForCreating : this.driverForLoading;
444
+ }
445
+ /**
446
+ * {@inheritDoc ITestObjectProvider.createFluidEntryPoint}
447
+ */
448
+ get createFluidEntryPoint() {
449
+ return this.useCreateApi
450
+ ? this.createFluidEntryPointForCreating
451
+ : this.createFluidEntryPointForLoading;
452
+ }
453
+ createLoaderForCreating(packageEntries, loaderProps) {
454
+ const logger = createMultiSinkLogger({
455
+ loggers: [this.logger, loaderProps?.logger],
456
+ });
457
+ const loader = new this.LoaderConstructorForCreating({
458
+ ...loaderProps,
459
+ logger,
460
+ codeLoader: loaderProps?.codeLoader ?? new 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
+ createLoaderForLoading(packageEntries, loaderProps) {
468
+ const logger = createMultiSinkLogger({
469
+ loggers: [this.logger, loaderProps?.logger],
470
+ });
471
+ const loader = new this.LoaderConstructorForLoading({
472
+ ...loaderProps,
473
+ logger,
474
+ codeLoader: loaderProps?.codeLoader ?? new LocalCodeLoader(packageEntries),
475
+ urlResolver: loaderProps?.urlResolver ?? this.urlResolver,
476
+ documentServiceFactory: loaderProps?.documentServiceFactory ?? this.documentServiceFactory,
477
+ });
478
+ this._loaderContainerTracker.add(loader);
479
+ return loader;
480
+ }
481
+ /**
482
+ * {@inheritDoc ITestObjectProvider.createLoader}
483
+ */
484
+ createLoader(packageEntries, loaderProps) {
485
+ if (this.useCreateApi) {
486
+ // After we create the first loader, we can set this.useCreateApi to false.
487
+ this.useCreateApi = false;
488
+ return this.createLoaderForCreating(packageEntries, loaderProps);
489
+ }
490
+ return this.createLoaderForLoading(packageEntries, loaderProps);
491
+ }
492
+ /**
493
+ * {@inheritDoc ITestObjectProvider.createContainer}
494
+ */
495
+ async createContainer(entryPoint, loaderProps) {
496
+ if (this._documentCreated) {
497
+ throw new Error("Only one container/document can be created. To load the container/document use loadContainer");
498
+ }
499
+ const loader = this.createLoader([[defaultCodeDetails, entryPoint]], loaderProps);
500
+ const container = await createAndAttachContainer(defaultCodeDetails, loader, this.driverForCreating.createCreateNewRequest(this.documentId));
501
+ this._documentCreated = true;
502
+ // r11s driver will generate a new ID for the new container.
503
+ // update the document ID with the actual ID of the attached container.
504
+ this._documentIdStrategy.update(container.resolvedUrl);
505
+ return container;
506
+ }
507
+ /**
508
+ * {@inheritdoc ITestObjectProvider.createDetachedContainer}
509
+ */
510
+ async createDetachedContainer(entryPoint, loaderProps) {
511
+ if (this._documentCreated) {
512
+ throw new Error("Only one container/document can be created. To load the container/document use loadContainer");
513
+ }
514
+ const loader = this.createLoader([[defaultCodeDetails, entryPoint]], loaderProps);
515
+ return loader.createDetachedContainer(defaultCodeDetails);
516
+ }
517
+ /**
518
+ * {@inheritdoc ITestObjectProvider.attachDetachedContainer}
519
+ */
520
+ async attachDetachedContainer(container) {
521
+ if (this._documentCreated) {
522
+ throw new Error("Only one container/document can be created. To load the container/document use loadContainer");
523
+ }
524
+ await container.attach(this.driver.createCreateNewRequest(this.documentId));
525
+ this._documentCreated = true;
526
+ this._documentIdStrategy.update(container.resolvedUrl);
527
+ }
528
+ /**
529
+ * {@inheritDoc ITestObjectProvider.loadContainer}
530
+ */
531
+ async loadContainer(entryPoint, loaderProps, requestHeader) {
532
+ const driver = this.useCreateApi ? this.driverForCreating : this.driverForLoading;
533
+ const loader = this.createLoader([[defaultCodeDetails, entryPoint]], loaderProps);
534
+ return this.resolveContainer(loader, requestHeader, driver);
535
+ }
536
+ async resolveContainer(loader, headers, driver) {
537
+ return loader.resolve({
538
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
539
+ url: await driver.createContainerUrl(this.documentId),
540
+ headers,
541
+ });
542
+ }
543
+ /**
544
+ * {@inheritDoc ITestObjectProvider.makeTestLoader}
545
+ */
546
+ makeTestLoader(testContainerConfig) {
547
+ return this.createLoader([[defaultCodeDetails, this.createFluidEntryPoint(testContainerConfig)]], testContainerConfig?.loaderProps);
548
+ }
549
+ /**
550
+ * {@inheritDoc ITestObjectProvider.makeTestContainer}
551
+ */
552
+ async makeTestContainer(testContainerConfig) {
553
+ if (this._documentCreated) {
554
+ throw new Error("Only one container/document can be created. To load the container/document use loadTestContainer");
555
+ }
556
+ const loader = this.createLoader([[defaultCodeDetails, this.createFluidEntryPoint(testContainerConfig)]], testContainerConfig?.loaderProps);
557
+ const container = await createAndAttachContainer(defaultCodeDetails, loader, this.driverForCreating.createCreateNewRequest(this.documentId));
558
+ this._documentCreated = true;
559
+ // r11s driver will generate a new ID for the new container.
560
+ // update the document ID with the actual ID of the attached container.
561
+ this._documentIdStrategy.update(container.resolvedUrl);
562
+ return container;
563
+ }
564
+ /**
565
+ * {@inheritDoc ITestObjectProvider.loadTestContainer}
566
+ */
567
+ async loadTestContainer(testContainerConfig, requestHeader) {
568
+ // Keep track of which Loader we are about to use so we can pass the correct driver through
569
+ const driver = this.useCreateApi ? this.driverForCreating : this.driverForLoading;
570
+ const loader = this.makeTestLoader(testContainerConfig);
571
+ const container = await this.resolveContainer(loader, requestHeader, driver);
572
+ await this.waitContainerToCatchUp(container);
573
+ return container;
574
+ }
575
+ /**
576
+ * {@inheritDoc ITestObjectProvider.reset}
577
+ */
578
+ reset() {
579
+ this.useCreateApi = true;
580
+ this._loaderContainerTracker.reset();
581
+ this._logger = undefined;
582
+ this._documentServiceFactory = undefined;
583
+ this._urlResolver = undefined;
584
+ this._documentIdStrategy.reset();
585
+ const logError = getUnexpectedLogErrorException(this._logger);
586
+ if (logError) {
587
+ throw logError;
588
+ }
589
+ this._documentCreated = false;
590
+ }
591
+ /**
592
+ * {@inheritDoc ITestObjectProvider.ensureSynchronized}
593
+ */
594
+ async ensureSynchronized() {
595
+ return this._loaderContainerTracker.ensureSynchronized();
596
+ }
597
+ async waitContainerToCatchUp(container) {
598
+ // The original waitContainerToCatchUp() from container loader uses either Container.resume()
599
+ // or Container.connect() as part of its implementation. However, resume() was deprecated
600
+ // and eventually replaced with connect(). To avoid issues during LTS compatibility testing
601
+ // with older container versions issues, we use resume() when connect() is unavailable.
602
+ if (container.connect === undefined) {
603
+ container.connect = container.resume;
604
+ }
605
+ return waitContainerToCatchUp_original(container);
606
+ }
607
+ /**
608
+ * {@inheritDoc ITestObjectProvider.updateDocumentId}
609
+ */
610
+ updateDocumentId(resolvedUrl) {
611
+ this._documentIdStrategy.update(resolvedUrl);
612
+ }
613
+ /**
614
+ * {@inheritDoc ITestObjectProvider.resetLoaderContainerTracker}
615
+ */
616
+ resetLoaderContainerTracker(syncSummarizerClients = false) {
617
+ this._loaderContainerTracker.reset();
618
+ this._loaderContainerTracker = new LoaderContainerTracker(syncSummarizerClients);
619
+ }
620
+ }
621
+ /**
622
+ * @internal
623
+ */
624
+ export function getUnexpectedLogErrorException(logger, prefix) {
625
+ if (logger === undefined) {
626
+ return;
627
+ }
628
+ const results = logger.reportAndClearTrackedEvents();
629
+ if (results.unexpectedErrors.length > 0) {
630
+ return new Error(`${prefix ?? ""}Unexpected Errors in Logs:\n${JSON.stringify(results.unexpectedErrors, undefined, 2)}`);
631
+ }
632
+ if (results.expectedNotFound.length > 0) {
633
+ return new Error(`${prefix ?? ""}Expected Events not found:\n${JSON.stringify(results.expectedNotFound, undefined, 2)}`);
634
+ }
635
+ }
636
+ //# sourceMappingURL=testObjectProvider.js.map