@fluidframework/test-runtime-utils 2.70.0-361092 → 2.70.0-361788
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api-report/test-runtime-utils.legacy.beta.api.md +2 -2
- package/dist/mocks.d.ts +19 -6
- package/dist/mocks.d.ts.map +1 -1
- package/dist/mocks.js +51 -9
- package/dist/mocks.js.map +1 -1
- package/lib/mocks.d.ts +19 -6
- package/lib/mocks.d.ts.map +1 -1
- package/lib/mocks.js +49 -8
- package/lib/mocks.js.map +1 -1
- package/package.json +35 -16
- package/src/mocks.ts +62 -12
package/src/mocks.ts
CHANGED
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
ITreeEntry,
|
|
46
46
|
MessageType,
|
|
47
47
|
ISequencedDocumentMessage,
|
|
48
|
+
type ISnapshotTree,
|
|
48
49
|
} from "@fluidframework/driver-definitions/internal";
|
|
49
50
|
import type { IIdCompressor } from "@fluidframework/id-compressor";
|
|
50
51
|
import type {
|
|
@@ -708,7 +709,10 @@ export class MockQuorumClients implements IQuorumClients, EventEmitter {
|
|
|
708
709
|
}
|
|
709
710
|
|
|
710
711
|
getMembers(): Map<string, ISequencedClient> {
|
|
711
|
-
|
|
712
|
+
// Implementation always generates a new Map.
|
|
713
|
+
// Mock should as well in case any callers rely on being able to modify
|
|
714
|
+
// the returned Map.
|
|
715
|
+
return new Map(this.members);
|
|
712
716
|
}
|
|
713
717
|
getMember(clientId: string): ISequencedClient | undefined {
|
|
714
718
|
return this.getMembers().get(clientId);
|
|
@@ -1040,14 +1044,6 @@ export class MockFluidDataStoreRuntime
|
|
|
1040
1044
|
return null;
|
|
1041
1045
|
}
|
|
1042
1046
|
|
|
1043
|
-
/**
|
|
1044
|
-
* @deprecated Use `IFluidDataStoreContext.submitMessage` instead.
|
|
1045
|
-
* @see https://github.com/microsoft/FluidFramework/issues/24406
|
|
1046
|
-
*/
|
|
1047
|
-
public submitMessage(type: MessageType, content: any) {
|
|
1048
|
-
return null;
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
1047
|
private submitMessageInternal(messageContent: any, localOpMetadata: unknown): number {
|
|
1052
1048
|
assert(
|
|
1053
1049
|
this.containerRuntime !== undefined,
|
|
@@ -1232,22 +1228,36 @@ export class MockEmptyDeltaConnection implements IDeltaConnection {
|
|
|
1232
1228
|
* @legacy @beta
|
|
1233
1229
|
*/
|
|
1234
1230
|
export class MockObjectStorageService implements IChannelStorageService {
|
|
1235
|
-
|
|
1231
|
+
private readonly snapshotTree: ISnapshotTree;
|
|
1232
|
+
|
|
1233
|
+
/**
|
|
1234
|
+
* @param contents - Key value pairs that represent a snapshot.
|
|
1235
|
+
* The keys are the path to the contents of a blob in the snapshot tree. The corresponding values are its contents.
|
|
1236
|
+
*
|
|
1237
|
+
* @remarks
|
|
1238
|
+
* The snapshot contents must not change after it has been passed here as the changes will not be reflected
|
|
1239
|
+
* in the snapshot tree retrieved via `getSnapshotTree`.
|
|
1240
|
+
*/
|
|
1241
|
+
public constructor(private readonly contents: { [key: string]: string }) {
|
|
1242
|
+
this.snapshotTree = createSnapshotTreeFromContents(contents);
|
|
1243
|
+
}
|
|
1236
1244
|
|
|
1237
1245
|
public async readBlob(path: string): Promise<ArrayBufferLike> {
|
|
1238
1246
|
return stringToBuffer(this.contents[path], "utf8");
|
|
1239
1247
|
}
|
|
1240
|
-
|
|
1241
1248
|
public async contains(path: string): Promise<boolean> {
|
|
1242
1249
|
return this.contents[path] !== undefined;
|
|
1243
1250
|
}
|
|
1244
|
-
|
|
1245
1251
|
public async list(path: string): Promise<string[]> {
|
|
1246
1252
|
const pathPartsLength = getNormalizedObjectStoragePathParts(path).length;
|
|
1247
1253
|
return Object.keys(this.contents).filter(
|
|
1248
1254
|
(key) => key.startsWith(path) && key.split("/").length === pathPartsLength + 1,
|
|
1249
1255
|
);
|
|
1250
1256
|
}
|
|
1257
|
+
|
|
1258
|
+
public getSnapshotTree(): ISnapshotTree {
|
|
1259
|
+
return this.snapshotTree;
|
|
1260
|
+
}
|
|
1251
1261
|
}
|
|
1252
1262
|
|
|
1253
1263
|
/**
|
|
@@ -1294,3 +1304,43 @@ function setContentsFromSummaryTree(
|
|
|
1294
1304
|
}
|
|
1295
1305
|
}
|
|
1296
1306
|
}
|
|
1307
|
+
|
|
1308
|
+
/**
|
|
1309
|
+
* Create an ISnapshotTree from contents object (reverse of setContentsFromSummaryTree)
|
|
1310
|
+
* @param contents - Object with path/value pairs
|
|
1311
|
+
* @returns ISnapshotTree representing the hierarchical structure
|
|
1312
|
+
*/
|
|
1313
|
+
export function createSnapshotTreeFromContents(contents: {
|
|
1314
|
+
[key: string]: string;
|
|
1315
|
+
}): ISnapshotTree {
|
|
1316
|
+
const tree: ISnapshotTree = {
|
|
1317
|
+
trees: {},
|
|
1318
|
+
blobs: {},
|
|
1319
|
+
};
|
|
1320
|
+
|
|
1321
|
+
for (const [path, content] of Object.entries(contents)) {
|
|
1322
|
+
// Remove empty strings to handle leading, trailing, or consecutive slashes in the path.
|
|
1323
|
+
const pathParts = path.split("/").filter((part) => part !== "");
|
|
1324
|
+
let currentTree = tree;
|
|
1325
|
+
|
|
1326
|
+
// Navigate/create the tree structure for all but the last part
|
|
1327
|
+
for (let i = 0; i < pathParts.length - 1; i++) {
|
|
1328
|
+
const part = pathParts[i];
|
|
1329
|
+
if (!currentTree.trees[part]) {
|
|
1330
|
+
currentTree.trees[part] = {
|
|
1331
|
+
trees: {},
|
|
1332
|
+
blobs: {},
|
|
1333
|
+
};
|
|
1334
|
+
}
|
|
1335
|
+
currentTree = currentTree.trees[part];
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
// Add the blob at the final location
|
|
1339
|
+
const blobName = pathParts[pathParts.length - 1];
|
|
1340
|
+
if (blobName !== undefined) {
|
|
1341
|
+
currentTree.blobs[blobName] = content;
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
return tree;
|
|
1346
|
+
}
|