Skip to content

Commit 3620b0a

Browse files
authored
E2E test for re-connect attempts when container is disconnected (#20627)
This is a follow up PR to test changes made in #20547. Here we test the expected container re-connection behavior when host called container.disconnect(); [AB#7760](https://dev.azure.com/fluidframework/235294da-091d-4c29-84fc-cdfc3d90890b/_workitems/edit/7760)
1 parent f777c5c commit 3620b0a

File tree

1 file changed

+93
-1
lines changed

1 file changed

+93
-1
lines changed

packages/test/test-end-to-end-tests/src/test/container.spec.ts

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import { strict as assert } from "assert";
7-
7+
import { useFakeTimers } from "sinon";
88
import { MockDocumentDeltaConnection } from "@fluid-private/test-loader-utils";
99
import {
1010
ITestDataObject,
@@ -40,6 +40,7 @@ import { FiveDaysMs, IDocumentServiceFactory } from "@fluidframework/driver-defi
4040
import {
4141
DeltaStreamConnectionForbiddenError,
4242
NonRetryableError,
43+
RetryableError,
4344
} from "@fluidframework/driver-utils/internal";
4445
import { IClient } from "@fluidframework/protocol-definitions";
4546
import { DataCorruptionError } from "@fluidframework/telemetry-utils/internal";
@@ -857,3 +858,94 @@ describeCompat("Driver", "NoCompat", (getTestObjectProvider) => {
857858
assert.equal(storage.policies?.maximumCacheDurationMs, fiveDaysMs);
858859
});
859860
});
861+
862+
describeCompat("Container connections", "NoCompat", (getTestObjectProvider) => {
863+
let provider: ITestObjectProvider;
864+
let clock;
865+
before(() => {
866+
clock = useFakeTimers();
867+
});
868+
beforeEach("", async function () {
869+
provider = getTestObjectProvider();
870+
if (provider.driver.type !== "local") {
871+
this.skip();
872+
}
873+
});
874+
afterEach(() => {
875+
clock.reset();
876+
});
877+
after(() => {
878+
clock.restore();
879+
});
880+
it("container disconnect() stops the connection re-attempt loop", async () => {
881+
let emulateThrowErrorOnConnection = false;
882+
const retryAfter = 3;
883+
let reconnectionAttemptCount = 0;
884+
(provider as any)._documentServiceFactory = wrapObjectAndOverride<IDocumentServiceFactory>(
885+
provider.documentServiceFactory,
886+
{
887+
createDocumentService: {
888+
connectToDeltaStream: (_ds) => async (client) => {
889+
// We let the container get created first before starting emulate throwing of errors.
890+
if (emulateThrowErrorOnConnection) {
891+
reconnectionAttemptCount++;
892+
throw new RetryableError("Test message", "ThrottlingError", {
893+
retryAfterSeconds: retryAfter,
894+
driverVersion: "1",
895+
});
896+
} else {
897+
return _ds.connectToDeltaStream(client);
898+
}
899+
},
900+
},
901+
},
902+
);
903+
// Create container
904+
const container = await provider.makeTestContainer();
905+
await waitForContainerConnection(container);
906+
emulateThrowErrorOnConnection = true;
907+
908+
// This flag will ensure that the container warnings were observed when throttling error was thrown
909+
let didReceiveContainerWarning = false;
910+
911+
// Host apps can chose to listen to container warning events and disconnect the container if they observe throttling errors
912+
container.once("warning", (warning) => {
913+
assert.equal(
914+
warning.errorType,
915+
"throttlingError",
916+
"Error type thrown by the warning message is incorrect",
917+
);
918+
919+
// disconnecting the container should also stop re-connects to the service
920+
container.disconnect();
921+
const countUntilDisconnectWasCalled = reconnectionAttemptCount;
922+
923+
clock.tick(retryAfter * 1000 + 10);
924+
// Check if there has been any retry attempt after some time greater than retry after has elapsed
925+
assert.equal(
926+
reconnectionAttemptCount,
927+
countUntilDisconnectWasCalled,
928+
"Connection should not have been attempted, even after the retry timedout",
929+
);
930+
931+
clock.tick(retryAfter * 1000 + 10);
932+
// Check if there has been any retry attempt after more time has elapsed
933+
assert.equal(
934+
reconnectionAttemptCount,
935+
countUntilDisconnectWasCalled,
936+
"Connection should not have been attempted after some more time",
937+
);
938+
didReceiveContainerWarning = true;
939+
});
940+
941+
// Disconnect and connect the container again to trigger the connection to the delta service
942+
// to test the container warning behavior above
943+
container.disconnect();
944+
container.connect();
945+
await clock.tickAsync(retryAfter * 1000 + 20);
946+
assert(
947+
didReceiveContainerWarning,
948+
"Container warning event should happen when throttling error occurs",
949+
);
950+
});
951+
});

0 commit comments

Comments
 (0)