Skip to content

Commit 1842e6c

Browse files
wip
1 parent 95be7e0 commit 1842e6c

File tree

3 files changed

+87
-20
lines changed

3 files changed

+87
-20
lines changed

packages/dds/matrix/src/test/fuzz.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import { isFluidHandle, toFluidHandleInternal } from "@fluidframework/runtime-ut
1919
import type { MatrixItem } from "../ops.js";
2020
import { SharedMatrix, type SharedMatrixFactory } from "../runtime.js";
2121

22+
import { hasSharedMatrixOracle } from "./matrixOracle.js";
23+
2224
/**
2325
* Supported cell values used within the fuzz model.
2426
*/
@@ -225,7 +227,17 @@ export const baseSharedMatrixModel: Omit<
225227
factory: SharedMatrix.getFactory(),
226228
generatorFactory: () => takeAsync(50, makeGenerator()),
227229
reducer: (state, operation) => reducer(state, operation),
228-
validateConsistency: async (a, b) => assertMatricesAreEquivalent(a.channel, b.channel),
230+
validateConsistency: async (a, b) => {
231+
if (hasSharedMatrixOracle(a.channel)) {
232+
a.channel.matrixOracle.validate();
233+
}
234+
235+
if (hasSharedMatrixOracle(b.channel)) {
236+
b.channel.matrixOracle.validate();
237+
}
238+
239+
return assertMatricesAreEquivalent(a.channel, b.channel);
240+
},
229241
minimizationTransforms: ["count", "start", "row", "col"].map((p) => (op) => {
230242
if (p in op && typeof op[p] === "number" && op[p] > 0) {
231243
op[p]--;

packages/dds/matrix/src/test/matrix.fuzz.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ describe("Matrix fuzz tests", function () {
6363
...baseOptions,
6464
reconnectProbability: 0,
6565
// Uncomment to replay a particular seed.
66-
// replay: 0,
66+
// only: 97,
6767
skip: [4, 54, 73, 97],
6868
saveFailures: { directory: path.join(_dirname, "../../../src/test/mocha/results/1") },
6969
});

packages/dds/matrix/src/test/matrixOracle.ts

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,78 @@ import { strict as assert } from "node:assert";
77

88
import type { ISharedMatrix, SharedMatrix } from "../matrix.js";
99

10-
/**
11-
* @internal
12-
*/
10+
import { TestConsumer } from "./testconsumer.js";
11+
1312
export class SharedMatrixOracle {
14-
constructor(private readonly shared: ISharedMatrix) {
15-
this.shared.on("conflict", (row, col, currentValue, conflictingValue, target) => {
16-
if (row < this.shared.rowCount && col < this.shared.colCount) {
17-
assert(
18-
this.shared.isSetCellConflictResolutionPolicyFWW(),
19-
"Conflict should only fire in FWW mode",
20-
);
13+
private readonly testConsumer: TestConsumer;
14+
private readonly conflictListener: (
15+
row: number,
16+
col: number,
17+
currentValue: unknown,
18+
conflictingValue: unknown,
19+
) => void;
20+
21+
constructor(private readonly shared: SharedMatrix) {
22+
this.testConsumer = new TestConsumer(shared);
23+
24+
this.conflictListener = (row, col, currentValue, conflictingValue) => {
25+
this.onConflict(row, col, currentValue, conflictingValue);
26+
};
27+
28+
this.shared.on("conflict", this.conflictListener);
29+
}
30+
31+
private onConflict(
32+
row: number,
33+
col: number,
34+
currentValue: unknown,
35+
conflictingValue: unknown,
36+
): void {
37+
assert.ok(
38+
this.shared.isSetCellConflictResolutionPolicyFWW(),
39+
"Conflict should only fire in FWW mode",
40+
);
41+
42+
if (row < this.shared.rowCount && col < this.shared.colCount) {
43+
assert(
44+
this.shared.isSetCellConflictResolutionPolicyFWW(),
45+
"Conflict should only fire in FWW mode",
46+
);
2147

22-
const actual = this.shared.getCell(row, col);
48+
const actual = this.testConsumer.getCell(row, col);
2349

24-
// The loser must be different
25-
assert.notDeepStrictEqual(currentValue, conflictingValue);
50+
// The loser must be different
51+
assert.notDeepStrictEqual(currentValue, conflictingValue);
2652

27-
// The cell contains the winner
28-
assert.deepStrictEqual(
53+
// The cell contains the winner
54+
assert.deepStrictEqual(
55+
actual,
56+
currentValue,
57+
`Conflict mismatch at [${row},${col}]: expected winner=${currentValue}, actual=${actual} with conflicting value=${conflictingValue}`,
58+
);
59+
}
60+
}
61+
62+
public validate(): void {
63+
const rows = this.shared.rowCount;
64+
const cols = this.shared.colCount;
65+
66+
// Validate the entire matrix
67+
for (let r = 0; r < rows; r++) {
68+
for (let c = 0; c < cols; c++) {
69+
const expected = this.testConsumer.getCell(r, c);
70+
const actual = this.shared.getCell(r, c);
71+
assert.strictEqual(
2972
actual,
30-
currentValue,
31-
`Conflict mismatch at [${row},${col}]: expected winner=${currentValue}, actual=${actual} with conflicting value=${conflictingValue}`,
73+
expected,
74+
`Mismatch at [${r},${c}]: expected="${expected}", actual="${actual}"`,
3275
);
3376
}
34-
});
77+
}
78+
}
79+
80+
public dispose(): void {
81+
this.shared.off("conflict", this.conflictListener);
3582
}
3683
}
3784

@@ -41,3 +88,11 @@ export class SharedMatrixOracle {
4188
export interface IChannelWithOracles extends SharedMatrix {
4289
matrixOracle: SharedMatrixOracle;
4390
}
91+
92+
/**
93+
* Type guard for SharedMatrix with an oracle
94+
* @internal
95+
*/
96+
export function hasSharedMatrixOracle(s: ISharedMatrix): s is IChannelWithOracles {
97+
return "matrixOracle" in s && s.matrixOracle instanceof SharedMatrixOracle;
98+
}

0 commit comments

Comments
 (0)