@fluidframework/map 2.0.0-rc.1.0.6 → 2.0.0-rc.2.0.1

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.
Files changed (132) hide show
  1. package/{.eslintrc.js → .eslintrc.cjs} +10 -1
  2. package/{.mocharc.js → .mocharc.cjs} +1 -1
  3. package/CHANGELOG.md +11 -0
  4. package/{api-extractor-esm.json → api-extractor-cjs.json} +5 -1
  5. package/api-extractor-lint.json +1 -1
  6. package/api-extractor.json +1 -1
  7. package/api-report/map.api.md +14 -57
  8. package/dist/directory.d.ts +10 -50
  9. package/dist/directory.d.ts.map +1 -1
  10. package/dist/directory.js +76 -164
  11. package/dist/directory.js.map +1 -1
  12. package/dist/index.d.ts +45 -4
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +43 -8
  15. package/dist/index.js.map +1 -1
  16. package/dist/interfaces.d.ts.map +1 -1
  17. package/dist/interfaces.js.map +1 -1
  18. package/dist/internalInterfaces.d.ts +2 -2
  19. package/dist/internalInterfaces.d.ts.map +1 -1
  20. package/dist/internalInterfaces.js.map +1 -1
  21. package/dist/localValues.d.ts +3 -5
  22. package/dist/localValues.d.ts.map +1 -1
  23. package/dist/localValues.js +9 -8
  24. package/dist/localValues.js.map +1 -1
  25. package/dist/map-alpha.d.ts +31 -116
  26. package/dist/map-beta.d.ts +24 -105
  27. package/dist/map-public.d.ts +24 -105
  28. package/dist/map-untrimmed.d.ts +31 -116
  29. package/dist/map.d.ts +4 -23
  30. package/dist/map.d.ts.map +1 -1
  31. package/dist/map.js +6 -29
  32. package/dist/map.js.map +1 -1
  33. package/dist/mapKernel.d.ts +3 -4
  34. package/dist/mapKernel.d.ts.map +1 -1
  35. package/dist/mapKernel.js +30 -35
  36. package/dist/mapKernel.js.map +1 -1
  37. package/dist/package.json +3 -0
  38. package/dist/packageVersion.d.ts +1 -1
  39. package/dist/packageVersion.js +1 -1
  40. package/dist/packageVersion.js.map +1 -1
  41. package/dist/tsdoc-metadata.json +1 -1
  42. package/lib/{directory.d.mts → directory.d.ts} +11 -51
  43. package/lib/directory.d.ts.map +1 -0
  44. package/lib/{directory.mjs → directory.js} +77 -165
  45. package/lib/directory.js.map +1 -0
  46. package/lib/index.d.ts +61 -0
  47. package/lib/index.d.ts.map +1 -0
  48. package/lib/index.js +55 -0
  49. package/lib/index.js.map +1 -0
  50. package/lib/{interfaces.d.mts → interfaces.d.ts} +1 -1
  51. package/lib/interfaces.d.ts.map +1 -0
  52. package/lib/{interfaces.mjs → interfaces.js} +1 -1
  53. package/lib/interfaces.js.map +1 -0
  54. package/lib/{internalInterfaces.d.mts → internalInterfaces.d.ts} +3 -3
  55. package/lib/internalInterfaces.d.ts.map +1 -0
  56. package/lib/{internalInterfaces.mjs → internalInterfaces.js} +1 -1
  57. package/lib/internalInterfaces.js.map +1 -0
  58. package/lib/{localValues.d.mts → localValues.d.ts} +4 -6
  59. package/lib/localValues.d.ts.map +1 -0
  60. package/lib/{localValues.mjs → localValues.js} +10 -9
  61. package/lib/localValues.js.map +1 -0
  62. package/lib/{map-alpha.d.mts → map-alpha.d.ts} +43 -116
  63. package/lib/{map-beta.d.mts → map-beta.d.ts} +36 -105
  64. package/lib/{map-public.d.mts → map-public.d.ts} +36 -105
  65. package/lib/{map-untrimmed.d.mts → map-untrimmed.d.ts} +43 -116
  66. package/lib/{map.d.mts → map.d.ts} +5 -24
  67. package/lib/map.d.ts.map +1 -0
  68. package/lib/{map.mjs → map.js} +5 -28
  69. package/lib/map.js.map +1 -0
  70. package/lib/{mapKernel.d.mts → mapKernel.d.ts} +4 -5
  71. package/lib/mapKernel.d.ts.map +1 -0
  72. package/lib/{mapKernel.mjs → mapKernel.js} +32 -37
  73. package/lib/mapKernel.js.map +1 -0
  74. package/lib/{packageVersion.d.mts → packageVersion.d.ts} +2 -2
  75. package/lib/packageVersion.d.ts.map +1 -0
  76. package/lib/{packageVersion.mjs → packageVersion.js} +2 -2
  77. package/lib/packageVersion.js.map +1 -0
  78. package/lib/test/memory/directory.spec.js +71 -0
  79. package/lib/test/memory/directory.spec.js.map +1 -0
  80. package/lib/test/memory/map.spec.js +71 -0
  81. package/lib/test/memory/map.spec.js.map +1 -0
  82. package/lib/test/mocha/directory.order.spec.js +422 -0
  83. package/lib/test/mocha/directory.order.spec.js.map +1 -0
  84. package/lib/test/mocha/directory.snapshot.spec.js +111 -0
  85. package/lib/test/mocha/directory.snapshot.spec.js.map +1 -0
  86. package/lib/test/mocha/directory.spec.js +1406 -0
  87. package/lib/test/mocha/directory.spec.js.map +1 -0
  88. package/lib/test/mocha/directoryEquivalenceUtils.js +36 -0
  89. package/lib/test/mocha/directoryEquivalenceUtils.js.map +1 -0
  90. package/lib/test/mocha/directoryFuzzTests.spec.js +337 -0
  91. package/lib/test/mocha/directoryFuzzTests.spec.js.map +1 -0
  92. package/lib/test/mocha/dirname.cjs +16 -0
  93. package/lib/test/mocha/dirname.cjs.map +1 -0
  94. package/lib/test/mocha/map.fuzz.spec.js +114 -0
  95. package/lib/test/mocha/map.fuzz.spec.js.map +1 -0
  96. package/lib/test/mocha/map.spec.js +685 -0
  97. package/lib/test/mocha/map.spec.js.map +1 -0
  98. package/lib/test/mocha/rebasing.spec.js +158 -0
  99. package/lib/test/mocha/rebasing.spec.js.map +1 -0
  100. package/lib/test/mocha/reconnection.spec.js +327 -0
  101. package/lib/test/mocha/reconnection.spec.js.map +1 -0
  102. package/lib/test/types/validateMapPrevious.generated.js +66 -0
  103. package/lib/test/types/validateMapPrevious.generated.js.map +1 -0
  104. package/package.json +55 -52
  105. package/src/directory.ts +122 -217
  106. package/src/index.ts +57 -4
  107. package/src/interfaces.ts +2 -2
  108. package/src/internalInterfaces.ts +2 -2
  109. package/src/localValues.ts +14 -9
  110. package/src/map.ts +7 -32
  111. package/src/mapKernel.ts +40 -42
  112. package/src/packageVersion.ts +1 -1
  113. package/tsconfig.cjs.json +7 -0
  114. package/tsconfig.json +2 -5
  115. package/lib/directory.d.mts.map +0 -1
  116. package/lib/directory.mjs.map +0 -1
  117. package/lib/index.d.mts +0 -9
  118. package/lib/index.d.mts.map +0 -1
  119. package/lib/index.mjs +0 -8
  120. package/lib/index.mjs.map +0 -1
  121. package/lib/interfaces.d.mts.map +0 -1
  122. package/lib/interfaces.mjs.map +0 -1
  123. package/lib/internalInterfaces.d.mts.map +0 -1
  124. package/lib/internalInterfaces.mjs.map +0 -1
  125. package/lib/localValues.d.mts.map +0 -1
  126. package/lib/localValues.mjs.map +0 -1
  127. package/lib/map.d.mts.map +0 -1
  128. package/lib/map.mjs.map +0 -1
  129. package/lib/mapKernel.d.mts.map +0 -1
  130. package/lib/mapKernel.mjs.map +0 -1
  131. package/lib/packageVersion.d.mts.map +0 -1
  132. package/lib/packageVersion.mjs.map +0 -1
@@ -0,0 +1,422 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ import { strict as assert } from "node:assert";
6
+ import { MockContainerRuntimeFactory, MockContainerRuntimeFactoryForReconnection, MockFluidDataStoreRuntime, MockSharedObjectServices, MockStorage, } from "@fluidframework/test-runtime-utils";
7
+ import { AttachState } from "@fluidframework/container-definitions";
8
+ import { DirectoryFactory, SharedDirectory, } from "../../directory.js";
9
+ function createConnectedDirectory(id, runtimeFactory) {
10
+ const dataStoreRuntime = new MockFluidDataStoreRuntime();
11
+ const containerRuntime = runtimeFactory.createContainerRuntime(dataStoreRuntime);
12
+ const services = {
13
+ deltaConnection: dataStoreRuntime.createDeltaConnection(),
14
+ objectStorage: new MockStorage(),
15
+ };
16
+ const directory = new SharedDirectory(id, dataStoreRuntime, DirectoryFactory.Attributes);
17
+ directory.connect(services);
18
+ return directory;
19
+ }
20
+ class TestSharedDirectory extends SharedDirectory {
21
+ testApplyStashedOp(content) {
22
+ this.lastMetadata = undefined;
23
+ this.applyStashedOp(content);
24
+ return this.lastMetadata;
25
+ }
26
+ submitLocalMessage(op, localOpMetadata) {
27
+ this.lastMetadata = localOpMetadata;
28
+ super.submitLocalMessage(op, localOpMetadata);
29
+ }
30
+ }
31
+ async function populate(directory, content) {
32
+ const storage = new MockSharedObjectServices({
33
+ header: JSON.stringify(content),
34
+ });
35
+ return directory.load(storage);
36
+ }
37
+ function assertDirectoryIterationOrder(directory, expectedDirNames) {
38
+ const actualDirNames = [];
39
+ for (const [subdirName, subdirObject] of directory.subdirectories()) {
40
+ actualDirNames.push(subdirName);
41
+ }
42
+ assert.deepEqual(actualDirNames, expectedDirNames);
43
+ }
44
+ describe("Directory Iteration Order", () => {
45
+ describe("Local state", () => {
46
+ let directory;
47
+ let dataStoreRuntime;
48
+ beforeEach("createDirectory", async () => {
49
+ dataStoreRuntime = new MockFluidDataStoreRuntime({ attachState: AttachState.Detached });
50
+ directory = new SharedDirectory("directory", dataStoreRuntime, DirectoryFactory.Attributes);
51
+ });
52
+ it("create subdirectories", () => {
53
+ directory.createSubDirectory("b");
54
+ directory.createSubDirectory("a");
55
+ directory.createSubDirectory("c");
56
+ assertDirectoryIterationOrder(directory, ["b", "a", "c"]);
57
+ });
58
+ it("create nested subdirectories", () => {
59
+ directory.createSubDirectory("c").createSubDirectory("c-a");
60
+ directory.createSubDirectory("a").createSubDirectory("a-b");
61
+ directory.createSubDirectory("a").createSubDirectory("a-a");
62
+ directory.createSubDirectory("b");
63
+ directory.createSubDirectory("c").createSubDirectory("c-c");
64
+ directory.createSubDirectory("a").createSubDirectory("a-c");
65
+ directory.createSubDirectory("c").createSubDirectory("c-b");
66
+ assertDirectoryIterationOrder(directory, ["c", "a", "b"]);
67
+ assert.notEqual(directory.getWorkingDirectory("/a"), undefined);
68
+ assertDirectoryIterationOrder(directory.getWorkingDirectory("/a"), [
69
+ "a-b",
70
+ "a-a",
71
+ "a-c",
72
+ ]);
73
+ assert.notEqual(directory.getWorkingDirectory("/b"), undefined);
74
+ assertDirectoryIterationOrder(directory.getWorkingDirectory("/b"), []);
75
+ assert.notEqual(directory.getWorkingDirectory("/c"), undefined);
76
+ assertDirectoryIterationOrder(directory.getWorkingDirectory("/c"), [
77
+ "c-a",
78
+ "c-c",
79
+ "c-b",
80
+ ]);
81
+ });
82
+ it("delete subdirectories", () => {
83
+ directory.createSubDirectory("c").createSubDirectory("c-a");
84
+ directory.createSubDirectory("a").createSubDirectory("a-b");
85
+ directory.createSubDirectory("a").createSubDirectory("a-a");
86
+ directory.createSubDirectory("b");
87
+ directory.createSubDirectory("c").createSubDirectory("c-c");
88
+ directory.createSubDirectory("a").createSubDirectory("a-c");
89
+ directory.createSubDirectory("c").createSubDirectory("c-b");
90
+ directory.deleteSubDirectory("a");
91
+ assertDirectoryIterationOrder(directory, ["c", "b"]);
92
+ directory.createSubDirectory("a");
93
+ assertDirectoryIterationOrder(directory, ["c", "b", "a"]);
94
+ directory.getWorkingDirectory("/c")?.createSubDirectory("c-d");
95
+ directory.getWorkingDirectory("/c")?.deleteSubDirectory("c-c");
96
+ assertDirectoryIterationOrder(directory.getWorkingDirectory("/c"), [
97
+ "c-a",
98
+ "c-b",
99
+ "c-d",
100
+ ]);
101
+ });
102
+ });
103
+ describe("Connected state", () => {
104
+ let containerRuntimeFactory;
105
+ let directory1;
106
+ let directory2;
107
+ beforeEach("createDirectories", async () => {
108
+ containerRuntimeFactory = new MockContainerRuntimeFactory();
109
+ // Create the first directory.
110
+ directory1 = createConnectedDirectory("directory1", containerRuntimeFactory);
111
+ // Create the second directory.
112
+ directory2 = createConnectedDirectory("directory2", containerRuntimeFactory);
113
+ });
114
+ it("Remote messages have no conflict with the local pending ops", () => {
115
+ directory1.createSubDirectory("a");
116
+ directory1.createSubDirectory("b").createSubDirectory("b-b");
117
+ directory2.createSubDirectory("c");
118
+ directory2.createSubDirectory("d");
119
+ directory1.deleteSubDirectory("a");
120
+ directory2.createSubDirectory("b").createSubDirectory("b-a");
121
+ containerRuntimeFactory.processSomeMessages(3);
122
+ assertDirectoryIterationOrder(directory1, ["b"]);
123
+ assertDirectoryIterationOrder(directory2, ["a", "b", "c", "d"]);
124
+ containerRuntimeFactory.processSomeMessages(2);
125
+ assertDirectoryIterationOrder(directory1, ["b", "c", "d"]);
126
+ assertDirectoryIterationOrder(directory2, ["a", "b", "c", "d"]);
127
+ containerRuntimeFactory.processAllMessages();
128
+ assertDirectoryIterationOrder(directory1, ["b", "c", "d"]);
129
+ assertDirectoryIterationOrder(directory2, ["b", "c", "d"]);
130
+ assert(directory1.getWorkingDirectory("b"));
131
+ assert(directory2.getWorkingDirectory("b"));
132
+ assertDirectoryIterationOrder(directory1.getWorkingDirectory("b"), [
133
+ "b-b",
134
+ "b-a",
135
+ ]);
136
+ assertDirectoryIterationOrder(directory2.getWorkingDirectory("b"), [
137
+ "b-b",
138
+ "b-a",
139
+ ]);
140
+ });
141
+ it("Remote messages have conflicts with the local pending ops", () => {
142
+ directory1.createSubDirectory("b");
143
+ directory2.createSubDirectory("a");
144
+ directory2.createSubDirectory("b");
145
+ containerRuntimeFactory.processSomeMessages(3);
146
+ assertDirectoryIterationOrder(directory1, ["b", "a"]);
147
+ assertDirectoryIterationOrder(directory2, ["b", "a"]);
148
+ directory1.createSubDirectory("d").createSubDirectory("d-b");
149
+ directory2.createSubDirectory("d").createSubDirectory("d-a");
150
+ containerRuntimeFactory.processSomeMessages(4);
151
+ assertDirectoryIterationOrder(directory1, ["b", "a", "d"]);
152
+ assertDirectoryIterationOrder(directory2, ["b", "a", "d"]);
153
+ assert.notEqual(directory1.getWorkingDirectory("/d"), undefined);
154
+ assertDirectoryIterationOrder(directory1.getWorkingDirectory("/d"), ["d-b", "d-a"]);
155
+ assert.notEqual(directory2.getWorkingDirectory("/d"), undefined);
156
+ assertDirectoryIterationOrder(directory2.getWorkingDirectory("/d"), ["d-b", "d-a"]);
157
+ directory1.deleteSubDirectory("d");
158
+ directory2.getWorkingDirectory("/d")?.createSubDirectory("d-c");
159
+ assertDirectoryIterationOrder(directory1, ["b", "a"]);
160
+ assertDirectoryIterationOrder(directory2, ["b", "a", "d"]);
161
+ assertDirectoryIterationOrder(directory2.getWorkingDirectory("/d"), ["d-b", "d-a", "d-c"]);
162
+ containerRuntimeFactory.processAllMessages();
163
+ assertDirectoryIterationOrder(directory1, ["b", "a"]);
164
+ assertDirectoryIterationOrder(directory2, ["b", "a"]);
165
+ });
166
+ });
167
+ describe("Serialization/Load", () => {
168
+ let directory1;
169
+ it("can be compatible with the old format summary", async () => {
170
+ const dataStoreRuntime = new MockFluidDataStoreRuntime({
171
+ attachState: AttachState.Detached,
172
+ });
173
+ directory1 = new SharedDirectory("directory", dataStoreRuntime, DirectoryFactory.Attributes);
174
+ await populate(directory1, {
175
+ storage: {
176
+ key1: {
177
+ type: "Plain",
178
+ value: "val1",
179
+ },
180
+ key2: {
181
+ type: "Plain",
182
+ value: "val2",
183
+ },
184
+ },
185
+ subdirectories: {
186
+ b: {
187
+ storage: {
188
+ testKey: {
189
+ type: "Plain",
190
+ value: "testValue",
191
+ },
192
+ testKey2: {
193
+ type: "Plain",
194
+ value: "testValue2",
195
+ },
196
+ },
197
+ },
198
+ c: {
199
+ storage: {
200
+ testKey3: {
201
+ type: "Plain",
202
+ value: "testValue3",
203
+ },
204
+ },
205
+ },
206
+ a: {
207
+ storage: {},
208
+ },
209
+ },
210
+ });
211
+ assertDirectoryIterationOrder(directory1, ["b", "c", "a"]);
212
+ });
213
+ it("can be compatible with the new format summary", async () => {
214
+ const dataStoreRuntime = new MockFluidDataStoreRuntime({
215
+ attachState: AttachState.Detached,
216
+ });
217
+ directory1 = new SharedDirectory("directory", dataStoreRuntime, DirectoryFactory.Attributes);
218
+ await populate(directory1, {
219
+ storage: {
220
+ key1: {
221
+ type: "Plain",
222
+ value: "val1",
223
+ },
224
+ key2: {
225
+ type: "Plain",
226
+ value: "val2",
227
+ },
228
+ },
229
+ subdirectories: {
230
+ b: {
231
+ storage: {
232
+ testKey: {
233
+ type: "Plain",
234
+ value: "testValue",
235
+ },
236
+ testKey2: {
237
+ type: "Plain",
238
+ value: "testValue2",
239
+ },
240
+ },
241
+ ci: {
242
+ csn: 4,
243
+ ccIds: ["client1"],
244
+ },
245
+ },
246
+ c: {
247
+ storage: {
248
+ testKey3: {
249
+ type: "Plain",
250
+ value: "testValue3",
251
+ },
252
+ },
253
+ subdirectories: {
254
+ c_b: {
255
+ storage: {},
256
+ ci: {
257
+ csn: 5,
258
+ ccIds: ["client1"],
259
+ },
260
+ },
261
+ c_a: {
262
+ storage: {},
263
+ ci: {
264
+ csn: 6,
265
+ ccIds: ["client1"],
266
+ },
267
+ },
268
+ },
269
+ ci: {
270
+ csn: 2,
271
+ ccIds: ["client2"],
272
+ ccsn: 1,
273
+ },
274
+ },
275
+ a: {
276
+ storage: {},
277
+ ci: {
278
+ csn: 4,
279
+ ccIds: ["client2"],
280
+ },
281
+ },
282
+ },
283
+ ci: {
284
+ csn: 1,
285
+ ccIds: ["client1", "client2"],
286
+ },
287
+ });
288
+ assertDirectoryIterationOrder(directory1, ["c", "b", "a"]);
289
+ assert(directory1.getWorkingDirectory("/c"));
290
+ assertDirectoryIterationOrder(directory1.getWorkingDirectory("/c"), ["c_b", "c_a"]);
291
+ });
292
+ it("serialize the contents, load it into another directory and maintain the order", async () => {
293
+ directory1 = new SharedDirectory("dir1", new MockFluidDataStoreRuntime(), DirectoryFactory.Attributes);
294
+ directory1.createSubDirectory("c");
295
+ directory1.createSubDirectory("b");
296
+ directory1.createSubDirectory("a");
297
+ const containerRuntimeFactory = new MockContainerRuntimeFactory();
298
+ const dataStoreRuntime = new MockFluidDataStoreRuntime();
299
+ const containerRuntime = containerRuntimeFactory.createContainerRuntime(dataStoreRuntime);
300
+ const services = MockSharedObjectServices.createFromSummary(directory1.getAttachSummary().summary);
301
+ services.deltaConnection = dataStoreRuntime.createDeltaConnection();
302
+ const directory2 = new SharedDirectory("map2", dataStoreRuntime, DirectoryFactory.Attributes);
303
+ await directory2.load(services);
304
+ assertDirectoryIterationOrder(directory2, ["c", "b", "a"]);
305
+ });
306
+ it("can be compatible with the detached scenario", async () => {
307
+ // It is to reproduce the regression bug causing the corruption of the summarization, indicated by 0x85c
308
+ // https://dev.azure.com/fluidframework/internal/_workitems/edit/7013
309
+ const runtimeFactory = new MockContainerRuntimeFactory();
310
+ const dataStoreRuntime = new MockFluidDataStoreRuntime();
311
+ runtimeFactory.createContainerRuntime(dataStoreRuntime);
312
+ const factory = SharedDirectory.getFactory();
313
+ const summaryContent = '{"blobs":[],"content":{"ci":{"csn":0,"ccIds":[]},"subdirectories":{"detached1":{"ci":{"csn":0,"ccIds":["97cd0b77-34b1-46a8-bbe2-5fbefb3e014b"]}},"detached2":{"ci":{"csn":0,"ccIds":["97cd0b77-34b1-46a8-bbe2-5fbefb3e014b"]}},"detached3":{"ci":{"csn":-1,"ccIds":["97cd0b77-34b1-46a8-bbe2-5fbefb3e014b"]}}}}}';
314
+ const summary = {
315
+ type: 1,
316
+ tree: {
317
+ header: {
318
+ type: 2,
319
+ content: summaryContent,
320
+ },
321
+ },
322
+ };
323
+ const directory = await factory.load(dataStoreRuntime, "A", {
324
+ deltaConnection: dataStoreRuntime.createDeltaConnection(),
325
+ objectStorage: MockStorage.createFromSummary(summary),
326
+ }, factory.attributes);
327
+ await directory.summarize();
328
+ });
329
+ });
330
+ describe("Reconnection", () => {
331
+ let containerRuntimeFactory;
332
+ let containerRuntime1;
333
+ let containerRuntime2;
334
+ let directory1;
335
+ let directory2;
336
+ beforeEach("createDirectories", async () => {
337
+ containerRuntimeFactory = new MockContainerRuntimeFactoryForReconnection();
338
+ // Create the first SharedDirectory
339
+ const dataStoreRuntime1 = new MockFluidDataStoreRuntime();
340
+ containerRuntime1 = containerRuntimeFactory.createContainerRuntime(dataStoreRuntime1);
341
+ const services1 = {
342
+ deltaConnection: dataStoreRuntime1.createDeltaConnection(),
343
+ objectStorage: new MockStorage(),
344
+ };
345
+ directory1 = new SharedDirectory("dir1", dataStoreRuntime1, DirectoryFactory.Attributes);
346
+ directory1.connect(services1);
347
+ // Create the second SharedDirectory
348
+ const dataStoreRuntime2 = new MockFluidDataStoreRuntime();
349
+ containerRuntime2 = containerRuntimeFactory.createContainerRuntime(dataStoreRuntime2);
350
+ const services2 = {
351
+ deltaConnection: dataStoreRuntime2.createDeltaConnection(),
352
+ objectStorage: new MockStorage(),
353
+ };
354
+ directory2 = new SharedDirectory("dir1", dataStoreRuntime2, DirectoryFactory.Attributes);
355
+ directory2.connect(services2);
356
+ });
357
+ it("Can resend unacked ops on reconnection and impact the order", async () => {
358
+ directory1.createSubDirectory("a");
359
+ directory1.createSubDirectory("b");
360
+ directory2.createSubDirectory("c");
361
+ directory2.createSubDirectory("b");
362
+ // Disconnect and reconnect the first client
363
+ containerRuntime1.connected = false;
364
+ containerRuntime1.connected = true;
365
+ containerRuntimeFactory.processAllMessages();
366
+ assertDirectoryIterationOrder(directory1, ["c", "b", "a"]);
367
+ assertDirectoryIterationOrder(directory2, ["c", "b", "a"]);
368
+ });
369
+ it("can maintain order when a client disconnects in the meanwhile", async () => {
370
+ directory1.createSubDirectory("c");
371
+ containerRuntimeFactory.processAllMessages();
372
+ // Disconnect the first client
373
+ containerRuntime1.connected = false;
374
+ directory1.createSubDirectory("a");
375
+ directory2.createSubDirectory("d");
376
+ directory2.createSubDirectory("b");
377
+ // Reconnect the first client.
378
+ containerRuntime1.connected = true;
379
+ assertDirectoryIterationOrder(directory1, ["c", "a"]);
380
+ assertDirectoryIterationOrder(directory2, ["c", "d", "b"]);
381
+ containerRuntimeFactory.processAllMessages();
382
+ assertDirectoryIterationOrder(directory1, ["c", "d", "b", "a"]);
383
+ assertDirectoryIterationOrder(directory2, ["c", "d", "b", "a"]);
384
+ });
385
+ });
386
+ describe("Op Processing", () => {
387
+ let directory;
388
+ beforeEach("createDirectory", async () => {
389
+ const dataStoreRuntime = new MockFluidDataStoreRuntime();
390
+ directory = new TestSharedDirectory("dir1", dataStoreRuntime, DirectoryFactory.Attributes);
391
+ });
392
+ it("applyStashedOp", async () => {
393
+ const op1 = {
394
+ type: "createSubDirectory",
395
+ path: "./",
396
+ subdirName: "c",
397
+ };
398
+ const op2 = {
399
+ type: "createSubDirectory",
400
+ path: "./",
401
+ subdirName: "b",
402
+ };
403
+ const op3 = {
404
+ type: "createSubDirectory",
405
+ path: "./",
406
+ subdirName: "a",
407
+ };
408
+ const op4 = {
409
+ type: "deleteSubDirectory",
410
+ path: "./",
411
+ subdirName: "b",
412
+ };
413
+ directory.testApplyStashedOp(op1);
414
+ directory.testApplyStashedOp(op2);
415
+ directory.testApplyStashedOp(op3);
416
+ assertDirectoryIterationOrder(directory, ["c", "b", "a"]);
417
+ directory.testApplyStashedOp(op4);
418
+ assertDirectoryIterationOrder(directory, ["c", "a"]);
419
+ });
420
+ });
421
+ });
422
+ //# sourceMappingURL=directory.order.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory.order.spec.js","sourceRoot":"","sources":["../../../src/test/mocha/directory.order.spec.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { strict as assert } from \"node:assert\";\nimport {\n\tMockContainerRuntimeFactory,\n\tMockContainerRuntimeFactoryForReconnection,\n\tMockContainerRuntimeForReconnection,\n\tMockFluidDataStoreRuntime,\n\tMockSharedObjectServices,\n\tMockStorage,\n} from \"@fluidframework/test-runtime-utils\";\nimport { ISummaryTree } from \"@fluidframework/protocol-definitions\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport {\n\tDirectoryFactory,\n\tDirectoryLocalOpMetadata,\n\tIDirectoryOperation,\n\tSharedDirectory,\n} from \"../../directory.js\";\nimport { ISharedDirectory } from \"../../interfaces.js\";\n\nfunction createConnectedDirectory(\n\tid: string,\n\truntimeFactory: MockContainerRuntimeFactory,\n): SharedDirectory {\n\tconst dataStoreRuntime = new MockFluidDataStoreRuntime();\n\tconst containerRuntime = runtimeFactory.createContainerRuntime(dataStoreRuntime);\n\tconst services = {\n\t\tdeltaConnection: dataStoreRuntime.createDeltaConnection(),\n\t\tobjectStorage: new MockStorage(),\n\t};\n\tconst directory = new SharedDirectory(id, dataStoreRuntime, DirectoryFactory.Attributes);\n\tdirectory.connect(services);\n\treturn directory;\n}\n\nclass TestSharedDirectory extends SharedDirectory {\n\tprivate lastMetadata?: DirectoryLocalOpMetadata;\n\tpublic testApplyStashedOp(content: IDirectoryOperation): DirectoryLocalOpMetadata | undefined {\n\t\tthis.lastMetadata = undefined;\n\t\tthis.applyStashedOp(content);\n\t\treturn this.lastMetadata;\n\t}\n\n\tpublic submitLocalMessage(op: IDirectoryOperation, localOpMetadata: unknown): void {\n\t\tthis.lastMetadata = localOpMetadata as DirectoryLocalOpMetadata;\n\t\tsuper.submitLocalMessage(op, localOpMetadata);\n\t}\n}\n\nasync function populate(directory: SharedDirectory, content: unknown): Promise<void> {\n\tconst storage = new MockSharedObjectServices({\n\t\theader: JSON.stringify(content),\n\t});\n\treturn directory.load(storage);\n}\n\nfunction assertDirectoryIterationOrder(\n\tdirectory: ISharedDirectory,\n\texpectedDirNames: string[],\n): void {\n\tconst actualDirNames: string[] = [];\n\tfor (const [subdirName, subdirObject] of directory.subdirectories()) {\n\t\tactualDirNames.push(subdirName);\n\t}\n\tassert.deepEqual(actualDirNames, expectedDirNames);\n}\n\ndescribe(\"Directory Iteration Order\", () => {\n\tdescribe(\"Local state\", () => {\n\t\tlet directory: SharedDirectory;\n\t\tlet dataStoreRuntime: MockFluidDataStoreRuntime;\n\n\t\tbeforeEach(\"createDirectory\", async () => {\n\t\t\tdataStoreRuntime = new MockFluidDataStoreRuntime({ attachState: AttachState.Detached });\n\t\t\tdirectory = new SharedDirectory(\n\t\t\t\t\"directory\",\n\t\t\t\tdataStoreRuntime,\n\t\t\t\tDirectoryFactory.Attributes,\n\t\t\t);\n\t\t});\n\n\t\tit(\"create subdirectories\", () => {\n\t\t\tdirectory.createSubDirectory(\"b\");\n\t\t\tdirectory.createSubDirectory(\"a\");\n\t\t\tdirectory.createSubDirectory(\"c\");\n\n\t\t\tassertDirectoryIterationOrder(directory, [\"b\", \"a\", \"c\"]);\n\t\t});\n\n\t\tit(\"create nested subdirectories\", () => {\n\t\t\tdirectory.createSubDirectory(\"c\").createSubDirectory(\"c-a\");\n\t\t\tdirectory.createSubDirectory(\"a\").createSubDirectory(\"a-b\");\n\t\t\tdirectory.createSubDirectory(\"a\").createSubDirectory(\"a-a\");\n\t\t\tdirectory.createSubDirectory(\"b\");\n\t\t\tdirectory.createSubDirectory(\"c\").createSubDirectory(\"c-c\");\n\t\t\tdirectory.createSubDirectory(\"a\").createSubDirectory(\"a-c\");\n\t\t\tdirectory.createSubDirectory(\"c\").createSubDirectory(\"c-b\");\n\n\t\t\tassertDirectoryIterationOrder(directory, [\"c\", \"a\", \"b\"]);\n\t\t\tassert.notEqual(directory.getWorkingDirectory(\"/a\"), undefined);\n\t\t\tassertDirectoryIterationOrder(directory.getWorkingDirectory(\"/a\") as ISharedDirectory, [\n\t\t\t\t\"a-b\",\n\t\t\t\t\"a-a\",\n\t\t\t\t\"a-c\",\n\t\t\t]);\n\t\t\tassert.notEqual(directory.getWorkingDirectory(\"/b\"), undefined);\n\t\t\tassertDirectoryIterationOrder(\n\t\t\t\tdirectory.getWorkingDirectory(\"/b\") as ISharedDirectory,\n\t\t\t\t[],\n\t\t\t);\n\t\t\tassert.notEqual(directory.getWorkingDirectory(\"/c\"), undefined);\n\t\t\tassertDirectoryIterationOrder(directory.getWorkingDirectory(\"/c\") as ISharedDirectory, [\n\t\t\t\t\"c-a\",\n\t\t\t\t\"c-c\",\n\t\t\t\t\"c-b\",\n\t\t\t]);\n\t\t});\n\n\t\tit(\"delete subdirectories\", () => {\n\t\t\tdirectory.createSubDirectory(\"c\").createSubDirectory(\"c-a\");\n\t\t\tdirectory.createSubDirectory(\"a\").createSubDirectory(\"a-b\");\n\t\t\tdirectory.createSubDirectory(\"a\").createSubDirectory(\"a-a\");\n\t\t\tdirectory.createSubDirectory(\"b\");\n\t\t\tdirectory.createSubDirectory(\"c\").createSubDirectory(\"c-c\");\n\t\t\tdirectory.createSubDirectory(\"a\").createSubDirectory(\"a-c\");\n\t\t\tdirectory.createSubDirectory(\"c\").createSubDirectory(\"c-b\");\n\n\t\t\tdirectory.deleteSubDirectory(\"a\");\n\t\t\tassertDirectoryIterationOrder(directory, [\"c\", \"b\"]);\n\n\t\t\tdirectory.createSubDirectory(\"a\");\n\t\t\tassertDirectoryIterationOrder(directory, [\"c\", \"b\", \"a\"]);\n\n\t\t\tdirectory.getWorkingDirectory(\"/c\")?.createSubDirectory(\"c-d\");\n\t\t\tdirectory.getWorkingDirectory(\"/c\")?.deleteSubDirectory(\"c-c\");\n\n\t\t\tassertDirectoryIterationOrder(directory.getWorkingDirectory(\"/c\") as ISharedDirectory, [\n\t\t\t\t\"c-a\",\n\t\t\t\t\"c-b\",\n\t\t\t\t\"c-d\",\n\t\t\t]);\n\t\t});\n\t});\n\n\tdescribe(\"Connected state\", () => {\n\t\tlet containerRuntimeFactory: MockContainerRuntimeFactory;\n\t\tlet directory1: SharedDirectory;\n\t\tlet directory2: SharedDirectory;\n\n\t\tbeforeEach(\"createDirectories\", async () => {\n\t\t\tcontainerRuntimeFactory = new MockContainerRuntimeFactory();\n\t\t\t// Create the first directory.\n\t\t\tdirectory1 = createConnectedDirectory(\"directory1\", containerRuntimeFactory);\n\t\t\t// Create the second directory.\n\t\t\tdirectory2 = createConnectedDirectory(\"directory2\", containerRuntimeFactory);\n\t\t});\n\n\t\tit(\"Remote messages have no conflict with the local pending ops\", () => {\n\t\t\tdirectory1.createSubDirectory(\"a\");\n\t\t\tdirectory1.createSubDirectory(\"b\").createSubDirectory(\"b-b\");\n\t\t\tdirectory2.createSubDirectory(\"c\");\n\t\t\tdirectory2.createSubDirectory(\"d\");\n\t\t\tdirectory1.deleteSubDirectory(\"a\");\n\t\t\tdirectory2.createSubDirectory(\"b\").createSubDirectory(\"b-a\");\n\n\t\t\tcontainerRuntimeFactory.processSomeMessages(3);\n\t\t\tassertDirectoryIterationOrder(directory1, [\"b\"]);\n\t\t\tassertDirectoryIterationOrder(directory2, [\"a\", \"b\", \"c\", \"d\"]);\n\n\t\t\tcontainerRuntimeFactory.processSomeMessages(2);\n\t\t\tassertDirectoryIterationOrder(directory1, [\"b\", \"c\", \"d\"]);\n\t\t\tassertDirectoryIterationOrder(directory2, [\"a\", \"b\", \"c\", \"d\"]);\n\n\t\t\tcontainerRuntimeFactory.processAllMessages();\n\t\t\tassertDirectoryIterationOrder(directory1, [\"b\", \"c\", \"d\"]);\n\t\t\tassertDirectoryIterationOrder(directory2, [\"b\", \"c\", \"d\"]);\n\n\t\t\tassert(directory1.getWorkingDirectory(\"b\"));\n\t\t\tassert(directory2.getWorkingDirectory(\"b\"));\n\t\t\tassertDirectoryIterationOrder(directory1.getWorkingDirectory(\"b\") as ISharedDirectory, [\n\t\t\t\t\"b-b\",\n\t\t\t\t\"b-a\",\n\t\t\t]);\n\t\t\tassertDirectoryIterationOrder(directory2.getWorkingDirectory(\"b\") as ISharedDirectory, [\n\t\t\t\t\"b-b\",\n\t\t\t\t\"b-a\",\n\t\t\t]);\n\t\t});\n\n\t\tit(\"Remote messages have conflicts with the local pending ops\", () => {\n\t\t\tdirectory1.createSubDirectory(\"b\");\n\t\t\tdirectory2.createSubDirectory(\"a\");\n\t\t\tdirectory2.createSubDirectory(\"b\");\n\n\t\t\tcontainerRuntimeFactory.processSomeMessages(3);\n\t\t\tassertDirectoryIterationOrder(directory1, [\"b\", \"a\"]);\n\t\t\tassertDirectoryIterationOrder(directory2, [\"b\", \"a\"]);\n\n\t\t\tdirectory1.createSubDirectory(\"d\").createSubDirectory(\"d-b\");\n\t\t\tdirectory2.createSubDirectory(\"d\").createSubDirectory(\"d-a\");\n\n\t\t\tcontainerRuntimeFactory.processSomeMessages(4);\n\t\t\tassertDirectoryIterationOrder(directory1, [\"b\", \"a\", \"d\"]);\n\t\t\tassertDirectoryIterationOrder(directory2, [\"b\", \"a\", \"d\"]);\n\n\t\t\tassert.notEqual(directory1.getWorkingDirectory(\"/d\"), undefined);\n\t\t\tassertDirectoryIterationOrder(\n\t\t\t\tdirectory1.getWorkingDirectory(\"/d\") as ISharedDirectory,\n\t\t\t\t[\"d-b\", \"d-a\"],\n\t\t\t);\n\n\t\t\tassert.notEqual(directory2.getWorkingDirectory(\"/d\"), undefined);\n\t\t\tassertDirectoryIterationOrder(\n\t\t\t\tdirectory2.getWorkingDirectory(\"/d\") as ISharedDirectory,\n\t\t\t\t[\"d-b\", \"d-a\"],\n\t\t\t);\n\n\t\t\tdirectory1.deleteSubDirectory(\"d\");\n\t\t\tdirectory2.getWorkingDirectory(\"/d\")?.createSubDirectory(\"d-c\");\n\n\t\t\tassertDirectoryIterationOrder(directory1, [\"b\", \"a\"]);\n\t\t\tassertDirectoryIterationOrder(directory2, [\"b\", \"a\", \"d\"]);\n\t\t\tassertDirectoryIterationOrder(\n\t\t\t\tdirectory2.getWorkingDirectory(\"/d\") as ISharedDirectory,\n\t\t\t\t[\"d-b\", \"d-a\", \"d-c\"],\n\t\t\t);\n\n\t\t\tcontainerRuntimeFactory.processAllMessages();\n\t\t\tassertDirectoryIterationOrder(directory1, [\"b\", \"a\"]);\n\t\t\tassertDirectoryIterationOrder(directory2, [\"b\", \"a\"]);\n\t\t});\n\t});\n\n\tdescribe(\"Serialization/Load\", () => {\n\t\tlet directory1: SharedDirectory;\n\n\t\tit(\"can be compatible with the old format summary\", async () => {\n\t\t\tconst dataStoreRuntime = new MockFluidDataStoreRuntime({\n\t\t\t\tattachState: AttachState.Detached,\n\t\t\t});\n\t\t\tdirectory1 = new SharedDirectory(\n\t\t\t\t\"directory\",\n\t\t\t\tdataStoreRuntime,\n\t\t\t\tDirectoryFactory.Attributes,\n\t\t\t);\n\n\t\t\tawait populate(directory1, {\n\t\t\t\tstorage: {\n\t\t\t\t\tkey1: {\n\t\t\t\t\t\ttype: \"Plain\",\n\t\t\t\t\t\tvalue: \"val1\",\n\t\t\t\t\t},\n\t\t\t\t\tkey2: {\n\t\t\t\t\t\ttype: \"Plain\",\n\t\t\t\t\t\tvalue: \"val2\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tsubdirectories: {\n\t\t\t\t\tb: {\n\t\t\t\t\t\tstorage: {\n\t\t\t\t\t\t\ttestKey: {\n\t\t\t\t\t\t\t\ttype: \"Plain\",\n\t\t\t\t\t\t\t\tvalue: \"testValue\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\ttestKey2: {\n\t\t\t\t\t\t\t\ttype: \"Plain\",\n\t\t\t\t\t\t\t\tvalue: \"testValue2\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tc: {\n\t\t\t\t\t\tstorage: {\n\t\t\t\t\t\t\ttestKey3: {\n\t\t\t\t\t\t\t\ttype: \"Plain\",\n\t\t\t\t\t\t\t\tvalue: \"testValue3\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\ta: {\n\t\t\t\t\t\tstorage: {},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tassertDirectoryIterationOrder(directory1, [\"b\", \"c\", \"a\"]);\n\t\t});\n\n\t\tit(\"can be compatible with the new format summary\", async () => {\n\t\t\tconst dataStoreRuntime = new MockFluidDataStoreRuntime({\n\t\t\t\tattachState: AttachState.Detached,\n\t\t\t});\n\t\t\tdirectory1 = new SharedDirectory(\n\t\t\t\t\"directory\",\n\t\t\t\tdataStoreRuntime,\n\t\t\t\tDirectoryFactory.Attributes,\n\t\t\t);\n\n\t\t\tawait populate(directory1, {\n\t\t\t\tstorage: {\n\t\t\t\t\tkey1: {\n\t\t\t\t\t\ttype: \"Plain\",\n\t\t\t\t\t\tvalue: \"val1\",\n\t\t\t\t\t},\n\t\t\t\t\tkey2: {\n\t\t\t\t\t\ttype: \"Plain\",\n\t\t\t\t\t\tvalue: \"val2\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tsubdirectories: {\n\t\t\t\t\tb: {\n\t\t\t\t\t\tstorage: {\n\t\t\t\t\t\t\ttestKey: {\n\t\t\t\t\t\t\t\ttype: \"Plain\",\n\t\t\t\t\t\t\t\tvalue: \"testValue\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\ttestKey2: {\n\t\t\t\t\t\t\t\ttype: \"Plain\",\n\t\t\t\t\t\t\t\tvalue: \"testValue2\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tci: {\n\t\t\t\t\t\t\tcsn: 4,\n\t\t\t\t\t\t\tccIds: [\"client1\"],\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tc: {\n\t\t\t\t\t\tstorage: {\n\t\t\t\t\t\t\ttestKey3: {\n\t\t\t\t\t\t\t\ttype: \"Plain\",\n\t\t\t\t\t\t\t\tvalue: \"testValue3\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsubdirectories: {\n\t\t\t\t\t\t\tc_b: {\n\t\t\t\t\t\t\t\tstorage: {},\n\t\t\t\t\t\t\t\tci: {\n\t\t\t\t\t\t\t\t\tcsn: 5,\n\t\t\t\t\t\t\t\t\tccIds: [\"client1\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tc_a: {\n\t\t\t\t\t\t\t\tstorage: {},\n\t\t\t\t\t\t\t\tci: {\n\t\t\t\t\t\t\t\t\tcsn: 6,\n\t\t\t\t\t\t\t\t\tccIds: [\"client1\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tci: {\n\t\t\t\t\t\t\tcsn: 2,\n\t\t\t\t\t\t\tccIds: [\"client2\"],\n\t\t\t\t\t\t\tccsn: 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\ta: {\n\t\t\t\t\t\tstorage: {},\n\t\t\t\t\t\tci: {\n\t\t\t\t\t\t\tcsn: 4,\n\t\t\t\t\t\t\tccIds: [\"client2\"],\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tci: {\n\t\t\t\t\tcsn: 1,\n\t\t\t\t\tccIds: [\"client1\", \"client2\"],\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tassertDirectoryIterationOrder(directory1, [\"c\", \"b\", \"a\"]);\n\t\t\tassert(directory1.getWorkingDirectory(\"/c\"));\n\t\t\tassertDirectoryIterationOrder(\n\t\t\t\tdirectory1.getWorkingDirectory(\"/c\") as ISharedDirectory,\n\t\t\t\t[\"c_b\", \"c_a\"],\n\t\t\t);\n\t\t});\n\n\t\tit(\"serialize the contents, load it into another directory and maintain the order\", async () => {\n\t\t\tdirectory1 = new SharedDirectory(\n\t\t\t\t\"dir1\",\n\t\t\t\tnew MockFluidDataStoreRuntime(),\n\t\t\t\tDirectoryFactory.Attributes,\n\t\t\t);\n\t\t\tdirectory1.createSubDirectory(\"c\");\n\t\t\tdirectory1.createSubDirectory(\"b\");\n\t\t\tdirectory1.createSubDirectory(\"a\");\n\n\t\t\tconst containerRuntimeFactory = new MockContainerRuntimeFactory();\n\t\t\tconst dataStoreRuntime = new MockFluidDataStoreRuntime();\n\t\t\tconst containerRuntime =\n\t\t\t\tcontainerRuntimeFactory.createContainerRuntime(dataStoreRuntime);\n\t\t\tconst services = MockSharedObjectServices.createFromSummary(\n\t\t\t\tdirectory1.getAttachSummary().summary,\n\t\t\t);\n\t\t\tservices.deltaConnection = dataStoreRuntime.createDeltaConnection();\n\n\t\t\tconst directory2 = new SharedDirectory(\n\t\t\t\t\"map2\",\n\t\t\t\tdataStoreRuntime,\n\t\t\t\tDirectoryFactory.Attributes,\n\t\t\t);\n\t\t\tawait directory2.load(services);\n\n\t\t\tassertDirectoryIterationOrder(directory2, [\"c\", \"b\", \"a\"]);\n\t\t});\n\n\t\tit(\"can be compatible with the detached scenario\", async () => {\n\t\t\t// It is to reproduce the regression bug causing the corruption of the summarization, indicated by 0x85c\n\t\t\t// https://dev.azure.com/fluidframework/internal/_workitems/edit/7013\n\t\t\tconst runtimeFactory = new MockContainerRuntimeFactory();\n\t\t\tconst dataStoreRuntime = new MockFluidDataStoreRuntime();\n\t\t\truntimeFactory.createContainerRuntime(dataStoreRuntime);\n\t\t\tconst factory = SharedDirectory.getFactory();\n\n\t\t\tconst summaryContent =\n\t\t\t\t'{\"blobs\":[],\"content\":{\"ci\":{\"csn\":0,\"ccIds\":[]},\"subdirectories\":{\"detached1\":{\"ci\":{\"csn\":0,\"ccIds\":[\"97cd0b77-34b1-46a8-bbe2-5fbefb3e014b\"]}},\"detached2\":{\"ci\":{\"csn\":0,\"ccIds\":[\"97cd0b77-34b1-46a8-bbe2-5fbefb3e014b\"]}},\"detached3\":{\"ci\":{\"csn\":-1,\"ccIds\":[\"97cd0b77-34b1-46a8-bbe2-5fbefb3e014b\"]}}}}}';\n\t\t\tconst summary: ISummaryTree = {\n\t\t\t\ttype: 1,\n\t\t\t\ttree: {\n\t\t\t\t\theader: {\n\t\t\t\t\t\ttype: 2,\n\t\t\t\t\t\tcontent: summaryContent,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\n\t\t\tconst directory = await factory.load(\n\t\t\t\tdataStoreRuntime,\n\t\t\t\t\"A\",\n\t\t\t\t{\n\t\t\t\t\tdeltaConnection: dataStoreRuntime.createDeltaConnection(),\n\t\t\t\t\tobjectStorage: MockStorage.createFromSummary(summary),\n\t\t\t\t},\n\t\t\t\tfactory.attributes,\n\t\t\t);\n\n\t\t\tawait directory.summarize();\n\t\t});\n\t});\n\n\tdescribe(\"Reconnection\", () => {\n\t\tlet containerRuntimeFactory: MockContainerRuntimeFactoryForReconnection;\n\t\tlet containerRuntime1: MockContainerRuntimeForReconnection;\n\t\tlet containerRuntime2: MockContainerRuntimeForReconnection;\n\t\tlet directory1: SharedDirectory;\n\t\tlet directory2: SharedDirectory;\n\n\t\tbeforeEach(\"createDirectories\", async () => {\n\t\t\tcontainerRuntimeFactory = new MockContainerRuntimeFactoryForReconnection();\n\n\t\t\t// Create the first SharedDirectory\n\t\t\tconst dataStoreRuntime1 = new MockFluidDataStoreRuntime();\n\t\t\tcontainerRuntime1 = containerRuntimeFactory.createContainerRuntime(dataStoreRuntime1);\n\t\t\tconst services1 = {\n\t\t\t\tdeltaConnection: dataStoreRuntime1.createDeltaConnection(),\n\t\t\t\tobjectStorage: new MockStorage(),\n\t\t\t};\n\t\t\tdirectory1 = new SharedDirectory(\n\t\t\t\t\"dir1\",\n\t\t\t\tdataStoreRuntime1,\n\t\t\t\tDirectoryFactory.Attributes,\n\t\t\t);\n\t\t\tdirectory1.connect(services1);\n\n\t\t\t// Create the second SharedDirectory\n\t\t\tconst dataStoreRuntime2 = new MockFluidDataStoreRuntime();\n\t\t\tcontainerRuntime2 = containerRuntimeFactory.createContainerRuntime(dataStoreRuntime2);\n\t\t\tconst services2 = {\n\t\t\t\tdeltaConnection: dataStoreRuntime2.createDeltaConnection(),\n\t\t\t\tobjectStorage: new MockStorage(),\n\t\t\t};\n\t\t\tdirectory2 = new SharedDirectory(\n\t\t\t\t\"dir1\",\n\t\t\t\tdataStoreRuntime2,\n\t\t\t\tDirectoryFactory.Attributes,\n\t\t\t);\n\t\t\tdirectory2.connect(services2);\n\t\t});\n\n\t\tit(\"Can resend unacked ops on reconnection and impact the order\", async () => {\n\t\t\tdirectory1.createSubDirectory(\"a\");\n\t\t\tdirectory1.createSubDirectory(\"b\");\n\t\t\tdirectory2.createSubDirectory(\"c\");\n\t\t\tdirectory2.createSubDirectory(\"b\");\n\n\t\t\t// Disconnect and reconnect the first client\n\t\t\tcontainerRuntime1.connected = false;\n\t\t\tcontainerRuntime1.connected = true;\n\n\t\t\tcontainerRuntimeFactory.processAllMessages();\n\n\t\t\tassertDirectoryIterationOrder(directory1, [\"c\", \"b\", \"a\"]);\n\t\t\tassertDirectoryIterationOrder(directory2, [\"c\", \"b\", \"a\"]);\n\t\t});\n\n\t\tit(\"can maintain order when a client disconnects in the meanwhile\", async () => {\n\t\t\tdirectory1.createSubDirectory(\"c\");\n\t\t\tcontainerRuntimeFactory.processAllMessages();\n\n\t\t\t// Disconnect the first client\n\t\t\tcontainerRuntime1.connected = false;\n\n\t\t\tdirectory1.createSubDirectory(\"a\");\n\t\t\tdirectory2.createSubDirectory(\"d\");\n\t\t\tdirectory2.createSubDirectory(\"b\");\n\n\t\t\t// Reconnect the first client.\n\t\t\tcontainerRuntime1.connected = true;\n\n\t\t\tassertDirectoryIterationOrder(directory1, [\"c\", \"a\"]);\n\t\t\tassertDirectoryIterationOrder(directory2, [\"c\", \"d\", \"b\"]);\n\n\t\t\tcontainerRuntimeFactory.processAllMessages();\n\n\t\t\tassertDirectoryIterationOrder(directory1, [\"c\", \"d\", \"b\", \"a\"]);\n\t\t\tassertDirectoryIterationOrder(directory2, [\"c\", \"d\", \"b\", \"a\"]);\n\t\t});\n\t});\n\n\tdescribe(\"Op Processing\", () => {\n\t\tlet directory: TestSharedDirectory;\n\n\t\tbeforeEach(\"createDirectory\", async () => {\n\t\t\tconst dataStoreRuntime = new MockFluidDataStoreRuntime();\n\t\t\tdirectory = new TestSharedDirectory(\n\t\t\t\t\"dir1\",\n\t\t\t\tdataStoreRuntime,\n\t\t\t\tDirectoryFactory.Attributes,\n\t\t\t);\n\t\t});\n\n\t\tit(\"applyStashedOp\", async () => {\n\t\t\tconst op1: IDirectoryOperation = {\n\t\t\t\ttype: \"createSubDirectory\",\n\t\t\t\tpath: \"./\",\n\t\t\t\tsubdirName: \"c\",\n\t\t\t};\n\t\t\tconst op2: IDirectoryOperation = {\n\t\t\t\ttype: \"createSubDirectory\",\n\t\t\t\tpath: \"./\",\n\t\t\t\tsubdirName: \"b\",\n\t\t\t};\n\t\t\tconst op3: IDirectoryOperation = {\n\t\t\t\ttype: \"createSubDirectory\",\n\t\t\t\tpath: \"./\",\n\t\t\t\tsubdirName: \"a\",\n\t\t\t};\n\t\t\tconst op4: IDirectoryOperation = {\n\t\t\t\ttype: \"deleteSubDirectory\",\n\t\t\t\tpath: \"./\",\n\t\t\t\tsubdirName: \"b\",\n\t\t\t};\n\n\t\t\tdirectory.testApplyStashedOp(op1);\n\t\t\tdirectory.testApplyStashedOp(op2);\n\t\t\tdirectory.testApplyStashedOp(op3);\n\n\t\t\tassertDirectoryIterationOrder(directory, [\"c\", \"b\", \"a\"]);\n\n\t\t\tdirectory.testApplyStashedOp(op4);\n\n\t\t\tassertDirectoryIterationOrder(directory, [\"c\", \"a\"]);\n\t\t});\n\t});\n});\n"]}
@@ -0,0 +1,111 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ import { strict as assert } from "node:assert";
6
+ import path from "node:path";
7
+ import { MockContainerRuntimeFactory, MockFluidDataStoreRuntime, MockStorage, } from "@fluidframework/test-runtime-utils";
8
+ import { convertSummaryTreeToITree } from "@fluidframework/runtime-utils";
9
+ import { createSnapshotSuite } from "@fluid-private/test-dds-utils";
10
+ import { DirectoryFactory, SharedDirectory } from "../../index.js";
11
+ import { assertEquivalentDirectories } from "./directoryEquivalenceUtils.js";
12
+ import { _dirname } from "./dirname.cjs";
13
+ function serialize(directory) {
14
+ const summaryTree = directory.getAttachSummary().summary;
15
+ const snapshotTree = convertSummaryTreeToITree(summaryTree);
16
+ return JSON.stringify(snapshotTree, undefined, 1);
17
+ }
18
+ async function loadSharedDirectory(id, serializedSnapshot) {
19
+ const containerRuntimeFactory = new MockContainerRuntimeFactory();
20
+ const dataStoreRuntime = new MockFluidDataStoreRuntime();
21
+ const containerRuntime = containerRuntimeFactory.createContainerRuntime(dataStoreRuntime);
22
+ const services = {
23
+ deltaConnection: dataStoreRuntime.createDeltaConnection(),
24
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
25
+ objectStorage: new MockStorage(JSON.parse(serializedSnapshot)),
26
+ };
27
+ const sharedDirectory = new SharedDirectory(id, dataStoreRuntime, DirectoryFactory.Attributes);
28
+ await sharedDirectory.load(services);
29
+ return sharedDirectory;
30
+ }
31
+ function generateTestScenarios() {
32
+ const runtimeFactory = new MockContainerRuntimeFactory();
33
+ const dataStoreRuntime = new MockFluidDataStoreRuntime({ clientId: "A" });
34
+ runtimeFactory.createContainerRuntime(dataStoreRuntime);
35
+ const factory = SharedDirectory.getFactory();
36
+ /**
37
+ * @remarks - This test suite isn't set up to be easily augmented when map's document format changes.
38
+ * `writeCompatible` may want to be changed to enable storing all snapshots over time for a given scenario.
39
+ * See e.g. SharedString tests.
40
+ */
41
+ const testScenarios = [
42
+ {
43
+ name: "random-create-delete",
44
+ runScenario: () => {
45
+ const testDirectory = new SharedDirectory("A", dataStoreRuntime, factory.attributes);
46
+ const dir1 = testDirectory.createSubDirectory("a");
47
+ const dir2 = testDirectory.createSubDirectory("b");
48
+ dir1.set("key1", "value1");
49
+ dir1.set("key2", "value2");
50
+ dir2.set("key3", "value3");
51
+ testDirectory.set("key4", "value4");
52
+ testDirectory.set("key5", "value5");
53
+ dir2.createSubDirectory("b-a");
54
+ return testDirectory;
55
+ },
56
+ },
57
+ {
58
+ name: "long-property-value",
59
+ runScenario: () => {
60
+ const testDirectory = new SharedDirectory("A", dataStoreRuntime, factory.attributes);
61
+ // 40K word
62
+ let longWord = "0123456789";
63
+ for (let i = 0; i < 12; i++) {
64
+ longWord = longWord + longWord;
65
+ }
66
+ const logWord2 = `${longWord}_2`;
67
+ testDirectory.set("first", "second");
68
+ testDirectory.set("long1", longWord);
69
+ const nestedDirectory = testDirectory.createSubDirectory("nested");
70
+ nestedDirectory.set("deepKey1", "deepValue1");
71
+ nestedDirectory.set("long2", logWord2);
72
+ return testDirectory;
73
+ },
74
+ },
75
+ {
76
+ name: "old-format-directory",
77
+ runScenario: () => {
78
+ const testDirectory = new SharedDirectory("A", dataStoreRuntime, factory.attributes);
79
+ const dir1 = testDirectory.createSubDirectory("a");
80
+ const dir2 = testDirectory.createSubDirectory("b");
81
+ dir1.set("key3", "value3");
82
+ dir1.set("key4", "value2");
83
+ dir2.set("key5", "value3");
84
+ testDirectory.set("key1", "value1");
85
+ testDirectory.set("key2", "value2");
86
+ return testDirectory;
87
+ },
88
+ writeCompatible: false,
89
+ },
90
+ // Add more test scenarios as needed
91
+ ];
92
+ return testScenarios;
93
+ }
94
+ describe("SharedDirectory Snapshot Tests", () => {
95
+ // Set up the directory path for reading/writing snapshots and generate tests
96
+ assert(_dirname.match(/(dist|lib)[/\\]test[/\\]mocha$/));
97
+ const testScenarios = generateTestScenarios();
98
+ const { takeSnapshot, readSnapshot } = createSnapshotSuite(path.resolve(_dirname, `../../../src/test/mocha/snapshots/`));
99
+ for (const { name, runScenario, only = false, skip = false, writeCompatible = true, } of testScenarios) {
100
+ const itFn = only ? it.only : skip ? it.skip : it;
101
+ itFn(name, async () => {
102
+ const testDirectory = runScenario();
103
+ const snapshotData = writeCompatible
104
+ ? takeSnapshot(serialize(testDirectory))
105
+ : readSnapshot();
106
+ const secondDirectory = await loadSharedDirectory("B", snapshotData);
107
+ assertEquivalentDirectories(testDirectory, secondDirectory);
108
+ });
109
+ }
110
+ });
111
+ //# sourceMappingURL=directory.snapshot.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory.snapshot.spec.js","sourceRoot":"","sources":["../../../src/test/mocha/directory.snapshot.spec.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { strict as assert } from \"node:assert\";\nimport path from \"node:path\";\nimport {\n\tMockContainerRuntimeFactory,\n\tMockFluidDataStoreRuntime,\n\tMockStorage,\n} from \"@fluidframework/test-runtime-utils\";\nimport { convertSummaryTreeToITree } from \"@fluidframework/runtime-utils\";\nimport { createSnapshotSuite } from \"@fluid-private/test-dds-utils\";\nimport { DirectoryFactory, SharedDirectory } from \"../../index.js\";\nimport { assertEquivalentDirectories } from \"./directoryEquivalenceUtils.js\";\nimport { _dirname } from \"./dirname.cjs\";\n\nfunction serialize(directory: SharedDirectory): string {\n\tconst summaryTree = directory.getAttachSummary().summary;\n\tconst snapshotTree = convertSummaryTreeToITree(summaryTree);\n\treturn JSON.stringify(snapshotTree, undefined, 1);\n}\n\nasync function loadSharedDirectory(\n\tid: string,\n\tserializedSnapshot: string,\n): Promise<SharedDirectory> {\n\tconst containerRuntimeFactory = new MockContainerRuntimeFactory();\n\tconst dataStoreRuntime = new MockFluidDataStoreRuntime();\n\tconst containerRuntime = containerRuntimeFactory.createContainerRuntime(dataStoreRuntime);\n\tconst services = {\n\t\tdeltaConnection: dataStoreRuntime.createDeltaConnection(),\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n\t\tobjectStorage: new MockStorage(JSON.parse(serializedSnapshot)),\n\t};\n\tconst sharedDirectory = new SharedDirectory(id, dataStoreRuntime, DirectoryFactory.Attributes);\n\tawait sharedDirectory.load(services);\n\treturn sharedDirectory;\n}\n\ninterface TestScenario {\n\tonly?: boolean;\n\tskip?: boolean;\n\tname: string;\n\trunScenario: () => unknown;\n\t/**\n\t * Whether running the scenario produces a snapshot which matches the saved one.\n\t * This is used to test back-compat of snapshots, i.e. ensuring current code can load older documents.\n\t * @remarks - It may be valuable to confirm clients can collaborate on such documents\n\t * after loading them.\n\t */\n\twriteCompatible?: boolean;\n}\n\nfunction generateTestScenarios(): TestScenario[] {\n\tconst runtimeFactory = new MockContainerRuntimeFactory();\n\tconst dataStoreRuntime = new MockFluidDataStoreRuntime({ clientId: \"A\" });\n\truntimeFactory.createContainerRuntime(dataStoreRuntime);\n\tconst factory = SharedDirectory.getFactory();\n\n\t/**\n\t * @remarks - This test suite isn't set up to be easily augmented when map's document format changes.\n\t * `writeCompatible` may want to be changed to enable storing all snapshots over time for a given scenario.\n\t * See e.g. SharedString tests.\n\t */\n\tconst testScenarios: TestScenario[] = [\n\t\t{\n\t\t\tname: \"random-create-delete\",\n\t\t\trunScenario: (): SharedDirectory => {\n\t\t\t\tconst testDirectory = new SharedDirectory(\n\t\t\t\t\t\"A\",\n\t\t\t\t\tdataStoreRuntime,\n\t\t\t\t\tfactory.attributes,\n\t\t\t\t);\n\t\t\t\tconst dir1 = testDirectory.createSubDirectory(\"a\");\n\t\t\t\tconst dir2 = testDirectory.createSubDirectory(\"b\");\n\t\t\t\tdir1.set(\"key1\", \"value1\");\n\t\t\t\tdir1.set(\"key2\", \"value2\");\n\t\t\t\tdir2.set(\"key3\", \"value3\");\n\t\t\t\ttestDirectory.set(\"key4\", \"value4\");\n\t\t\t\ttestDirectory.set(\"key5\", \"value5\");\n\t\t\t\tdir2.createSubDirectory(\"b-a\");\n\t\t\t\treturn testDirectory;\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"long-property-value\",\n\t\t\trunScenario: (): SharedDirectory => {\n\t\t\t\tconst testDirectory = new SharedDirectory(\n\t\t\t\t\t\"A\",\n\t\t\t\t\tdataStoreRuntime,\n\t\t\t\t\tfactory.attributes,\n\t\t\t\t);\n\t\t\t\t// 40K word\n\t\t\t\tlet longWord = \"0123456789\";\n\t\t\t\tfor (let i = 0; i < 12; i++) {\n\t\t\t\t\tlongWord = longWord + longWord;\n\t\t\t\t}\n\t\t\t\tconst logWord2 = `${longWord}_2`;\n\n\t\t\t\ttestDirectory.set(\"first\", \"second\");\n\t\t\t\ttestDirectory.set(\"long1\", longWord);\n\t\t\t\tconst nestedDirectory = testDirectory.createSubDirectory(\"nested\");\n\t\t\t\tnestedDirectory.set(\"deepKey1\", \"deepValue1\");\n\t\t\t\tnestedDirectory.set(\"long2\", logWord2);\n\t\t\t\treturn testDirectory;\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"old-format-directory\",\n\t\t\trunScenario: (): SharedDirectory => {\n\t\t\t\tconst testDirectory = new SharedDirectory(\n\t\t\t\t\t\"A\",\n\t\t\t\t\tdataStoreRuntime,\n\t\t\t\t\tfactory.attributes,\n\t\t\t\t);\n\t\t\t\tconst dir1 = testDirectory.createSubDirectory(\"a\");\n\t\t\t\tconst dir2 = testDirectory.createSubDirectory(\"b\");\n\t\t\t\tdir1.set(\"key3\", \"value3\");\n\t\t\t\tdir1.set(\"key4\", \"value2\");\n\t\t\t\tdir2.set(\"key5\", \"value3\");\n\t\t\t\ttestDirectory.set(\"key1\", \"value1\");\n\t\t\t\ttestDirectory.set(\"key2\", \"value2\");\n\t\t\t\treturn testDirectory;\n\t\t\t},\n\t\t\twriteCompatible: false,\n\t\t},\n\t\t// Add more test scenarios as needed\n\t];\n\n\treturn testScenarios;\n}\n\ndescribe(\"SharedDirectory Snapshot Tests\", () => {\n\t// Set up the directory path for reading/writing snapshots and generate tests\n\tassert(_dirname.match(/(dist|lib)[/\\\\]test[/\\\\]mocha$/));\n\tconst testScenarios = generateTestScenarios();\n\tconst { takeSnapshot, readSnapshot } = createSnapshotSuite(\n\t\tpath.resolve(_dirname, `../../../src/test/mocha/snapshots/`),\n\t);\n\n\tfor (const {\n\t\tname,\n\t\trunScenario,\n\t\tonly = false,\n\t\tskip = false,\n\t\twriteCompatible = true,\n\t} of testScenarios) {\n\t\tconst itFn = only ? it.only : skip ? it.skip : it;\n\t\titFn(name, async () => {\n\t\t\tconst testDirectory = runScenario() as SharedDirectory;\n\t\t\tconst snapshotData = writeCompatible\n\t\t\t\t? takeSnapshot(serialize(testDirectory))\n\t\t\t\t: readSnapshot();\n\t\t\tconst secondDirectory = await loadSharedDirectory(\"B\", snapshotData);\n\t\t\tassertEquivalentDirectories(testDirectory, secondDirectory);\n\t\t});\n\t}\n});\n"]}