Skip to content

Commit d8dc721

Browse files
authored
Enabling testing of 2.0 file format features (#20109)
The issue we have in our tests (mostly end-to-end tests) is that we are not testing new capabilities that are either enabled or will be enabled by customers as part of 2.0 timeframe. Example of the features are: 1. Id Compressor 2. op compression 3. op chunking 4. op grouping Successful solution here will have these properties: 1. We will enable all the features in our tests that are possible to enable, in order to get best coverage - i.e. in tests that use only 2.0, all the recent features will be enabled. 3. At the same time, we will reduce usage of such features in tests to a level that the minimum runtime version understands. - I.e. in tests that uses 1.3 directly, or mixes 1.3 and 2.0, we will disable all the features that 1.3 does not understand. The obvious question to ask - are we losing too much of coverage for when these features are off? I'd say no, as - Any test combos that use a mix of 1.3 & 2.0 still test it - When options are off, we are (ideally, not guaranteed) should get to well know state that was already tested (before such features were added). There are no guarantees here, but there are even less guarantees for these features to be working when they are On, as that's a lot of new code. Please note that this question is orthogonal to a question - should each feature in question here be properly tested by dedicated UT with on & off states. The answer is - absolutely yes, but that's not enough. Here are bugs found and already fixed thanks to this work (I also hit first two bugs independently while stress testing unrelated piece of code that used ID compressor): 1. #20089 2. #20080 3. #20111 4. #20115 As for results: - Initial commit (for this PR) has comments describing how many tests are failing. That was 2 weeks back or so. - Rerunning it today (with merging rebasing to latest main, which includes first 2 commits/PRs mentioned above) shows smaller number of failures. I expect that the PRs I've mentioned above (that I merged this week) are addressing some of the issues we are seeing here (but I have not validated that). - I'll keep adding PRs to the list with bugfixes as I identify issues and fixes. This is just a prototype. I think the next steps are: 1. Investigate all the failures and fix all the production / test bugs that this direction finds. - Or possibly - learn that direction has a flaw. 2. Expose by container runtime package a default config & max config for testing 5. Test packages use above if available, and not hard code options in test code. 6. We need to fix AzureClient not to use Immediate Flush mode, and approach it in exactly same way as the rest of runtime options (in terms of testing / flighting / making it eventually a reality)
1 parent 83947c9 commit d8dc721

File tree

9 files changed

+155
-8
lines changed

9 files changed

+155
-8
lines changed

examples/data-objects/webflow/src/test/layout.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ describeCompat("Layout", "LoaderCompat", (getTestObjectProvider) => {
4545

4646
let provider: ITestObjectProvider;
4747
before(async function () {
48-
// Initialization of 'compat LTS ^1.3.4 - old loader' compat variant can take a couple seconds.
48+
// Initialization of 'compat LTS ^1.3.x - old loader' compat variant can take a couple seconds.
4949
this.timeout(10000);
5050

5151
provider = getTestObjectProvider({ resetAfterEach: false });

packages/runtime/container-runtime/src/containerRuntime.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ export interface IContainerRuntimeOptions {
416416
* If specified, when in FlushMode.TurnBased, if the size of the ops between JS turns exceeds this value,
417417
* an error will be thrown and the container will close.
418418
*
419-
* If unspecified, the limit is 950 * 1024.
419+
* If unspecified, the limit is 700Kb.
420420
*
421421
* 'Infinity' will disable any limit.
422422
*

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
ISequencedDocumentMessage,
1919
ISequencedDocumentSystemMessage,
2020
} from "@fluidframework/protocol-definitions";
21-
import { IContainerRuntimeOptions } from "@fluidframework/container-runtime";
21+
import { IContainerRuntimeOptions, CompressionAlgorithms } from "@fluidframework/container-runtime";
2222
import { FluidErrorTypes } from "@fluidframework/core-interfaces";
2323
import { wrapObjectAndOverride } from "../mocking.js";
2424

@@ -149,6 +149,11 @@ describeCompat("Batching failures", "NoCompat", (getTestObjectProvider) => {
149149

150150
await runAndValidateBatch(provider, proxyDsf, this.timeout(), {
151151
enableGroupedBatching,
152+
chunkSizeInBytes: Number.POSITIVE_INFINITY, // disable
153+
compressionOptions: {
154+
minimumBatchSizeInBytes: Number.POSITIVE_INFINITY, // disable
155+
compressionAlgorithm: CompressionAlgorithms.lz4,
156+
},
152157
});
153158
assert.strictEqual(batchesSent, 1, "expected only a single batch to be sent");
154159

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,9 @@ describeCompat("Detached Container", "FullCompat", (getTestObjectProvider, apis)
478478
if (runtimeMessage === false) {
479479
return;
480480
}
481+
if (message.type === ContainerMessageType.IdAllocation) {
482+
return;
483+
}
481484
try {
482485
assert.strictEqual(
483486
message.type,

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ describeCompat("Fewer batches", "NoCompat", (getTestObjectProvider, apis) => {
5858
const configWithFeatureGates = {
5959
...containerConfig,
6060
loaderProps: { configProvider: configProvider(featureGates) },
61+
// This test counts number of ops and observes them at the container level.
62+
// It has certain assumptions about count and shape of those ops.
63+
// Disable op chunking to make sure test have full control over op stream, and thus can rely on those assumptions.
64+
runtimeOptions: {
65+
chunkSizeInBytes: Number.POSITIVE_INFINITY, // disable
66+
...containerConfig.runtimeOptions,
67+
},
6168
};
6269

6370
// Create a Container for the first client.
@@ -99,6 +106,7 @@ describeCompat("Fewer batches", "NoCompat", (getTestObjectProvider, apis) => {
99106
...testContainerConfig,
100107
runtimeOptions: {
101108
flushMode: test.flushMode,
109+
chunkSizeInBytes: Number.POSITIVE_INFINITY, // disable
102110
},
103111
});
104112

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ describeCompat("Runtime IdCompressor", "NoCompat", (getTestObjectProvider, apis)
144144
],
145145
fluidDataObjectType: DataObjectFactoryType.Test,
146146
loaderProps: {},
147+
runtimeOptions: {
148+
enableRuntimeIdCompressor: "off",
149+
},
147150
};
148151

149152
const containerConfigWithCompressor: ITestContainerConfig = {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import {
4444
ContainerRuntime,
4545
DefaultSummaryConfiguration,
4646
type RecentlyAddedContainerRuntimeMessageDetails,
47+
CompressionAlgorithms,
4748
} from "@fluidframework/container-runtime";
4849
import { IDocumentServiceFactory } from "@fluidframework/driver-definitions";
4950
import { wrapObjectAndOverride } from "../mocking.js";
@@ -89,6 +90,11 @@ describeCompat("stashed ops", "NoCompat", (getTestObjectProvider, apis) => {
8990
fluidDataObjectType: DataObjectFactoryType.Test,
9091
registry,
9192
runtimeOptions: {
93+
chunkSizeInBytes: Number.POSITIVE_INFINITY, // disable
94+
compressionOptions: {
95+
minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
96+
compressionAlgorithm: CompressionAlgorithms.lz4,
97+
},
9298
summaryOptions: {
9399
summaryConfigOverrides: {
94100
...DefaultSummaryConfiguration,

packages/test/test-version-utils/src/compatConfig.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
codeVersion,
2424
testBaseVersion,
2525
} from "./baseVersion.js";
26-
import { getRequestedVersion } from "./versionUtils.js";
26+
import { getRequestedVersion, resolveVersion } from "./versionUtils.js";
2727

2828
/**
2929
* Represents a previous major release of a package based on the provided delta. For example, if the base version is 2.X and
@@ -70,7 +70,7 @@ const defaultCompatVersions = {
7070
// N and N - 1
7171
currentVersionDeltas: [0, -1],
7272
// we are currently supporting 1.3.X long-term
73-
ltsVersions: ["^1.3.4"],
73+
ltsVersions: [resolveVersion("^1.3", false)],
7474
};
7575

7676
// This indicates the number of versions above 2.0.0.internal.1.y.z that we want to support for back compat.

packages/test/test-version-utils/src/compatUtils.ts

Lines changed: 125 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Licensed under the MIT License.
44
*/
55

6+
import * as semver from "semver";
67
import { FluidTestDriverConfig, createFluidTestDriver } from "@fluid-private/test-drivers";
78
import {
89
FluidObject,
@@ -28,6 +29,12 @@ import {
2829
} from "@fluidframework/test-utils";
2930
import { TestDriverTypes } from "@fluidframework/test-driver-definitions";
3031
import { mixinAttributor } from "@fluid-experimental/attributor";
32+
import {
33+
IContainerRuntimeOptions,
34+
DefaultSummaryConfiguration,
35+
CompressionAlgorithms,
36+
ICompressionRuntimeOptions,
37+
} from "@fluidframework/container-runtime";
3138
import { pkgVersion } from "./packageVersion.js";
3239
import {
3340
getLoaderApi,
@@ -42,6 +49,96 @@ import {
4249
*/
4350
export const TestDataObjectType = "@fluid-example/test-dataStore";
4451

52+
/**
53+
* This function modifies container runtime options according to a version of runtime used.
54+
* If a version of runtime does not support some options, they are removed.
55+
* If a version runtime supports some options, such options are enabled to increase a chance of
56+
* hitting feature set controlled by such options, and thus increase chances of finding product bugs.
57+
*
58+
* @param version - a version of container runtime to be used in test
59+
* @param optionsArg - input runtime options (optional)
60+
* @returns - runtime options that should be used with a given version of container runtime
61+
* @internal
62+
*/
63+
function filterRuntimeOptionsForVersion(
64+
version: string,
65+
optionsArg: IContainerRuntimeOptions = {
66+
summaryOptions: {
67+
summaryConfigOverrides: {
68+
...DefaultSummaryConfiguration,
69+
...{
70+
initialSummarizerDelayMs: 0,
71+
},
72+
},
73+
},
74+
},
75+
) {
76+
let options = { ...optionsArg };
77+
78+
// No test fails with this option, it allows us to validate properly expectations and
79+
// implementation of services
80+
options.loadSequenceNumberVerification = "close";
81+
82+
const compressorDisabled: ICompressionRuntimeOptions = {
83+
minimumBatchSizeInBytes: Number.POSITIVE_INFINITY,
84+
compressionAlgorithm: CompressionAlgorithms.lz4,
85+
};
86+
87+
// These is the "maximum" config.
88+
const {
89+
compressionOptions = {
90+
minimumBatchSizeInBytes: 200,
91+
compressionAlgorithm: CompressionAlgorithms.lz4,
92+
},
93+
enableGroupedBatching = true,
94+
enableRuntimeIdCompressor = "on",
95+
// chunkSizeInBytes = 200,
96+
} = options;
97+
98+
if (version.startsWith("1.")) {
99+
options = {
100+
...options,
101+
// None of these features are supported by 1.3
102+
compressionOptions: undefined,
103+
enableGroupedBatching: false,
104+
enableRuntimeIdCompressor: undefined,
105+
chunkSizeInBytes: Number.POSITIVE_INFINITY, // disabled
106+
};
107+
} else if (version.startsWith("2.0.0-rc.1.")) {
108+
options = {
109+
compressionOptions: compressorDisabled, // Can't use compression, need https://github.com/microsoft/FluidFramework/pull/20111 fix
110+
enableGroupedBatching,
111+
enableRuntimeIdCompressor: undefined, // it was boolean in RC1, switched to enum in RC2
112+
chunkSizeInBytes: Number.POSITIVE_INFINITY, // disabled, need https://github.com/microsoft/FluidFramework/pull/20115 fix
113+
...options,
114+
};
115+
} else if (version.startsWith("2.0.0-rc.2.")) {
116+
options = {
117+
compressionOptions: compressorDisabled, // Can't use compression, need https://github.com/microsoft/FluidFramework/pull/20111 fix
118+
enableGroupedBatching,
119+
// Can't track it down, but enabling Id Compressor for this config results in small number of t9s tests to timeout.
120+
// This is very likely related to one of these bugfixes that missed that release:
121+
// https://github.com/microsoft/FluidFramework/pull/20089
122+
// https://github.com/microsoft/FluidFramework/pull/20080
123+
enableRuntimeIdCompressor: undefined,
124+
chunkSizeInBytes: Number.POSITIVE_INFINITY, // disabled, need https://github.com/microsoft/FluidFramework/pull/20115 fix
125+
...options,
126+
};
127+
} else {
128+
// "2.0.0-rc.3." ++
129+
options = {
130+
compressionOptions,
131+
enableGroupedBatching,
132+
// need to investigate - some small number of t9s tests time out with this option on.
133+
// chunkSizeInBytes,
134+
enableRuntimeIdCompressor,
135+
...options,
136+
};
137+
}
138+
139+
return options;
140+
}
141+
45142
/**
46143
* @internal
47144
*/
@@ -138,7 +235,10 @@ export async function getVersionedTestObjectProviderFromApis(
138235
return new factoryCtor(
139236
TestDataObjectType,
140237
dataStoreFactory,
141-
containerOptions?.runtimeOptions,
238+
filterRuntimeOptionsForVersion(
239+
apis.containerRuntime.version,
240+
containerOptions?.runtimeOptions,
241+
),
142242
);
143243
};
144244

@@ -207,6 +307,28 @@ export async function getCompatVersionedTestObjectProviderFromApis(
207307
apis.dataRuntimeForLoading,
208308
);
209309

310+
// We want to ensure that we are testing all latest runtime features, but only if both runtimes
311+
// (one that creates containers and one that loads them) support them.
312+
//
313+
// Theoretically it should be fine to use config for apis.containerRuntimeForLoading?.version.
314+
// If it's higher then apis.containerRuntime, then unknown to lower version of apis.containerRuntime
315+
// would be ignored.
316+
//
317+
// But TestObjectProviderWithVersionedLoad.createLoader() implementation is dumb - it resets this.useCreateApi
318+
// on first call and thus uses apis.containerRuntimeForLoading for any container created after.
319+
// Many use non-first container instance to send ops, so that screws things up.
320+
//
321+
// As result, we absolutly need to use the min between two versions!
322+
const versionForCreating = apis.containerRuntime?.version;
323+
assert(versionForCreating !== undefined, "versionForCreating");
324+
const versionForLoading = apis.containerRuntimeForLoading?.version;
325+
assert(versionForLoading !== undefined, "versionForLoading");
326+
327+
const minVersion =
328+
semver.compare(versionForCreating, versionForLoading) < 0
329+
? versionForCreating
330+
: versionForLoading;
331+
210332
const createContainerFactoryFn = (containerOptions?: ITestContainerConfig) => {
211333
const dataStoreFactory = getDataStoreFactoryFn(containerOptions);
212334
const factoryCtor = createTestContainerRuntimeFactory(
@@ -215,7 +337,7 @@ export async function getCompatVersionedTestObjectProviderFromApis(
215337
return new factoryCtor(
216338
TestDataObjectType,
217339
dataStoreFactory,
218-
containerOptions?.runtimeOptions,
340+
filterRuntimeOptionsForVersion(minVersion, containerOptions?.runtimeOptions),
219341
[innerRequestHandler],
220342
);
221343
};
@@ -235,7 +357,7 @@ export async function getCompatVersionedTestObjectProviderFromApis(
235357
return new factoryCtor(
236358
TestDataObjectType,
237359
dataStoreFactory,
238-
containerOptions?.runtimeOptions,
360+
filterRuntimeOptionsForVersion(minVersion, containerOptions?.runtimeOptions),
239361
[innerRequestHandler],
240362
);
241363
};

0 commit comments

Comments
 (0)