Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
"js-base64": "^3.7.2",
"js-sdsl": "^4.4.0",
"jsbi": "^4.3.0",
"json-crdt-traces": "https://github.com/streamich/json-crdt-traces#5f68a13baf798897d39b87d7028b0b3cd5a50a6c",
"json-crdt-traces": "https://github.com/streamich/json-crdt-traces#02718a7a5d09e0dc6c31ea7d45a9ce3cbb0bf085",
"json-logic-js": "^2.0.1",
"json-pack-napi": "^0.0.2",
"load-script": "^2.0.0",
Expand Down
20 changes: 20 additions & 0 deletions src/json-crdt/__bench__/util/fuzzer-traces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import * as path from 'path';
import * as fs from 'fs';
import {Patch} from '../../../json-crdt-patch';
import {CborDecoder} from '../../../json-pack/cbor/CborDecoder';
import {Model} from '../../model';
import {bufferToUint8Array} from '../../../util/buffers/bufferToUint8Array';

export const loadFuzzerTrace = (traceName: string): [batch: Patch[], model: Model] => {
const root = path.resolve(__dirname, '..', '..', '..', '..');
const dir = path.join(root, 'node_modules', 'json-crdt-traces', 'traces', 'fuzzer', 'processed', traceName);
const patchFile = path.join(dir, 'patches.bin');
const modelFile = path.join(dir, 'model.bin');
const buf = fs.readFileSync(patchFile);
const modelBuf = bufferToUint8Array(fs.readFileSync(modelFile));
const model = Model.fromBinary(modelBuf);
const cborDecoder = new CborDecoder();
const data = cborDecoder.read(buf) as Uint8Array[];
const batch = data.map((blob) => Patch.fromBinary(blob));
return [batch, model];
};
27 changes: 26 additions & 1 deletion src/json-crdt/__tests__/editing-traces.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {sequentialTraceNames, traces} from '../__bench__/util/traces';
import {editors} from '../__bench__/util/editors';
import {Model} from '../model';
import {loadConcurrentTrace} from '../__bench__/util/concurrent-trace';
import {loadFuzzerTrace} from '../__bench__/util/fuzzer-traces';

describe('sequential traces', () => {
const editor = editors['json-joy'];
Expand All @@ -15,7 +16,7 @@ describe('sequential traces', () => {
}
});

describe.skip('concurrent traces', () => {
describe('concurrent traces', () => {
const traces: string[] = ['friendsforever'];
for (const traceName of traces) {
test(`"${traceName}" trace`, async () => {
Expand All @@ -26,3 +27,27 @@ describe.skip('concurrent traces', () => {
});
}
});

describe('fuzzer traces', () => {
const traces = [
<const>'trace-1',
<const>'trace-2',
<const>'trace-3',
<const>'long',
<const>'short',
<const>'low-concurrency',
<const>'high-concurrency',
<const>'str-only',
<const>'bin-only',
];

for (const traceName of traces) {
test(`"${traceName}" trace`, async () => {
const [batch, doc] = loadFuzzerTrace(traceName);
const model = Model.withLogicalClock(1000000);
model.applyBatch(batch);
expect(Model.fromBinary(model.toBinary()).toString()).toBe(doc.toString());
expect(model.view()).toStrictEqual(doc.view());
});
}
});
5 changes: 5 additions & 0 deletions src/json-crdt/__tests__/fuzzer/JsonCrdtFuzzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {FuzzerOptions} from './types';
import {RandomJson} from '../../../json-random/RandomJson';
import {generateInteger} from './util';
import {PatchBuilder} from '../../../json-crdt-patch/PatchBuilder';
import {Patch} from '../../../json-crdt-patch';

export const defaultFuzzerOptions: FuzzerOptions = {
startingValue: undefined,
Expand All @@ -18,12 +19,14 @@ export const defaultFuzzerOptions: FuzzerOptions = {
concurrentPeers: [1, 6],
patchesPerPeer: [0, 12],
testCodecs: true,
collectPatches: false,
};

export class JsonCrdtFuzzer {
public opts: FuzzerOptions;
public model: Model;
public picker: Picker;
public patches: Patch[] = [];

constructor(opts: Partial<FuzzerOptions> = {}) {
this.opts = {...defaultFuzzerOptions, ...opts};
Expand All @@ -39,6 +42,7 @@ export class JsonCrdtFuzzer {
const builder = new PatchBuilder(this.model.clock);
builder.root(builder.json(json));
const patch = builder.flush();
this.patches.push(patch);
this.model.applyPatch(patch);
}

Expand All @@ -47,6 +51,7 @@ export class JsonCrdtFuzzer {
const session = new SessionLogical(this, concurrency);
session.generateEdits();
session.synchronize();
if (this.opts.collectPatches) for (const patches of session.patches) this.patches.push(...patches);
return session;
}
}
40 changes: 40 additions & 0 deletions src/json-crdt/__tests__/fuzzer/generate-trace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* tslint:disable no-console */
// Run: npx ts-node src/json-crdt/__tests__/fuzzer/generate-trace.ts

import {Patch} from '../../../json-crdt-patch';
import {Model} from '../../model';
import {JsonCrdtFuzzer} from './JsonCrdtFuzzer';
import {CborEncoder} from '../../../json-pack/cbor/CborEncoder';
import {Writer} from '../../../util/buffers/Writer';
import * as fs from 'fs';

const sessionNum = 100;
const fuzzer = new JsonCrdtFuzzer({
// concurrentPeers: [20, 100],
// startingValue: new Uint8Array([1, 2, 3]),
collectPatches: true,
});
fuzzer.setupModel();

for (let ses = 0; ses < sessionNum; ses++) {
fuzzer.executeConcurrentSession();
}

const patches: Patch[] = [];
const dupes: Set<string> = new Set();
for (const patch of fuzzer.patches) {
const key = `${patch.getId()?.sid}_${patch.getId()?.time}`;
if (dupes.has(key)) continue;
dupes.add(key);
patches.push(patch);
}

const model = Model.withLogicalClock();
model.applyBatch(patches);
const cborEncoder = new CborEncoder(new Writer());
fs.writeFileSync(__dirname + '/trace.cbor', cborEncoder.encode(patches.map((p) => p.toBinary())));

// console.log(Buffer.from(jsonEncoder.encode(encoded)).toString());
console.log(model.view());
console.log(fuzzer.model.view());
// console.log(model + '');
3 changes: 3 additions & 0 deletions src/json-crdt/__tests__/fuzzer/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,7 @@ export interface FuzzerOptions {

/** Do not generate "__proto__" as a string, so it does not appear as object key. */
noProtoString?: boolean;

/** Whether to collect all generated patches. */
collectPatches?: boolean;
}
4 changes: 2 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3664,9 +3664,9 @@ jsesc@^2.5.1:
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==

"json-crdt-traces@https://github.com/streamich/json-crdt-traces#5f68a13baf798897d39b87d7028b0b3cd5a50a6c":
"json-crdt-traces@https://github.com/streamich/json-crdt-traces#02718a7a5d09e0dc6c31ea7d45a9ce3cbb0bf085":
version "0.0.1"
resolved "https://github.com/streamich/json-crdt-traces#5f68a13baf798897d39b87d7028b0b3cd5a50a6c"
resolved "https://github.com/streamich/json-crdt-traces#02718a7a5d09e0dc6c31ea7d45a9ce3cbb0bf085"

json-logic-js@^2.0.1:
version "2.0.2"
Expand Down