@fluidframework/test-utils 2.0.0-dev.4.1.0.148229 → 2.0.0-dev.4.3.0.157531
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/dist/TestSummaryUtils.d.ts +11 -1
- package/dist/TestSummaryUtils.d.ts.map +1 -1
- package/dist/TestSummaryUtils.js +14 -1
- package/dist/TestSummaryUtils.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/loaderContainerTracker.d.ts +27 -10
- package/dist/loaderContainerTracker.d.ts.map +1 -1
- package/dist/loaderContainerTracker.js +132 -49
- package/dist/loaderContainerTracker.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/testObjectProvider.d.ts +3 -0
- package/dist/testObjectProvider.d.ts.map +1 -1
- package/dist/testObjectProvider.js +10 -9
- package/dist/testObjectProvider.js.map +1 -1
- package/package.json +24 -24
- package/src/TestSummaryUtils.ts +29 -0
- package/src/index.ts +6 -1
- package/src/loaderContainerTracker.ts +163 -51
- package/src/packageVersion.ts +1 -1
- package/src/testObjectProvider.ts +24 -11
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
ISequencedDocumentMessage,
|
|
12
12
|
MessageType,
|
|
13
13
|
} from "@fluidframework/protocol-definitions";
|
|
14
|
+
import { waitForContainerConnection } from "./containerUtils";
|
|
14
15
|
import { debug } from "./debug";
|
|
15
16
|
import { IOpProcessingController } from "./testObjectProvider";
|
|
16
17
|
import { timeoutAwait, timeoutPromise } from "./timeoutUtils";
|
|
@@ -24,6 +25,7 @@ interface ContainerRecord {
|
|
|
24
25
|
|
|
25
26
|
// LoaderContainerTracker paused state
|
|
26
27
|
paused: boolean;
|
|
28
|
+
pauseP?: Promise<void>; // promise for for the pause that is in progress
|
|
27
29
|
|
|
28
30
|
// Tracking trailing no-op that may or may be acked by the server so we can discount them
|
|
29
31
|
// See issue #5629
|
|
@@ -178,33 +180,35 @@ export class LoaderContainerTracker implements IOpProcessingController {
|
|
|
178
180
|
* Make sure all the tracked containers are synchronized.
|
|
179
181
|
*
|
|
180
182
|
* No isDirty (non-readonly) containers
|
|
181
|
-
*
|
|
182
183
|
* No extra clientId in quorum of any container that is not tracked and still opened.
|
|
183
|
-
*
|
|
184
184
|
* - i.e. no pending Join/Leave message.
|
|
185
|
-
*
|
|
186
185
|
* No unresolved proposal (minSeqNum \>= lastProposalSeqNum)
|
|
187
|
-
*
|
|
188
186
|
* lastSequenceNumber of all container is the same
|
|
189
|
-
*
|
|
190
187
|
* clientSequenceNumberObserved is the same as clientSequenceNumber sent
|
|
191
|
-
*
|
|
192
188
|
* - this overlaps with !isDirty, but include task scheduler ops.
|
|
193
|
-
*
|
|
194
189
|
* - Trailing NoOp is tracked and don't count as pending ops.
|
|
190
|
+
*
|
|
191
|
+
* Containers that are already pause will resume process and paused again once
|
|
192
|
+
* everything is synchronized. Containers that aren't paused will remain unpaused when this
|
|
193
|
+
* function returns.
|
|
195
194
|
*/
|
|
196
195
|
public async ensureSynchronized(...containers: IContainer[]): Promise<void> {
|
|
197
196
|
const resumed = this.resumeProcessing(...containers);
|
|
198
197
|
|
|
199
|
-
let waitingSequenceNumberSynchronized
|
|
198
|
+
let waitingSequenceNumberSynchronized: string | undefined;
|
|
200
199
|
// eslint-disable-next-line no-constant-condition
|
|
201
200
|
while (true) {
|
|
201
|
+
// yield a turn to allow side effect of resuming or the ops we just processed execute before we check
|
|
202
|
+
await new Promise<void>((resolve) => {
|
|
203
|
+
setTimeout(resolve, 0);
|
|
204
|
+
});
|
|
205
|
+
|
|
202
206
|
const containersToApply = this.getContainers(containers);
|
|
203
207
|
if (containersToApply.length === 0) {
|
|
204
208
|
break;
|
|
205
209
|
}
|
|
206
210
|
|
|
207
|
-
// Ignore readonly dirty containers, because it can't sent
|
|
211
|
+
// Ignore readonly dirty containers, because it can't sent ops and nothing can be done about it being dirty
|
|
208
212
|
const dirtyContainers = containersToApply.filter((c) => {
|
|
209
213
|
const { deltaManager, isDirty } = c;
|
|
210
214
|
return deltaManager.readOnlyInfo.readonly !== true && isDirty;
|
|
@@ -213,20 +217,22 @@ export class LoaderContainerTracker implements IOpProcessingController {
|
|
|
213
217
|
// Wait for all the leave messages
|
|
214
218
|
const pendingClients = this.getPendingClients(containersToApply);
|
|
215
219
|
if (pendingClients.length === 0) {
|
|
216
|
-
|
|
220
|
+
const needSync = this.needSequenceNumberSynchronize(containersToApply);
|
|
221
|
+
if (needSync === undefined) {
|
|
217
222
|
// done, we are in sync
|
|
218
223
|
break;
|
|
219
224
|
}
|
|
220
|
-
if (
|
|
221
|
-
//
|
|
222
|
-
waitingSequenceNumberSynchronized =
|
|
223
|
-
debugWait(
|
|
224
|
-
await timeoutAwait(this.waitForAnyInboundOps(containersToApply), {
|
|
225
|
-
errorMsg: "Timeout on waiting for sequence number synchronized",
|
|
226
|
-
});
|
|
225
|
+
if (waitingSequenceNumberSynchronized !== needSync.reason) {
|
|
226
|
+
// Don't repeat writing to console if it is the same reason
|
|
227
|
+
waitingSequenceNumberSynchronized = needSync.reason;
|
|
228
|
+
debugWait(needSync.message);
|
|
227
229
|
}
|
|
230
|
+
// Wait for one inbounds ops which might change the state of things
|
|
231
|
+
await timeoutAwait(this.waitForAnyInboundOps(containersToApply), {
|
|
232
|
+
errorMsg: `Timeout on ${needSync.message}`,
|
|
233
|
+
});
|
|
228
234
|
} else {
|
|
229
|
-
waitingSequenceNumberSynchronized =
|
|
235
|
+
waitingSequenceNumberSynchronized = undefined;
|
|
230
236
|
await timeoutAwait(this.waitForPendingClients(pendingClients), {
|
|
231
237
|
errorMsg: "Timeout on waiting for pending join or leave op",
|
|
232
238
|
});
|
|
@@ -234,12 +240,9 @@ export class LoaderContainerTracker implements IOpProcessingController {
|
|
|
234
240
|
} else {
|
|
235
241
|
// Wait for all the containers to be saved
|
|
236
242
|
debugWait(
|
|
237
|
-
`Waiting container to be saved ${
|
|
238
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
239
|
-
(c) => this.containers.get(c)!.index,
|
|
240
|
-
)}`,
|
|
243
|
+
`Waiting container to be saved ${this.containerIndexStrings(dirtyContainers)}`,
|
|
241
244
|
);
|
|
242
|
-
waitingSequenceNumberSynchronized =
|
|
245
|
+
waitingSequenceNumberSynchronized = undefined;
|
|
243
246
|
await Promise.all(
|
|
244
247
|
dirtyContainers.map(async (c) =>
|
|
245
248
|
Promise.race([
|
|
@@ -251,11 +254,6 @@ export class LoaderContainerTracker implements IOpProcessingController {
|
|
|
251
254
|
),
|
|
252
255
|
);
|
|
253
256
|
}
|
|
254
|
-
|
|
255
|
-
// yield a turn to allow side effect of the ops we just processed execute before we check again
|
|
256
|
-
await new Promise<void>((resolve) => {
|
|
257
|
-
setTimeout(resolve, 0);
|
|
258
|
-
});
|
|
259
257
|
}
|
|
260
258
|
|
|
261
259
|
// Pause all container that was resumed
|
|
@@ -311,48 +309,78 @@ export class LoaderContainerTracker implements IOpProcessingController {
|
|
|
311
309
|
*
|
|
312
310
|
* @param containersToApply - the set of containers to check
|
|
313
311
|
*/
|
|
314
|
-
private
|
|
312
|
+
private needSequenceNumberSynchronize(containersToApply: IContainer[]) {
|
|
313
|
+
// If there is a pending proposal, wait for it to be accepted
|
|
314
|
+
const minSeqNum = containersToApply[0].deltaManager.minimumSequenceNumber;
|
|
315
|
+
if (minSeqNum < this.lastProposalSeqNum) {
|
|
316
|
+
return {
|
|
317
|
+
reason: "Proposal",
|
|
318
|
+
message: `waiting for MSN to advance to proposal at sequence number ${this.lastProposalSeqNum}`,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
315
322
|
// clientSequenceNumber check detects ops in flight, both on the wire and in the outbound queue
|
|
316
323
|
// We need both client sequence number and isDirty check because:
|
|
317
324
|
// - Currently isDirty flag ignores ops for task scheduler, so we need the client sequence number check
|
|
318
325
|
// - But isDirty flags include ops during forceReadonly and disconnected, because we don't submit
|
|
319
326
|
// the ops in the first place, clientSequenceNumber is not assigned
|
|
320
327
|
|
|
321
|
-
const
|
|
328
|
+
const containerWithInflightOps = containersToApply.filter((container) => {
|
|
322
329
|
if (container.deltaManager.readOnlyInfo.readonly === true) {
|
|
323
330
|
// Ignore readonly container. the clientSeqNum and clientSeqNumObserved might be out of sync
|
|
324
331
|
// because we transition to readonly when outbound is not empty or the in transit op got lost
|
|
325
|
-
return
|
|
332
|
+
return false;
|
|
326
333
|
}
|
|
327
334
|
// Note that in read only mode, the op won't be submitted
|
|
328
335
|
let deltaManager = container.deltaManager as any;
|
|
329
336
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
330
337
|
const { trailingNoOps } = this.containers.get(container)!;
|
|
331
|
-
// Back-compat: clientSequenceNumber
|
|
338
|
+
// Back-compat: lastSubmittedClientId/clientSequenceNumber/clientSequenceNumberObserved moved to ConnectionManager in 0.53
|
|
332
339
|
if (!("clientSequenceNumber" in deltaManager)) {
|
|
333
340
|
deltaManager = deltaManager.connectionManager;
|
|
334
341
|
}
|
|
335
342
|
assert("clientSequenceNumber" in deltaManager, "no clientSequenceNumber");
|
|
336
343
|
assert("clientSequenceNumberObserved" in deltaManager, "no clientSequenceNumber");
|
|
344
|
+
// If last submittedClientId isn't the current clientId, then we haven't send any ops
|
|
337
345
|
return (
|
|
338
|
-
deltaManager.
|
|
339
|
-
|
|
346
|
+
deltaManager.lastSubmittedClientId === container.clientId &&
|
|
347
|
+
deltaManager.clientSequenceNumber !==
|
|
348
|
+
(deltaManager.clientSequenceNumberObserved as number) + trailingNoOps
|
|
340
349
|
);
|
|
341
350
|
});
|
|
342
351
|
|
|
343
|
-
if (
|
|
344
|
-
return
|
|
352
|
+
if (containerWithInflightOps.length !== 0) {
|
|
353
|
+
return {
|
|
354
|
+
reason: "InflightOps",
|
|
355
|
+
message: `waiting for containers with inflight ops: ${this.containerIndexStrings(
|
|
356
|
+
containerWithInflightOps,
|
|
357
|
+
)}`,
|
|
358
|
+
};
|
|
345
359
|
}
|
|
346
360
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
361
|
+
// Check to see if all the container has process the same number of ops.
|
|
362
|
+
const maxSeqNum = Math.max(
|
|
363
|
+
...containersToApply.map((c) => c.deltaManager.lastSequenceNumber),
|
|
364
|
+
);
|
|
365
|
+
const containerWithPendingIncoming = containersToApply.filter(
|
|
366
|
+
(c) => c.deltaManager.lastSequenceNumber !== maxSeqNum,
|
|
367
|
+
);
|
|
368
|
+
if (containerWithPendingIncoming.length !== 0) {
|
|
369
|
+
return {
|
|
370
|
+
reason: "Pending",
|
|
371
|
+
message: `waiting for containers with pending incoming ops up to sequence number ${maxSeqNum}: ${this.containerIndexStrings(
|
|
372
|
+
containerWithPendingIncoming,
|
|
373
|
+
)}`,
|
|
374
|
+
};
|
|
351
375
|
}
|
|
376
|
+
return undefined;
|
|
377
|
+
}
|
|
352
378
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
379
|
+
private containerIndexStrings(containers: IContainer[]) {
|
|
380
|
+
return containers.map(
|
|
381
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
382
|
+
(c) => this.containers.get(c)!.index,
|
|
383
|
+
);
|
|
356
384
|
}
|
|
357
385
|
|
|
358
386
|
/**
|
|
@@ -425,6 +453,10 @@ export class LoaderContainerTracker implements IOpProcessingController {
|
|
|
425
453
|
const containersToApply = this.getContainers(containers);
|
|
426
454
|
for (const container of containersToApply) {
|
|
427
455
|
const record = this.containers.get(container);
|
|
456
|
+
assert(
|
|
457
|
+
record?.pauseP === undefined,
|
|
458
|
+
"Cannot resume container while pausing is in progress",
|
|
459
|
+
);
|
|
428
460
|
if (record?.paused === true) {
|
|
429
461
|
debugWait(`${record.index}: container resumed`);
|
|
430
462
|
container.deltaManager.inbound.resume();
|
|
@@ -439,26 +471,98 @@ export class LoaderContainerTracker implements IOpProcessingController {
|
|
|
439
471
|
/**
|
|
440
472
|
* Pause all queue activities on the containers given, or all tracked containers
|
|
441
473
|
* Any containers given that is not tracked will be ignored.
|
|
474
|
+
*
|
|
475
|
+
* When a container is paused, it is assumed that we want fine grain control over op
|
|
476
|
+
* sequencing. This function will prepare the container and force it into write mode to
|
|
477
|
+
* avoid missing join messages or change the sequence of event when switching from read to
|
|
478
|
+
* write mode.
|
|
442
479
|
*/
|
|
443
480
|
public async pauseProcessing(...containers: IContainer[]) {
|
|
444
|
-
const
|
|
481
|
+
const waitP: Promise<void>[] = [];
|
|
445
482
|
const containersToApply = this.getContainers(containers);
|
|
446
483
|
for (const container of containersToApply) {
|
|
447
484
|
const record = this.containers.get(container);
|
|
448
485
|
if (record !== undefined && !record.paused) {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
record.
|
|
486
|
+
if (record.pauseP === undefined) {
|
|
487
|
+
record.pauseP = this.pauseContainer(container, record);
|
|
488
|
+
}
|
|
489
|
+
waitP.push(record.pauseP);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
await Promise.all(waitP);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* When a container is paused, it is assumed that we want fine grain control over op
|
|
497
|
+
* sequencing. This function will prepare the container and force it into write mode to
|
|
498
|
+
* avoid missing join messages or change the sequence of event when switching from read to
|
|
499
|
+
* write mode.
|
|
500
|
+
*
|
|
501
|
+
* @param container - the container to pause
|
|
502
|
+
* @param record - the record for the container
|
|
503
|
+
*/
|
|
504
|
+
private async pauseContainer(container: IContainer, record: ContainerRecord) {
|
|
505
|
+
debugWait(`${record.index}: pausing container`);
|
|
506
|
+
assert(!container.deltaManager.outbound.paused, "Container should not be paused yet");
|
|
507
|
+
assert(!container.deltaManager.inbound.paused, "Container should not be paused yet");
|
|
508
|
+
|
|
509
|
+
// Pause outbound
|
|
510
|
+
debugWait(`${record.index}: pausing container outbound queues`);
|
|
511
|
+
await container.deltaManager.outbound.pause();
|
|
512
|
+
|
|
513
|
+
// Ensure the container is connected first.
|
|
514
|
+
if (container.connectionState !== ConnectionState.Connected) {
|
|
515
|
+
debugWait(`${record.index}: Wait for container connection`);
|
|
516
|
+
await waitForContainerConnection(container);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Check if the container is in write mode
|
|
520
|
+
if (!container.deltaManager.active) {
|
|
521
|
+
let proposalP: Promise<boolean> | undefined;
|
|
522
|
+
if (container.deltaManager.outbound.idle) {
|
|
523
|
+
// Need to generate an op to force write mode
|
|
524
|
+
debugWait(`${record.index}: container force write connection`);
|
|
525
|
+
const maybeContainer = container as Partial<IContainer>;
|
|
526
|
+
const codeProposal = maybeContainer.getLoadedCodeDetails
|
|
527
|
+
? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
528
|
+
container.getLoadedCodeDetails()!
|
|
529
|
+
: (container as any).chaincodePackage;
|
|
530
|
+
|
|
531
|
+
proposalP = container.proposeCodeDetails(codeProposal);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// Wait for nack
|
|
535
|
+
debugWait(`${record.index}: Wait for container disconnect`);
|
|
536
|
+
container.deltaManager.outbound.resume();
|
|
537
|
+
await new Promise<void>((resolve) => container.once("disconnected", resolve));
|
|
538
|
+
const accepted = proposalP ? await proposalP : false;
|
|
539
|
+
assert(!accepted, "A proposal in read mode should be rejected");
|
|
540
|
+
await container.deltaManager.outbound.pause();
|
|
541
|
+
|
|
542
|
+
// Ensure the container is reconnect.
|
|
543
|
+
if (container.connectionState !== ConnectionState.Connected) {
|
|
544
|
+
debugWait(`${record.index}: Wait for container reconnection`);
|
|
545
|
+
await waitForContainerConnection(container);
|
|
453
546
|
}
|
|
454
547
|
}
|
|
455
|
-
|
|
548
|
+
|
|
549
|
+
debugWait(`${record.index}: pausing container inbound queues`);
|
|
550
|
+
|
|
551
|
+
// Pause inbound
|
|
552
|
+
await container.deltaManager.inbound.pause();
|
|
553
|
+
|
|
554
|
+
debugWait(`${record.index}: container paused`);
|
|
555
|
+
|
|
556
|
+
record.pauseP = undefined;
|
|
557
|
+
record.paused = true;
|
|
456
558
|
}
|
|
457
559
|
|
|
458
560
|
/**
|
|
459
561
|
* Pause all queue activities on all tracked containers, and resume only
|
|
460
562
|
* inbound to process ops until it is idle. All queues are left in the paused state
|
|
461
|
-
* after the function
|
|
563
|
+
* after the function.
|
|
564
|
+
*
|
|
565
|
+
* Pausing will switch the container to write mode. See `pauseProcessing`
|
|
462
566
|
*/
|
|
463
567
|
public async processIncoming(...containers: IContainer[]) {
|
|
464
568
|
return this.processQueue(containers, (container) => container.deltaManager.inbound);
|
|
@@ -467,7 +571,9 @@ export class LoaderContainerTracker implements IOpProcessingController {
|
|
|
467
571
|
/**
|
|
468
572
|
* Pause all queue activities on all tracked containers, and resume only
|
|
469
573
|
* outbound to process ops until it is idle. All queues are left in the paused state
|
|
470
|
-
* after the function
|
|
574
|
+
* after the function.
|
|
575
|
+
*
|
|
576
|
+
* Pausing will switch the container to write mode. See `pauseProcessing`
|
|
471
577
|
*/
|
|
472
578
|
public async processOutgoing(...containers: IContainer[]) {
|
|
473
579
|
return this.processQueue(containers, (container) => container.deltaManager.outbound);
|
|
@@ -484,9 +590,15 @@ export class LoaderContainerTracker implements IOpProcessingController {
|
|
|
484
590
|
const resumed: IDeltaQueue<U>[] = [];
|
|
485
591
|
|
|
486
592
|
const containersToApply = this.getContainers(containers);
|
|
593
|
+
|
|
487
594
|
const inflightTracker = new Map<IContainer, number>();
|
|
488
595
|
const cleanup: (() => void)[] = [];
|
|
489
596
|
for (const container of containersToApply) {
|
|
597
|
+
assert(
|
|
598
|
+
container.deltaManager.active,
|
|
599
|
+
"Container should be connected in write mode already",
|
|
600
|
+
);
|
|
601
|
+
|
|
490
602
|
const queue = getQueue(container);
|
|
491
603
|
|
|
492
604
|
// track the outgoing ops (if any) to make sure they make the round trip to at least to the same client
|
package/src/packageVersion.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
IHostLoader,
|
|
9
9
|
IFluidCodeDetails,
|
|
10
10
|
LoaderHeader,
|
|
11
|
+
ILoader,
|
|
11
12
|
} from "@fluidframework/container-definitions";
|
|
12
13
|
import {
|
|
13
14
|
ITelemetryGenericEvent,
|
|
@@ -112,6 +113,9 @@ export interface ITestContainerConfig {
|
|
|
112
113
|
|
|
113
114
|
/** Loader options for the loader used to create containers */
|
|
114
115
|
loaderProps?: Partial<ILoaderProps>;
|
|
116
|
+
|
|
117
|
+
/** Temporary flag: simulate read connection using delay connection, default is true */
|
|
118
|
+
simulateReadConnectionUsingDelay?: boolean;
|
|
115
119
|
}
|
|
116
120
|
|
|
117
121
|
export const createDocumentId = (): string => uuid();
|
|
@@ -382,12 +386,20 @@ export class TestObjectProvider implements ITestObjectProvider {
|
|
|
382
386
|
requestHeader?: IRequestHeader,
|
|
383
387
|
): Promise<IContainer> {
|
|
384
388
|
const loader = this.createLoader([[defaultCodeDetails, entryPoint]], loaderProps);
|
|
389
|
+
return this.resolveContainer(loader, requestHeader);
|
|
390
|
+
}
|
|
385
391
|
|
|
386
|
-
|
|
392
|
+
private async resolveContainer(
|
|
393
|
+
loader: ILoader,
|
|
394
|
+
requestHeader?: IRequestHeader,
|
|
395
|
+
delay: boolean = true,
|
|
396
|
+
) {
|
|
397
|
+
// Once AB#3889 is done to switch default connection mode to "read" on load, we don't need
|
|
387
398
|
// to load "delayed" across the board. Remove the following code.
|
|
388
399
|
const delayConnection =
|
|
389
|
-
|
|
390
|
-
|
|
400
|
+
delay &&
|
|
401
|
+
(requestHeader === undefined || requestHeader[LoaderHeader.reconnect] !== false);
|
|
402
|
+
const headers: IRequestHeader | undefined = delayConnection
|
|
391
403
|
? {
|
|
392
404
|
[LoaderHeader.loadMode]: { deltaConnection: "delayed" },
|
|
393
405
|
...requestHeader,
|
|
@@ -399,19 +411,18 @@ export class TestObjectProvider implements ITestObjectProvider {
|
|
|
399
411
|
headers,
|
|
400
412
|
});
|
|
401
413
|
|
|
402
|
-
// Once
|
|
414
|
+
// Once AB#3889 is done to switch default connection mode to "read" on load, we don't need
|
|
403
415
|
// to load "delayed" across the board. Remove the following code.
|
|
404
416
|
if (delayConnection) {
|
|
405
|
-
// Older version may not have connect,
|
|
417
|
+
// Older version may not have connect/disconnect. It was add in PR#9439, and available >= 0.59.1000
|
|
406
418
|
const maybeContainer = container as Partial<IContainer>;
|
|
407
419
|
if (maybeContainer.connect !== undefined) {
|
|
408
420
|
container.connect();
|
|
409
421
|
} else {
|
|
410
|
-
// back compat
|
|
422
|
+
// back compat. Remove when we don't support < 0.59.1000
|
|
411
423
|
(container as any).resume();
|
|
412
424
|
}
|
|
413
425
|
}
|
|
414
|
-
|
|
415
426
|
return container;
|
|
416
427
|
}
|
|
417
428
|
|
|
@@ -464,10 +475,12 @@ export class TestObjectProvider implements ITestObjectProvider {
|
|
|
464
475
|
requestHeader?: IRequestHeader,
|
|
465
476
|
): Promise<IContainer> {
|
|
466
477
|
const loader = this.makeTestLoader(testContainerConfig);
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
478
|
+
|
|
479
|
+
const container = await this.resolveContainer(
|
|
480
|
+
loader,
|
|
481
|
+
requestHeader,
|
|
482
|
+
testContainerConfig?.simulateReadConnectionUsingDelay,
|
|
483
|
+
);
|
|
471
484
|
await this.waitContainerToCatchUp(container);
|
|
472
485
|
|
|
473
486
|
return container;
|