Skip to content

Commit

Permalink
test(tree): Add axiomatic change rebaser tests to test:stress (micros…
Browse files Browse the repository at this point in the history
…oft#19485)

## Description

Adds slightly longer variants of the axiomatic tests for optional field
and sequence field to the tree package's `test:stress` command.

In doing so, I added a `describeStress` block to complement
`describeFuzz`, which isn't typed as getting an explicit test count. I
thought this was more fitting for cases like these.

---------

Co-authored-by: Abram Sanderson <absander@microsoft.com>
  • Loading branch information
Abe27342 and Abram Sanderson committed Feb 5, 2024
1 parent b3496d2 commit 56fad1c
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

import { strict as assert } from "assert";
import { describeStress } from "@fluid-private/stochastic-test-utils";
import { CrossFieldManager, NodeChangeset } from "../../../feature-libraries/index.js";
import {
ChangesetLocalId,
Expand Down Expand Up @@ -491,15 +492,15 @@ export function testRebaserAxioms() {
runSingleEditRebaseAxiomSuite({ content: "A" });
});

describe("Exhaustive", () => {
describeStress("Exhaustive", ({ isStress }) => {
runExhaustiveComposeRebaseSuite(
[{ content: undefined }, { content: "A" }],
generateChildStates,
{ rebase, rebaseComposed, compose, invert, assertEqual, createEmpty },
{
numberOfEditsToRebase: 3,
numberOfEditsToRebaseOver: 3,
numberOfEditsToVerifyAssociativity: 4,
numberOfEditsToRebaseOver: isStress ? 5 : 3,
numberOfEditsToVerifyAssociativity: isStress ? 6 : 4,
},
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

import { assert } from "@fluidframework/core-utils";
import { describeStress } from "@fluid-private/stochastic-test-utils";
import { SequenceField as SF } from "../../../feature-libraries/index.js";
import {
ChangesetLocalId,
Expand Down Expand Up @@ -677,7 +678,8 @@ const fieldRebaser: BoundFieldChangeRebaser<TestChangeset> = {

export function testStateBasedRebaserAxioms() {
describe("State-based Rebaser Axioms", () => {
describe("Lineage Method", () => {
describeStress("Lineage Method", function ({ isStress }) {
this.timeout(30_000);
const allocator = idAllocatorFromMaxId();
const startingLength = 2;
const startingState: NodeState[] = makeArray(startingLength, () => ({
Expand All @@ -697,12 +699,13 @@ export function testStateBasedRebaserAxioms() {
fieldRebaser,
{
groupSubSuites: true,
numberOfEditsToVerifyAssociativity: 3,
numberOfEditsToVerifyAssociativity: isStress ? 4 : 3,
skipRebaseOverCompose: false,
},
);
});
describe("Tombstone Method", () => {
describeStress("Tombstone Method", function ({ isStress }) {
this.timeout(30_000);
const allocator = idAllocatorFromMaxId();
const startingLength = 2;
const startingState: NodeState[] = makeArray(startingLength, () => ({
Expand All @@ -722,7 +725,7 @@ export function testStateBasedRebaserAxioms() {
fieldRebaser,
{
groupSubSuites: true,
numberOfEditsToVerifyAssociativity: 3,
numberOfEditsToVerifyAssociativity: isStress ? 4 : 3,
skipRebaseOverCompose: false,
},
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ export function combineReducersAsync<TOperation extends {
// @internal (undocumented)
export function createFuzzDescribe(optionsArg?: FuzzDescribeOptions): DescribeFuzz;

// @internal (undocumented)
export type CreateMochaSuite<TArgs> = (name: string, createTests: (this: Mocha.Suite, args: TArgs) => void) => Mocha.Suite | void;

// @internal
export function createWeightedAsyncGenerator<T, TState extends BaseFuzzTestState>(weights: AsyncWeights<T, TState>): AsyncGenerator_2<T, TState>;

Expand All @@ -77,13 +80,16 @@ export function createWeightedGenerator<T, TState extends BaseFuzzTestState>(wei
export const defaultOptions: Required<FuzzDescribeOptions>;

// @internal (undocumented)
export type DescribeFuzz = DescribeFuzzSuite & Record<"skip" | "only", DescribeFuzzSuite>;
export type DescribeFuzz = MochaSuiteWithArguments<FuzzSuiteArguments>;

// @internal
export const describeFuzz: DescribeFuzz;

// @internal (undocumented)
export type DescribeFuzzSuite = (name: string, tests: (this: Mocha.Suite, args: FuzzSuiteArguments) => void) => Mocha.Suite | void;
export type DescribeStress = MochaSuiteWithArguments<StressSuiteArguments>;

// @internal
export const describeStress: DescribeStress;

// @internal (undocumented)
export const done: unique symbol;
Expand All @@ -103,8 +109,7 @@ export interface FuzzDescribeOptions {
}

// @internal (undocumented)
export interface FuzzSuiteArguments {
isStress: boolean;
export interface FuzzSuiteArguments extends StressSuiteArguments {
testCount: number;
}

Expand Down Expand Up @@ -152,6 +157,9 @@ export abstract class MarkovChain<PredictionPointType, OutputType> {
static readonly MARKOV_SENTENCE_END_KEY = "MARKOV_SENTENCE_END_KEY_01$#@%^#";
}

// @internal
export type MochaSuiteWithArguments<TArgs> = CreateMochaSuite<TArgs> & Record<"skip" | "only", CreateMochaSuite<TArgs>>;

// @internal (undocumented)
export class PerformanceWordMarkovChain extends MarkovChain<string, string> {
constructor(random?: IRandom, chain?: Record<string, string[]>);
Expand Down Expand Up @@ -225,6 +233,11 @@ export class SpaceEfficientWordMarkovChain extends MarkovChain<string, string> {
readonly random: IRandom;
}

// @internal (undocumented)
export interface StressSuiteArguments {
isStress: boolean;
}

// @internal
export function take<T, TState>(n: number, generator: Generator_2<T, TState>): Generator_2<T, TState>;

Expand Down
70 changes: 54 additions & 16 deletions packages/test/stochastic-test-utils/src/describeFuzz.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,37 @@

import process from "process";

function createFuzzSuite(
tests: (this: Mocha.Suite, args: FuzzSuiteArguments) => void,
args: FuzzSuiteArguments,
function createSuite<TArgs extends StressSuiteArguments>(
tests: (this: Mocha.Suite, args: TArgs) => void,
args: TArgs,
) {
return function (this: Mocha.Suite) {
if (args.isStress) {
// Stress runs may have tests which are expected to take longer amounts of time.
// Don't override the timeout if it's already set to a higher value, though.
this.timeout(Math.max(10_000, this.timeout()));
}
tests.bind(this)(args);
};
}

/**
* @internal
*/
export type DescribeFuzzSuite = (
name: string,
tests: (this: Mocha.Suite, args: FuzzSuiteArguments) => void,
) => Mocha.Suite | void;
export interface StressSuiteArguments {
/**
* Whether the current run is a stress run, which generally runs longer or more programatically generated tests.
*
* Packages which use this should generally have a `test:stress` script in their package.json for conveniently running
* the equivalent checks locally.
*/
isStress: boolean;
}

/**
* @internal
*/
export interface FuzzSuiteArguments {
export interface FuzzSuiteArguments extends StressSuiteArguments {
/**
* The number of tests this suite should produce up to a constant factor.
* It's up to the suite author to decide which parameters to vary in order to scale up the number of tests.
Expand All @@ -34,16 +44,32 @@ export interface FuzzSuiteArguments {
* `4 * testCount` tests) is fine.
*/
testCount: number;
/**
* Whether the current run is a stress run.
*/
isStress: boolean;
}

/**
* @internal
*/
export type DescribeFuzz = DescribeFuzzSuite & Record<"skip" | "only", DescribeFuzzSuite>;
export type CreateMochaSuite<TArgs> = (
name: string,
createTests: (this: Mocha.Suite, args: TArgs) => void,
) => Mocha.Suite | void;

/**
* A mocha-like test suite which is also provided some context to its test creation callback.
* @internal
*/
export type MochaSuiteWithArguments<TArgs> = CreateMochaSuite<TArgs> &
Record<"skip" | "only", CreateMochaSuite<TArgs>>;

/**
* @internal
*/
export type DescribeStress = MochaSuiteWithArguments<StressSuiteArguments>;

/**
* @internal
*/
export type DescribeFuzz = MochaSuiteWithArguments<FuzzSuiteArguments>;

/**
* @internal
Expand Down Expand Up @@ -72,9 +98,9 @@ export function createFuzzDescribe(optionsArg?: FuzzDescribeOptions): DescribeFu
const isStress = process.env?.FUZZ_STRESS_RUN !== undefined && !!process.env?.FUZZ_STRESS_RUN;
const args = { testCount, isStress };
const d: DescribeFuzz = (name, tests) =>
(isStress ? describe.only : describe)(name, createFuzzSuite(tests, args));
d.skip = (name, tests) => describe.skip(name, createFuzzSuite(tests, args));
d.only = (name, tests) => describe.only(name, createFuzzSuite(tests, args));
(isStress ? describe.only : describe)(name, createSuite(tests, args));
d.skip = (name, tests) => describe.skip(name, createSuite(tests, args));
d.only = (name, tests) => describe.only(name, createSuite(tests, args));
return d;
}

Expand All @@ -86,3 +112,15 @@ export function createFuzzDescribe(optionsArg?: FuzzDescribeOptions): DescribeFu
* @internal
*/
export const describeFuzz: DescribeFuzz = createFuzzDescribe();

/**
* Like `Mocha.describe`, but enables detection of whether the current run is a stress run.
* The test creation callback receives an `isStress` parameter which it should use to support
* this functionality as it deems fit.
*
* @privateRemarks - Reusing `createFuzzDescribe` here means tests will also receive a testCount parameter,
* but since the typing doesn't include that information it shouldn't be used.
*
* @internal
*/
export const describeStress: DescribeStress = createFuzzDescribe();
6 changes: 5 additions & 1 deletion packages/test/stochastic-test-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@
export { combineReducers, combineReducersAsync } from "./combineReducers";
export {
createFuzzDescribe,
CreateMochaSuite,
defaultOptions,
DescribeFuzz,
describeFuzz,
DescribeFuzzSuite,
DescribeStress,
describeStress,
FuzzDescribeOptions,
FuzzSuiteArguments,
MochaSuiteWithArguments,
StressSuiteArguments,
} from "./describeFuzz";
export {
asyncGeneratorFromArray,
Expand Down

0 comments on commit 56fad1c

Please sign in to comment.