@fluidframework/container-loader 2.0.0-dev-rc.2.0.0.246488 → 2.0.0-dev-rc.3.0.0.253463

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 (236) hide show
  1. package/api-report/container-loader.api.md +11 -11
  2. package/dist/attachment.d.ts +6 -9
  3. package/dist/attachment.d.ts.map +1 -1
  4. package/dist/attachment.js +3 -3
  5. package/dist/attachment.js.map +1 -1
  6. package/dist/audience.d.ts +1 -1
  7. package/dist/audience.d.ts.map +1 -1
  8. package/dist/audience.js +2 -2
  9. package/dist/audience.js.map +1 -1
  10. package/dist/catchUpMonitor.d.ts +1 -1
  11. package/dist/catchUpMonitor.d.ts.map +1 -1
  12. package/dist/catchUpMonitor.js +2 -2
  13. package/dist/catchUpMonitor.js.map +1 -1
  14. package/dist/connectionManager.d.ts +4 -4
  15. package/dist/connectionManager.d.ts.map +1 -1
  16. package/dist/connectionManager.js +42 -42
  17. package/dist/connectionManager.js.map +1 -1
  18. package/dist/connectionStateHandler.d.ts +3 -3
  19. package/dist/connectionStateHandler.d.ts.map +1 -1
  20. package/dist/connectionStateHandler.js +27 -27
  21. package/dist/connectionStateHandler.js.map +1 -1
  22. package/dist/container-loader-alpha.d.ts +11 -11
  23. package/dist/container-loader-beta.d.ts +11 -11
  24. package/dist/container-loader-public.d.ts +11 -11
  25. package/dist/container-loader-untrimmed.d.ts +11 -11
  26. package/dist/container.d.ts +9 -46
  27. package/dist/container.d.ts.map +1 -1
  28. package/dist/container.js +96 -108
  29. package/dist/container.js.map +1 -1
  30. package/dist/containerContext.d.ts +19 -7
  31. package/dist/containerContext.d.ts.map +1 -1
  32. package/dist/containerContext.js +7 -2
  33. package/dist/containerContext.js.map +1 -1
  34. package/dist/containerStorageAdapter.d.ts +3 -3
  35. package/dist/containerStorageAdapter.d.ts.map +1 -1
  36. package/dist/containerStorageAdapter.js +6 -6
  37. package/dist/containerStorageAdapter.js.map +1 -1
  38. package/dist/contracts.d.ts +4 -3
  39. package/dist/contracts.d.ts.map +1 -1
  40. package/dist/contracts.js +2 -2
  41. package/dist/contracts.js.map +1 -1
  42. package/dist/debugLogger.d.ts +2 -1
  43. package/dist/debugLogger.d.ts.map +1 -1
  44. package/dist/debugLogger.js +4 -4
  45. package/dist/debugLogger.js.map +1 -1
  46. package/dist/deltaManager.d.ts +7 -6
  47. package/dist/deltaManager.d.ts.map +1 -1
  48. package/dist/deltaManager.js +45 -45
  49. package/dist/deltaManager.js.map +1 -1
  50. package/dist/deltaQueue.d.ts +1 -1
  51. package/dist/deltaQueue.d.ts.map +1 -1
  52. package/dist/deltaQueue.js +5 -5
  53. package/dist/deltaQueue.js.map +1 -1
  54. package/dist/error.d.ts +3 -2
  55. package/dist/error.d.ts.map +1 -1
  56. package/dist/error.js +5 -5
  57. package/dist/error.js.map +1 -1
  58. package/dist/loader.d.ts +4 -4
  59. package/dist/loader.d.ts.map +1 -1
  60. package/dist/loader.js +23 -23
  61. package/dist/loader.js.map +1 -1
  62. package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts +2 -2
  63. package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -1
  64. package/dist/location-redirection-utilities/resolveWithLocationRedirection.js +2 -2
  65. package/dist/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -1
  66. package/dist/noopHeuristic.d.ts +1 -1
  67. package/dist/noopHeuristic.d.ts.map +1 -1
  68. package/dist/noopHeuristic.js +6 -6
  69. package/dist/noopHeuristic.js.map +1 -1
  70. package/dist/packageVersion.d.ts +1 -1
  71. package/dist/packageVersion.js +1 -1
  72. package/dist/packageVersion.js.map +1 -1
  73. package/dist/protocol.d.ts +1 -1
  74. package/dist/protocol.d.ts.map +1 -1
  75. package/dist/protocol.js +2 -2
  76. package/dist/protocol.js.map +1 -1
  77. package/dist/protocolTreeDocumentStorageService.d.ts +4 -4
  78. package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
  79. package/dist/protocolTreeDocumentStorageService.js.map +1 -1
  80. package/dist/quorum.d.ts +1 -1
  81. package/dist/quorum.d.ts.map +1 -1
  82. package/dist/quorum.js.map +1 -1
  83. package/dist/retriableDocumentStorageService.d.ts +2 -2
  84. package/dist/retriableDocumentStorageService.d.ts.map +1 -1
  85. package/dist/retriableDocumentStorageService.js +7 -7
  86. package/dist/retriableDocumentStorageService.js.map +1 -1
  87. package/dist/serializedStateManager.d.ts +87 -16
  88. package/dist/serializedStateManager.d.ts.map +1 -1
  89. package/dist/serializedStateManager.js +164 -80
  90. package/dist/serializedStateManager.js.map +1 -1
  91. package/dist/utils.d.ts +6 -7
  92. package/dist/utils.d.ts.map +1 -1
  93. package/dist/utils.js +39 -23
  94. package/dist/utils.js.map +1 -1
  95. package/lib/attachment.d.ts +6 -9
  96. package/lib/attachment.d.ts.map +1 -1
  97. package/lib/attachment.js +1 -1
  98. package/lib/attachment.js.map +1 -1
  99. package/lib/audience.d.ts +1 -1
  100. package/lib/audience.d.ts.map +1 -1
  101. package/lib/audience.js +1 -1
  102. package/lib/audience.js.map +1 -1
  103. package/lib/catchUpMonitor.d.ts +1 -1
  104. package/lib/catchUpMonitor.d.ts.map +1 -1
  105. package/lib/catchUpMonitor.js +1 -1
  106. package/lib/catchUpMonitor.js.map +1 -1
  107. package/lib/connectionManager.d.ts +4 -4
  108. package/lib/connectionManager.d.ts.map +1 -1
  109. package/lib/connectionManager.js +5 -5
  110. package/lib/connectionManager.js.map +1 -1
  111. package/lib/connectionStateHandler.d.ts +3 -3
  112. package/lib/connectionStateHandler.d.ts.map +1 -1
  113. package/lib/connectionStateHandler.js +2 -2
  114. package/lib/connectionStateHandler.js.map +1 -1
  115. package/lib/container-loader-alpha.d.ts +11 -11
  116. package/lib/container-loader-beta.d.ts +11 -11
  117. package/lib/container-loader-public.d.ts +11 -11
  118. package/lib/container-loader-untrimmed.d.ts +11 -11
  119. package/lib/container.d.ts +9 -46
  120. package/lib/container.d.ts.map +1 -1
  121. package/lib/container.js +28 -40
  122. package/lib/container.js.map +1 -1
  123. package/lib/containerContext.d.ts +19 -7
  124. package/lib/containerContext.d.ts.map +1 -1
  125. package/lib/containerContext.js +7 -2
  126. package/lib/containerContext.js.map +1 -1
  127. package/lib/containerStorageAdapter.d.ts +3 -3
  128. package/lib/containerStorageAdapter.d.ts.map +1 -1
  129. package/lib/containerStorageAdapter.js +2 -2
  130. package/lib/containerStorageAdapter.js.map +1 -1
  131. package/lib/contracts.d.ts +4 -3
  132. package/lib/contracts.d.ts.map +1 -1
  133. package/lib/contracts.js +1 -1
  134. package/lib/contracts.js.map +1 -1
  135. package/lib/debugLogger.d.ts +2 -1
  136. package/lib/debugLogger.d.ts.map +1 -1
  137. package/lib/debugLogger.js +1 -1
  138. package/lib/debugLogger.js.map +1 -1
  139. package/lib/deltaManager.d.ts +7 -6
  140. package/lib/deltaManager.d.ts.map +1 -1
  141. package/lib/deltaManager.js +5 -5
  142. package/lib/deltaManager.js.map +1 -1
  143. package/lib/deltaQueue.d.ts +1 -1
  144. package/lib/deltaQueue.d.ts.map +1 -1
  145. package/lib/deltaQueue.js +2 -2
  146. package/lib/deltaQueue.js.map +1 -1
  147. package/lib/error.d.ts +3 -2
  148. package/lib/error.d.ts.map +1 -1
  149. package/lib/error.js +2 -2
  150. package/lib/error.js.map +1 -1
  151. package/lib/loader.d.ts +4 -4
  152. package/lib/loader.d.ts.map +1 -1
  153. package/lib/loader.js +4 -4
  154. package/lib/loader.js.map +1 -1
  155. package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.ts +2 -2
  156. package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -1
  157. package/lib/location-redirection-utilities/resolveWithLocationRedirection.js +2 -2
  158. package/lib/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -1
  159. package/lib/noopHeuristic.d.ts +1 -1
  160. package/lib/noopHeuristic.d.ts.map +1 -1
  161. package/lib/noopHeuristic.js +2 -2
  162. package/lib/noopHeuristic.js.map +1 -1
  163. package/lib/packageVersion.d.ts +1 -1
  164. package/lib/packageVersion.js +1 -1
  165. package/lib/packageVersion.js.map +1 -1
  166. package/lib/protocol.d.ts +1 -1
  167. package/lib/protocol.d.ts.map +1 -1
  168. package/lib/protocol.js +1 -1
  169. package/lib/protocol.js.map +1 -1
  170. package/lib/protocolTreeDocumentStorageService.d.ts +4 -4
  171. package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
  172. package/lib/protocolTreeDocumentStorageService.js.map +1 -1
  173. package/lib/quorum.d.ts +1 -1
  174. package/lib/quorum.d.ts.map +1 -1
  175. package/lib/quorum.js.map +1 -1
  176. package/lib/retriableDocumentStorageService.d.ts +2 -2
  177. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  178. package/lib/retriableDocumentStorageService.js +3 -3
  179. package/lib/retriableDocumentStorageService.js.map +1 -1
  180. package/lib/serializedStateManager.d.ts +87 -16
  181. package/lib/serializedStateManager.d.ts.map +1 -1
  182. package/lib/serializedStateManager.js +156 -75
  183. package/lib/serializedStateManager.js.map +1 -1
  184. package/lib/tsdoc-metadata.json +11 -0
  185. package/lib/utils.d.ts +6 -7
  186. package/lib/utils.d.ts.map +1 -1
  187. package/lib/utils.js +27 -12
  188. package/lib/utils.js.map +1 -1
  189. package/package.json +19 -28
  190. package/src/attachment.ts +9 -8
  191. package/src/audience.ts +2 -2
  192. package/src/catchUpMonitor.ts +2 -2
  193. package/src/connectionManager.ts +19 -19
  194. package/src/connectionStateHandler.ts +7 -7
  195. package/src/container.ts +78 -133
  196. package/src/containerContext.ts +22 -12
  197. package/src/containerStorageAdapter.ts +7 -6
  198. package/src/contracts.ts +4 -5
  199. package/src/debugLogger.ts +3 -4
  200. package/src/deltaManager.ts +31 -25
  201. package/src/deltaQueue.ts +2 -2
  202. package/src/error.ts +5 -4
  203. package/src/loader.ts +25 -23
  204. package/src/location-redirection-utilities/resolveWithLocationRedirection.ts +4 -4
  205. package/src/noopHeuristic.ts +3 -3
  206. package/src/packageVersion.ts +1 -1
  207. package/src/protocol.ts +2 -2
  208. package/src/protocolTreeDocumentStorageService.ts +4 -1
  209. package/src/quorum.ts +1 -1
  210. package/src/retriableDocumentStorageService.ts +6 -5
  211. package/src/serializedStateManager.ts +276 -110
  212. package/src/utils.ts +51 -20
  213. package/lib/test/attachment.spec.js +0 -380
  214. package/lib/test/attachment.spec.js.map +0 -1
  215. package/lib/test/catchUpMonitor.spec.js +0 -88
  216. package/lib/test/catchUpMonitor.spec.js.map +0 -1
  217. package/lib/test/connectionManager.spec.js +0 -201
  218. package/lib/test/connectionManager.spec.js.map +0 -1
  219. package/lib/test/connectionStateHandler.spec.js +0 -555
  220. package/lib/test/connectionStateHandler.spec.js.map +0 -1
  221. package/lib/test/container.spec.js +0 -64
  222. package/lib/test/container.spec.js.map +0 -1
  223. package/lib/test/deltaManager.spec.js +0 -405
  224. package/lib/test/deltaManager.spec.js.map +0 -1
  225. package/lib/test/loader.spec.js +0 -212
  226. package/lib/test/loader.spec.js.map +0 -1
  227. package/lib/test/locationRedirectionTests.spec.js +0 -44
  228. package/lib/test/locationRedirectionTests.spec.js.map +0 -1
  229. package/lib/test/serializedStateManager.spec.js +0 -148
  230. package/lib/test/serializedStateManager.spec.js.map +0 -1
  231. package/lib/test/snapshotConversionTest.spec.js +0 -79
  232. package/lib/test/snapshotConversionTest.spec.js.map +0 -1
  233. package/lib/test/types/validateContainerLoaderPrevious.generated.js +0 -38
  234. package/lib/test/types/validateContainerLoaderPrevious.generated.js.map +0 -1
  235. package/lib/test/utils.spec.js +0 -31
  236. package/lib/test/utils.spec.js.map +0 -1
package/src/utils.ts CHANGED
@@ -3,19 +3,30 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { v4 as uuid } from "uuid";
7
6
  import { Uint8ArrayToString, stringToBuffer } from "@fluid-internal/client-utils";
8
- import { assert, compareArrays, unreachableCase } from "@fluidframework/core-utils";
9
- import { ISummaryTree, ISnapshotTree, SummaryType } from "@fluidframework/protocol-definitions";
10
- import { LoggingError, UsageError } from "@fluidframework/telemetry-utils";
7
+ import { assert, compareArrays, unreachableCase } from "@fluidframework/core-utils/internal";
8
+ import { DriverErrorTypes } from "@fluidframework/driver-definitions";
9
+ import { IDocumentStorageService } from "@fluidframework/driver-definitions/internal";
11
10
  import {
12
11
  CombinedAppAndProtocolSummary,
13
12
  DeltaStreamConnectionForbiddenError,
14
13
  isCombinedAppAndProtocolSummary,
15
- } from "@fluidframework/driver-utils";
16
- import { DriverErrorTypes } from "@fluidframework/driver-definitions";
14
+ readAndParse,
15
+ } from "@fluidframework/driver-utils/internal";
16
+ import {
17
+ IDocumentAttributes,
18
+ ISnapshotTree,
19
+ ISummaryTree,
20
+ SummaryType,
21
+ } from "@fluidframework/protocol-definitions";
22
+ import { LoggingError, UsageError } from "@fluidframework/telemetry-utils/internal";
23
+ import { v4 as uuid } from "uuid";
24
+
17
25
  import { ISerializableBlobContents } from "./containerStorageAdapter.js";
18
- import { IPendingDetachedContainerState } from "./container.js";
26
+ import type {
27
+ IPendingDetachedContainerState,
28
+ SnapshotWithBlobs,
29
+ } from "./serializedStateManager.js";
19
30
 
20
31
  // This is used when we rehydrate a container from the snapshot. Here we put the blob contents
21
32
  // in separate property: blobContents.
@@ -111,10 +122,7 @@ export function combineAppAndProtocolSummary(
111
122
  * to align detached container format with IPendingContainerState
112
123
  * @param summary - ISummaryTree
113
124
  */
114
- function convertSummaryToSnapshotAndBlobs(summary: ISummaryTree): {
115
- tree: ISnapshotTree;
116
- blobs: ISerializableBlobContents;
117
- } {
125
+ function convertSummaryToSnapshotAndBlobs(summary: ISummaryTree): SnapshotWithBlobs {
118
126
  let blobContents: ISerializableBlobContents = {};
119
127
  const treeNode: ISnapshotTree = {
120
128
  blobs: {},
@@ -129,9 +137,9 @@ function convertSummaryToSnapshotAndBlobs(summary: ISummaryTree): {
129
137
 
130
138
  switch (summaryObject.type) {
131
139
  case SummaryType.Tree: {
132
- const { tree, blobs } = convertSummaryToSnapshotAndBlobs(summaryObject);
133
- treeNode.trees[key] = tree;
134
- blobContents = { ...blobContents, ...blobs };
140
+ const innerSnapshot = convertSummaryToSnapshotAndBlobs(summaryObject);
141
+ treeNode.trees[key] = innerSnapshot.baseSnapshot;
142
+ blobContents = { ...blobContents, ...innerSnapshot.snapshotBlobs };
135
143
  break;
136
144
  }
137
145
  case SummaryType.Attachment:
@@ -157,7 +165,8 @@ function convertSummaryToSnapshotAndBlobs(summary: ISummaryTree): {
157
165
  }
158
166
  }
159
167
  }
160
- return { tree: treeNode, blobs: blobContents };
168
+ const pendingSnapshot = { baseSnapshot: treeNode, snapshotBlobs: blobContents };
169
+ return pendingSnapshot;
161
170
  }
162
171
 
163
172
  /**
@@ -168,7 +177,7 @@ function convertSummaryToSnapshotAndBlobs(summary: ISummaryTree): {
168
177
  function convertProtocolAndAppSummaryToSnapshotAndBlobs(
169
178
  protocolSummaryTree: ISummaryTree,
170
179
  appSummaryTree: ISummaryTree,
171
- ): { tree: ISnapshotTree; blobs: ISerializableBlobContents } {
180
+ ): SnapshotWithBlobs {
172
181
  const combinedSummary: ISummaryTree = {
173
182
  type: SummaryType.Tree,
174
183
  tree: { ...appSummaryTree.tree },
@@ -181,7 +190,7 @@ function convertProtocolAndAppSummaryToSnapshotAndBlobs(
181
190
 
182
191
  export const getSnapshotTreeAndBlobsFromSerializedContainer = (
183
192
  detachedContainerSnapshot: ISummaryTree,
184
- ): { tree: ISnapshotTree; blobs: ISerializableBlobContents } => {
193
+ ): SnapshotWithBlobs => {
185
194
  assert(
186
195
  isCombinedAppAndProtocolSummary(detachedContainerSnapshot),
187
196
  0x8e6 /* Protocol and App summary trees should be present */,
@@ -264,12 +273,12 @@ export function getDetachedContainerStateFromSerializedContainer(
264
273
  if (isPendingDetachedContainerState(parsedContainerState)) {
265
274
  return parsedContainerState;
266
275
  } else if (isCombinedAppAndProtocolSummary(parsedContainerState)) {
267
- const { tree, blobs } =
276
+ const { baseSnapshot, snapshotBlobs } =
268
277
  getSnapshotTreeAndBlobsFromSerializedContainer(parsedContainerState);
269
278
  const detachedContainerState: IPendingDetachedContainerState = {
270
279
  attached: false,
271
- baseSnapshot: tree,
272
- snapshotBlobs: blobs,
280
+ baseSnapshot,
281
+ snapshotBlobs,
273
282
  hasAttachmentBlobs: parsedContainerState.tree[hasBlobsSummaryTree] !== undefined,
274
283
  };
275
284
  return detachedContainerState;
@@ -305,3 +314,25 @@ export const runSingle = <A extends any[], R>(func: (...args: A) => Promise<R>)
305
314
  return running.result;
306
315
  };
307
316
  };
317
+
318
+ export async function getDocumentAttributes(
319
+ storage: Pick<IDocumentStorageService, "readBlob">,
320
+ tree: ISnapshotTree | undefined,
321
+ ): Promise<IDocumentAttributes> {
322
+ if (tree === undefined) {
323
+ return {
324
+ minimumSequenceNumber: 0,
325
+ sequenceNumber: 0,
326
+ };
327
+ }
328
+
329
+ // Backward compatibility: old docs would have ".attributes" instead of "attributes"
330
+ const attributesHash =
331
+ ".protocol" in tree.trees
332
+ ? tree.trees[".protocol"].blobs.attributes
333
+ : tree.blobs[".attributes"];
334
+
335
+ const attributes = await readAndParse<IDocumentAttributes>(storage, attributesHash);
336
+
337
+ return attributes;
338
+ }
@@ -1,380 +0,0 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
- import { strict as assert } from "assert";
6
- import { AttachState } from "@fluidframework/container-definitions";
7
- import { v4 as uuid } from "uuid";
8
- import { SummaryType } from "@fluidframework/protocol-definitions";
9
- import { stringToBuffer } from "@fluid-internal/client-utils";
10
- import { runRetriableAttachProcess, } from "../attachment.js";
11
- import { combineAppAndProtocolSummary } from "../utils.js";
12
- const emptySummary = combineAppAndProtocolSummary({ tree: {}, type: SummaryType.Tree }, { tree: {}, type: SummaryType.Tree });
13
- const addCallCounts = (obj) => {
14
- const calls = Object.keys(obj).reduce((pv, cv) => {
15
- pv[cv] = 0;
16
- return pv;
17
- }, {});
18
- return new Proxy(obj, {
19
- get: (t, p, r) => {
20
- if (p === "calls") {
21
- return calls;
22
- }
23
- else {
24
- calls[p]++;
25
- return Reflect.get(t, p, r);
26
- }
27
- },
28
- });
29
- };
30
- const createDetachStorage = (blobCount) => {
31
- const blobs = new Map(Array.from({ length: blobCount }).map((_, i) => [
32
- i.toString(),
33
- stringToBuffer(`${i}-content`, "utf-8"),
34
- ]));
35
- return addCallCounts({
36
- get size() {
37
- return blobs.size;
38
- },
39
- getBlobIds() {
40
- return [...blobs.keys()];
41
- },
42
- async readBlob(id) {
43
- const content = blobs.get(id);
44
- assert(content !== undefined, `no blob content for [${id}]`);
45
- return content;
46
- },
47
- });
48
- };
49
- const createProxyWithFailDefault = (partial = {}) => {
50
- return new Proxy(partial, {
51
- get: (t, p, r) => {
52
- if (p in t) {
53
- return Reflect.get(t, p, r);
54
- }
55
- return new Proxy({}, {
56
- get: () => assert.fail(`unexpected call too ${p.toString()}`),
57
- });
58
- },
59
- });
60
- };
61
- describe("runRetriableAttachProcess", () => {
62
- describe("end to end process", () => {
63
- it("From DetachedDefaultData without blobs or offline", async () => {
64
- const initial = {
65
- state: AttachState.Detached,
66
- };
67
- let attachmentData;
68
- await runRetriableAttachProcess({
69
- initialAttachmentData: initial,
70
- offlineLoadEnabled: false,
71
- setAttachmentData: (data) => (attachmentData = data),
72
- createAttachmentSummary: (redirectTable) => {
73
- assert.strictEqual(redirectTable, undefined, "redirectTable");
74
- return emptySummary;
75
- },
76
- createOrGetStorageService: async () => createProxyWithFailDefault(),
77
- });
78
- assert.strictEqual(attachmentData?.state, AttachState.Attached, "should be attached");
79
- });
80
- it("From DetachedDefaultData with offline and without blobs", async () => {
81
- const initial = {
82
- state: AttachState.Detached,
83
- };
84
- let attachmentData;
85
- const snapshot = await runRetriableAttachProcess({
86
- initialAttachmentData: initial,
87
- offlineLoadEnabled: true,
88
- setAttachmentData: (data) => (attachmentData = data),
89
- createAttachmentSummary: (redirectTable) => {
90
- assert.strictEqual(redirectTable, undefined, "redirectTable");
91
- return emptySummary;
92
- },
93
- createOrGetStorageService: async () => ({
94
- createBlob: async () => assert.fail("no blobs should be created"),
95
- uploadSummaryWithContext: async () => assert.fail("no summary should be uploaded outside of create"),
96
- }),
97
- });
98
- assert.strictEqual(attachmentData?.state, AttachState.Attached, "should be attached");
99
- assert.notStrictEqual(snapshot, undefined, "should have snapshot");
100
- });
101
- it("From DetachedDefaultData with blobs and without offline", async () => {
102
- const initial = {
103
- state: AttachState.Detached,
104
- };
105
- let attachmentData;
106
- const blobCount = 10;
107
- const detachedBlobStorage = createDetachStorage(blobCount);
108
- const storageAdapter = addCallCounts({
109
- createBlob: async () => Promise.resolve({ id: uuid() }),
110
- uploadSummaryWithContext: async () => Promise.resolve(uuid()),
111
- });
112
- await runRetriableAttachProcess({
113
- initialAttachmentData: initial,
114
- offlineLoadEnabled: false,
115
- setAttachmentData: (data) => (attachmentData = data),
116
- createAttachmentSummary: (redirectTable) => {
117
- assert.strictEqual(redirectTable?.size, blobCount, "redirectTable?.size");
118
- return emptySummary;
119
- },
120
- createOrGetStorageService: async () => storageAdapter,
121
- detachedBlobStorage,
122
- });
123
- // expect every blob to read, and uploaded
124
- assert.strictEqual(detachedBlobStorage.calls.readBlob, blobCount, "detachedBlobStorage.calls.readBlob");
125
- assert.strictEqual(storageAdapter.calls.createBlob, blobCount, "storageAdapter.calls.createBlob");
126
- // after blobs are uploaded summary should be
127
- assert.strictEqual(storageAdapter.calls.uploadSummaryWithContext, 1, "storageAdapter.calls.uploadSummaryWithContext");
128
- assert.strictEqual(attachmentData?.state, AttachState.Attached, "should be attached");
129
- });
130
- it("From DetachedDefaultData with zero blobs and without offline", async () => {
131
- const initial = {
132
- state: AttachState.Detached,
133
- };
134
- let attachmentData;
135
- await runRetriableAttachProcess({
136
- initialAttachmentData: initial,
137
- offlineLoadEnabled: false,
138
- setAttachmentData: (data) => (attachmentData = data),
139
- createAttachmentSummary: (redirectTable) => {
140
- assert.strictEqual(redirectTable, undefined, "redirectTable");
141
- return emptySummary;
142
- },
143
- createOrGetStorageService: async () => createProxyWithFailDefault(),
144
- // we have blobs storage, but it is empty,
145
- // so it should be treat like there are no blobs
146
- detachedBlobStorage: createProxyWithFailDefault({ size: 0 }),
147
- });
148
- assert.strictEqual(attachmentData?.state, AttachState.Attached, "should be attached");
149
- });
150
- });
151
- describe("ends in intermediate state due to failure", () => {
152
- it("From DetachedDefaultData without blobs with createAttachmentSummary failure", async () => {
153
- const initial = {
154
- state: AttachState.Detached,
155
- };
156
- let attachmentData;
157
- const error = new Error("createAttachmentSummary failure");
158
- try {
159
- await runRetriableAttachProcess(createProxyWithFailDefault({
160
- initialAttachmentData: initial,
161
- detachedBlobStorage: undefined,
162
- createAttachmentSummary: () => {
163
- throw error;
164
- },
165
- }));
166
- assert.fail("failure expected");
167
- }
168
- catch (e) {
169
- assert.deepStrictEqual(e, error);
170
- }
171
- assert.deepStrictEqual(attachmentData, undefined, "attachment data shouldn't have been set");
172
- });
173
- it("From DetachedDefaultData without blobs getStorageService failure", async () => {
174
- const initial = {
175
- state: AttachState.Detached,
176
- };
177
- let attachmentData;
178
- const error = new Error("getStorageService failure");
179
- try {
180
- await runRetriableAttachProcess(createProxyWithFailDefault({
181
- initialAttachmentData: initial,
182
- setAttachmentData: (data) => (attachmentData = data),
183
- createAttachmentSummary: () => emptySummary,
184
- detachedBlobStorage: undefined,
185
- createOrGetStorageService: () => {
186
- throw error;
187
- },
188
- }));
189
- assert.fail("failure expected");
190
- }
191
- catch (e) {
192
- assert.deepStrictEqual(e, error);
193
- }
194
- assert.deepStrictEqual(attachmentData, {
195
- state: AttachState.Attaching,
196
- blobs: "none",
197
- summary: emptySummary,
198
- }, "should have made it to attaching state");
199
- });
200
- it("From DetachedDefaultData with blobs with createBlob failure", async () => {
201
- const initial = {
202
- state: AttachState.Detached,
203
- };
204
- let attachmentData;
205
- const blobCount = 10;
206
- const detachedBlobStorage = createDetachStorage(blobCount);
207
- const error = new Error("createBlob failure");
208
- try {
209
- await runRetriableAttachProcess({
210
- initialAttachmentData: initial,
211
- offlineLoadEnabled: false,
212
- setAttachmentData: (data) => (attachmentData = data),
213
- createAttachmentSummary: () => emptySummary,
214
- createOrGetStorageService: async () => createProxyWithFailDefault({
215
- createBlob: () => {
216
- throw error;
217
- },
218
- }),
219
- detachedBlobStorage,
220
- });
221
- assert.fail("failure expected");
222
- }
223
- catch (e) {
224
- assert.deepStrictEqual(e, error);
225
- }
226
- assert.deepStrictEqual(attachmentData, {
227
- state: AttachState.Detached,
228
- blobs: "outstanding",
229
- redirectTable: new Map(),
230
- }, "should have made it to attaching state");
231
- });
232
- it("From DetachedDefaultData with blobs with createAttachmentSummary failure", async () => {
233
- const initial = {
234
- state: AttachState.Detached,
235
- };
236
- let attachmentData;
237
- const blobCount = 10;
238
- const detachedBlobStorage = createDetachStorage(blobCount);
239
- const error = new Error("createAttachmentSummary failure");
240
- try {
241
- await runRetriableAttachProcess({
242
- initialAttachmentData: initial,
243
- offlineLoadEnabled: false,
244
- setAttachmentData: (data) => (attachmentData = data),
245
- createAttachmentSummary: () => {
246
- throw error;
247
- },
248
- createOrGetStorageService: async () => createProxyWithFailDefault({
249
- createBlob: async () => Promise.resolve({ id: uuid() }),
250
- }),
251
- detachedBlobStorage,
252
- });
253
- assert.fail("failure expected");
254
- }
255
- catch (e) {
256
- assert.deepStrictEqual(e, error);
257
- }
258
- assert.deepStrictEqual(
259
- // override redirectTable as it makes validation pain, and we have good coverage in other tests
260
- {
261
- ...attachmentData,
262
- redirectTable: attachmentData && "redirectTable" in attachmentData ? new Map() : undefined,
263
- }, {
264
- state: AttachState.Detached,
265
- blobs: "outstanding",
266
- redirectTable: new Map(),
267
- }, "should have made it to attaching state");
268
- });
269
- it("From DetachedDefaultData with blobs with uploadSummaryWithContext failure", async () => {
270
- const initial = {
271
- state: AttachState.Detached,
272
- };
273
- let attachmentData;
274
- const blobCount = 10;
275
- const detachedBlobStorage = createDetachStorage(blobCount);
276
- const error = new Error("uploadSummaryWithContext failure");
277
- try {
278
- await runRetriableAttachProcess({
279
- initialAttachmentData: initial,
280
- offlineLoadEnabled: false,
281
- setAttachmentData: (data) => (attachmentData = data),
282
- createAttachmentSummary: (redirectTable) => {
283
- assert.strictEqual(redirectTable?.size, 10, "redirectTable?.size");
284
- return emptySummary;
285
- },
286
- createOrGetStorageService: async () => ({
287
- createBlob: async () => Promise.resolve({ id: uuid() }),
288
- uploadSummaryWithContext: () => {
289
- throw error;
290
- },
291
- }),
292
- detachedBlobStorage,
293
- });
294
- assert.fail("failure expected");
295
- }
296
- catch (e) {
297
- assert.deepStrictEqual(e, error);
298
- }
299
- assert.deepStrictEqual(attachmentData, {
300
- state: AttachState.Attaching,
301
- blobs: "done",
302
- summary: emptySummary,
303
- }, "should have made it to attaching state");
304
- });
305
- });
306
- describe("from intermediate state", () => {
307
- it("From DetachedDataWithOutstandingBlobs", async () => {
308
- const initial = {
309
- state: AttachState.Detached,
310
- blobs: "outstanding",
311
- redirectTable: new Map(),
312
- };
313
- let attachmentData;
314
- const blobCount = 10;
315
- const detachedBlobStorage = createDetachStorage(blobCount);
316
- const storageAdapter = addCallCounts({
317
- createBlob: async () => Promise.resolve({ id: uuid() }),
318
- uploadSummaryWithContext: async () => Promise.resolve(uuid()),
319
- });
320
- await runRetriableAttachProcess({
321
- initialAttachmentData: initial,
322
- offlineLoadEnabled: false,
323
- setAttachmentData: (data) => (attachmentData = data),
324
- createAttachmentSummary: (redirectTable) => {
325
- assert.strictEqual(redirectTable?.size, blobCount, "redirectTable?.size");
326
- return emptySummary;
327
- },
328
- createOrGetStorageService: async () => storageAdapter,
329
- detachedBlobStorage,
330
- });
331
- // expect every blob to read, and uploaded
332
- assert.strictEqual(initial.redirectTable.size, blobCount, "initial.redirectTable.size");
333
- assert.strictEqual(detachedBlobStorage.calls.readBlob, blobCount, "detachedBlobStorage.calls.readBlob");
334
- assert.strictEqual(storageAdapter.calls.createBlob, blobCount, "storageAdapter.calls.createBlob");
335
- // after blobs are uploaded summary should be
336
- assert.strictEqual(storageAdapter.calls.uploadSummaryWithContext, 1, "storageAdapter.calls.uploadSummaryWithContext");
337
- assert.strictEqual(attachmentData?.state, AttachState.Attached, "should be attached");
338
- });
339
- it("From AttachingDataWithBlobs", async () => {
340
- const initial = {
341
- state: AttachState.Attaching,
342
- blobs: "done",
343
- summary: emptySummary,
344
- };
345
- let attachmentData;
346
- const snapshot = await runRetriableAttachProcess(createProxyWithFailDefault({
347
- initialAttachmentData: initial,
348
- offlineLoadEnabled: true,
349
- setAttachmentData: (data) => (attachmentData = data),
350
- createOrGetStorageService: async () =>
351
- // only the summary should be left to upload
352
- createProxyWithFailDefault({
353
- uploadSummaryWithContext: async () => Promise.resolve(uuid()),
354
- }),
355
- }));
356
- assert.strictEqual(attachmentData?.state, AttachState.Attached, "should be attached");
357
- assert.notStrictEqual(snapshot, undefined, "should have snapshot");
358
- });
359
- it("From AttachingDataWithoutBlobs", async () => {
360
- const initial = {
361
- state: AttachState.Attaching,
362
- blobs: "none",
363
- summary: emptySummary,
364
- };
365
- let attachmentData;
366
- const snapshot = await runRetriableAttachProcess(createProxyWithFailDefault({
367
- initialAttachmentData: initial,
368
- offlineLoadEnabled: true,
369
- setAttachmentData: (data) => (attachmentData = data),
370
- createOrGetStorageService: async (summary) => {
371
- assert.notStrictEqual(summary, undefined, "data.summary");
372
- return createProxyWithFailDefault();
373
- },
374
- }));
375
- assert.strictEqual(attachmentData?.state, AttachState.Attached, "should be attached");
376
- assert.notStrictEqual(snapshot, undefined, "should have snapshot");
377
- });
378
- });
379
- });
380
- //# sourceMappingURL=attachment.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"attachment.spec.js","sourceRoot":"","sources":["../../src/test/attachment.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 \"assert\";\nimport { AttachState } from \"@fluidframework/container-definitions\";\nimport { v4 as uuid } from \"uuid\";\nimport { SummaryType } from \"@fluidframework/protocol-definitions\";\nimport { stringToBuffer } from \"@fluid-internal/client-utils\";\nimport { IDocumentStorageService } from \"@fluidframework/driver-definitions\";\nimport {\n\tAttachProcessProps,\n\tAttachingDataWithBlobs,\n\tDetachedDataWithOutstandingBlobs,\n\trunRetriableAttachProcess,\n\tDetachedDefaultData,\n\tAttachmentData,\n\tAttachingDataWithoutBlobs,\n} from \"../attachment.js\";\nimport { combineAppAndProtocolSummary } from \"../utils.js\";\n\nconst emptySummary = combineAppAndProtocolSummary(\n\t{ tree: {}, type: SummaryType.Tree },\n\t{ tree: {}, type: SummaryType.Tree },\n);\n\ntype ObjectWithCallCounts<T extends Record<string, any>> = T &\n\tRecord<\"calls\", Record<keyof T, number>>;\n\nconst addCallCounts = <T extends Record<string, any>>(obj: T): ObjectWithCallCounts<T> => {\n\tconst calls = Object.keys(obj).reduce((pv, cv) => {\n\t\tpv[cv] = 0;\n\t\treturn pv;\n\t}, {}) as Record<keyof T, number>;\n\n\treturn new Proxy<ObjectWithCallCounts<T>>(obj as ObjectWithCallCounts<T>, {\n\t\tget: (t, p, r): any => {\n\t\t\tif (p === \"calls\") {\n\t\t\t\treturn calls;\n\t\t\t} else {\n\t\t\t\tcalls[p as keyof T]++;\n\t\t\t\treturn Reflect.get(t, p, r);\n\t\t\t}\n\t\t},\n\t});\n};\n\nconst createDetachStorage = (\n\tblobCount: number,\n): ObjectWithCallCounts<Exclude<AttachProcessProps[\"detachedBlobStorage\"], undefined>> => {\n\tconst blobs = new Map<string, ArrayBufferLike>(\n\t\tArray.from({ length: blobCount }).map((_, i) => [\n\t\t\ti.toString(),\n\t\t\tstringToBuffer(`${i}-content`, \"utf-8\"),\n\t\t]),\n\t);\n\n\treturn addCallCounts({\n\t\tget size() {\n\t\t\treturn blobs.size;\n\t\t},\n\t\tgetBlobIds() {\n\t\t\treturn [...blobs.keys()];\n\t\t},\n\t\tasync readBlob(id) {\n\t\t\tconst content = blobs.get(id);\n\t\t\tassert(content !== undefined, `no blob content for [${id}]`);\n\t\t\treturn content;\n\t\t},\n\t});\n};\n\nconst createProxyWithFailDefault = <T extends Record<string, any> | undefined>(\n\tpartial: Partial<T> = {},\n): T => {\n\treturn new Proxy(partial, {\n\t\tget: (t, p, r): any => {\n\t\t\tif (p in t) {\n\t\t\t\treturn Reflect.get(t, p, r);\n\t\t\t}\n\n\t\t\treturn new Proxy(\n\t\t\t\t{},\n\t\t\t\t{\n\t\t\t\t\tget: () => assert.fail(`unexpected call too ${p.toString()}`),\n\t\t\t\t},\n\t\t\t);\n\t\t},\n\t}) as T;\n};\n\ndescribe(\"runRetriableAttachProcess\", () => {\n\tdescribe(\"end to end process\", () => {\n\t\tit(\"From DetachedDefaultData without blobs or offline\", async () => {\n\t\t\tconst initial: DetachedDefaultData = {\n\t\t\t\tstate: AttachState.Detached,\n\t\t\t};\n\t\t\tlet attachmentData: AttachmentData | undefined;\n\t\t\tawait runRetriableAttachProcess({\n\t\t\t\tinitialAttachmentData: initial,\n\t\t\t\tofflineLoadEnabled: false,\n\t\t\t\tsetAttachmentData: (data) => (attachmentData = data),\n\t\t\t\tcreateAttachmentSummary: (redirectTable) => {\n\t\t\t\t\tassert.strictEqual(redirectTable, undefined, \"redirectTable\");\n\t\t\t\t\treturn emptySummary;\n\t\t\t\t},\n\t\t\t\tcreateOrGetStorageService: async () =>\n\t\t\t\t\tcreateProxyWithFailDefault<IDocumentStorageService>(),\n\t\t\t});\n\n\t\t\tassert.strictEqual(attachmentData?.state, AttachState.Attached, \"should be attached\");\n\t\t});\n\n\t\tit(\"From DetachedDefaultData with offline and without blobs\", async () => {\n\t\t\tconst initial: DetachedDefaultData = {\n\t\t\t\tstate: AttachState.Detached,\n\t\t\t};\n\t\t\tlet attachmentData: AttachmentData | undefined;\n\t\t\tconst snapshot = await runRetriableAttachProcess({\n\t\t\t\tinitialAttachmentData: initial,\n\t\t\t\tofflineLoadEnabled: true,\n\t\t\t\tsetAttachmentData: (data) => (attachmentData = data),\n\t\t\t\tcreateAttachmentSummary: (redirectTable) => {\n\t\t\t\t\tassert.strictEqual(redirectTable, undefined, \"redirectTable\");\n\t\t\t\t\treturn emptySummary;\n\t\t\t\t},\n\t\t\t\tcreateOrGetStorageService: async () => ({\n\t\t\t\t\tcreateBlob: async () => assert.fail(\"no blobs should be created\"),\n\t\t\t\t\tuploadSummaryWithContext: async () =>\n\t\t\t\t\t\tassert.fail(\"no summary should be uploaded outside of create\"),\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\tassert.strictEqual(attachmentData?.state, AttachState.Attached, \"should be attached\");\n\t\t\tassert.notStrictEqual(snapshot, undefined, \"should have snapshot\");\n\t\t});\n\n\t\tit(\"From DetachedDefaultData with blobs and without offline\", async () => {\n\t\t\tconst initial: DetachedDefaultData = {\n\t\t\t\tstate: AttachState.Detached,\n\t\t\t};\n\t\t\tlet attachmentData: AttachmentData | undefined;\n\t\t\tconst blobCount = 10;\n\t\t\tconst detachedBlobStorage = createDetachStorage(blobCount);\n\t\t\tconst storageAdapter = addCallCounts({\n\t\t\t\tcreateBlob: async () => Promise.resolve({ id: uuid() }),\n\t\t\t\tuploadSummaryWithContext: async () => Promise.resolve(uuid()),\n\t\t\t});\n\t\t\tawait runRetriableAttachProcess({\n\t\t\t\tinitialAttachmentData: initial,\n\t\t\t\tofflineLoadEnabled: false,\n\t\t\t\tsetAttachmentData: (data) => (attachmentData = data),\n\t\t\t\tcreateAttachmentSummary: (redirectTable) => {\n\t\t\t\t\tassert.strictEqual(redirectTable?.size, blobCount, \"redirectTable?.size\");\n\t\t\t\t\treturn emptySummary;\n\t\t\t\t},\n\t\t\t\tcreateOrGetStorageService: async () => storageAdapter,\n\t\t\t\tdetachedBlobStorage,\n\t\t\t});\n\n\t\t\t// expect every blob to read, and uploaded\n\t\t\tassert.strictEqual(\n\t\t\t\tdetachedBlobStorage.calls.readBlob,\n\t\t\t\tblobCount,\n\t\t\t\t\"detachedBlobStorage.calls.readBlob\",\n\t\t\t);\n\t\t\tassert.strictEqual(\n\t\t\t\tstorageAdapter.calls.createBlob,\n\t\t\t\tblobCount,\n\t\t\t\t\"storageAdapter.calls.createBlob\",\n\t\t\t);\n\n\t\t\t// after blobs are uploaded summary should be\n\t\t\tassert.strictEqual(\n\t\t\t\tstorageAdapter.calls.uploadSummaryWithContext,\n\t\t\t\t1,\n\t\t\t\t\"storageAdapter.calls.uploadSummaryWithContext\",\n\t\t\t);\n\n\t\t\tassert.strictEqual(attachmentData?.state, AttachState.Attached, \"should be attached\");\n\t\t});\n\n\t\tit(\"From DetachedDefaultData with zero blobs and without offline\", async () => {\n\t\t\tconst initial: DetachedDefaultData = {\n\t\t\t\tstate: AttachState.Detached,\n\t\t\t};\n\t\t\tlet attachmentData: AttachmentData | undefined;\n\t\t\tawait runRetriableAttachProcess({\n\t\t\t\tinitialAttachmentData: initial,\n\t\t\t\tofflineLoadEnabled: false,\n\t\t\t\tsetAttachmentData: (data) => (attachmentData = data),\n\t\t\t\tcreateAttachmentSummary: (redirectTable) => {\n\t\t\t\t\tassert.strictEqual(redirectTable, undefined, \"redirectTable\");\n\t\t\t\t\treturn emptySummary;\n\t\t\t\t},\n\t\t\t\tcreateOrGetStorageService: async () => createProxyWithFailDefault(),\n\t\t\t\t// we have blobs storage, but it is empty,\n\t\t\t\t// so it should be treat like there are no blobs\n\t\t\t\tdetachedBlobStorage: createProxyWithFailDefault<\n\t\t\t\t\tAttachProcessProps[\"detachedBlobStorage\"]\n\t\t\t\t>({ size: 0 }),\n\t\t\t});\n\n\t\t\tassert.strictEqual(attachmentData?.state, AttachState.Attached, \"should be attached\");\n\t\t});\n\t});\n\n\tdescribe(\"ends in intermediate state due to failure\", () => {\n\t\tit(\"From DetachedDefaultData without blobs with createAttachmentSummary failure\", async () => {\n\t\t\tconst initial: DetachedDefaultData = {\n\t\t\t\tstate: AttachState.Detached,\n\t\t\t};\n\t\t\tlet attachmentData: AttachmentData | undefined;\n\t\t\tconst error = new Error(\"createAttachmentSummary failure\");\n\t\t\ttry {\n\t\t\t\tawait runRetriableAttachProcess(\n\t\t\t\t\tcreateProxyWithFailDefault<AttachProcessProps>({\n\t\t\t\t\t\tinitialAttachmentData: initial,\n\t\t\t\t\t\tdetachedBlobStorage: undefined,\n\t\t\t\t\t\tcreateAttachmentSummary: () => {\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tassert.fail(\"failure expected\");\n\t\t\t} catch (e) {\n\t\t\t\tassert.deepStrictEqual(e, error);\n\t\t\t}\n\n\t\t\tassert.deepStrictEqual(\n\t\t\t\tattachmentData,\n\t\t\t\tundefined,\n\t\t\t\t\"attachment data shouldn't have been set\",\n\t\t\t);\n\t\t});\n\n\t\tit(\"From DetachedDefaultData without blobs getStorageService failure\", async () => {\n\t\t\tconst initial: DetachedDefaultData = {\n\t\t\t\tstate: AttachState.Detached,\n\t\t\t};\n\t\t\tlet attachmentData: AttachmentData | undefined;\n\t\t\tconst error = new Error(\"getStorageService failure\");\n\t\t\ttry {\n\t\t\t\tawait runRetriableAttachProcess(\n\t\t\t\t\tcreateProxyWithFailDefault<AttachProcessProps>({\n\t\t\t\t\t\tinitialAttachmentData: initial,\n\t\t\t\t\t\tsetAttachmentData: (data) => (attachmentData = data),\n\t\t\t\t\t\tcreateAttachmentSummary: () => emptySummary,\n\t\t\t\t\t\tdetachedBlobStorage: undefined,\n\t\t\t\t\t\tcreateOrGetStorageService: () => {\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tassert.fail(\"failure expected\");\n\t\t\t} catch (e) {\n\t\t\t\tassert.deepStrictEqual(e, error);\n\t\t\t}\n\n\t\t\tassert.deepStrictEqual<AttachingDataWithoutBlobs>(\n\t\t\t\tattachmentData,\n\t\t\t\t{\n\t\t\t\t\tstate: AttachState.Attaching,\n\t\t\t\t\tblobs: \"none\",\n\t\t\t\t\tsummary: emptySummary,\n\t\t\t\t},\n\t\t\t\t\"should have made it to attaching state\",\n\t\t\t);\n\t\t});\n\n\t\tit(\"From DetachedDefaultData with blobs with createBlob failure\", async () => {\n\t\t\tconst initial: DetachedDefaultData = {\n\t\t\t\tstate: AttachState.Detached,\n\t\t\t};\n\t\t\tlet attachmentData: AttachmentData | undefined;\n\t\t\tconst blobCount = 10;\n\t\t\tconst detachedBlobStorage = createDetachStorage(blobCount);\n\t\t\tconst error = new Error(\"createBlob failure\");\n\t\t\ttry {\n\t\t\t\tawait runRetriableAttachProcess({\n\t\t\t\t\tinitialAttachmentData: initial,\n\t\t\t\t\tofflineLoadEnabled: false,\n\t\t\t\t\tsetAttachmentData: (data) => (attachmentData = data),\n\t\t\t\t\tcreateAttachmentSummary: () => emptySummary,\n\t\t\t\t\tcreateOrGetStorageService: async () =>\n\t\t\t\t\t\tcreateProxyWithFailDefault<IDocumentStorageService>({\n\t\t\t\t\t\t\tcreateBlob: () => {\n\t\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\tdetachedBlobStorage,\n\t\t\t\t});\n\t\t\t\tassert.fail(\"failure expected\");\n\t\t\t} catch (e) {\n\t\t\t\tassert.deepStrictEqual(e, error);\n\t\t\t}\n\n\t\t\tassert.deepStrictEqual<DetachedDataWithOutstandingBlobs>(\n\t\t\t\tattachmentData,\n\t\t\t\t{\n\t\t\t\t\tstate: AttachState.Detached,\n\t\t\t\t\tblobs: \"outstanding\",\n\t\t\t\t\tredirectTable: new Map(),\n\t\t\t\t},\n\t\t\t\t\"should have made it to attaching state\",\n\t\t\t);\n\t\t});\n\n\t\tit(\"From DetachedDefaultData with blobs with createAttachmentSummary failure\", async () => {\n\t\t\tconst initial: DetachedDefaultData = {\n\t\t\t\tstate: AttachState.Detached,\n\t\t\t};\n\t\t\tlet attachmentData: AttachmentData | undefined;\n\t\t\tconst blobCount = 10;\n\t\t\tconst detachedBlobStorage = createDetachStorage(blobCount);\n\t\t\tconst error = new Error(\"createAttachmentSummary failure\");\n\t\t\ttry {\n\t\t\t\tawait runRetriableAttachProcess({\n\t\t\t\t\tinitialAttachmentData: initial,\n\t\t\t\t\tofflineLoadEnabled: false,\n\t\t\t\t\tsetAttachmentData: (data) => (attachmentData = data),\n\t\t\t\t\tcreateAttachmentSummary: () => {\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t},\n\t\t\t\t\tcreateOrGetStorageService: async () =>\n\t\t\t\t\t\tcreateProxyWithFailDefault<IDocumentStorageService>({\n\t\t\t\t\t\t\tcreateBlob: async () => Promise.resolve({ id: uuid() }),\n\t\t\t\t\t\t}),\n\t\t\t\t\tdetachedBlobStorage,\n\t\t\t\t});\n\t\t\t\tassert.fail(\"failure expected\");\n\t\t\t} catch (e) {\n\t\t\t\tassert.deepStrictEqual(e, error);\n\t\t\t}\n\n\t\t\tassert.deepStrictEqual<DetachedDataWithOutstandingBlobs>(\n\t\t\t\t// override redirectTable as it makes validation pain, and we have good coverage in other tests\n\t\t\t\t{\n\t\t\t\t\t...attachmentData,\n\t\t\t\t\tredirectTable:\n\t\t\t\t\t\tattachmentData && \"redirectTable\" in attachmentData ? new Map() : undefined,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tstate: AttachState.Detached,\n\t\t\t\t\tblobs: \"outstanding\",\n\t\t\t\t\tredirectTable: new Map(),\n\t\t\t\t},\n\t\t\t\t\"should have made it to attaching state\",\n\t\t\t);\n\t\t});\n\n\t\tit(\"From DetachedDefaultData with blobs with uploadSummaryWithContext failure\", async () => {\n\t\t\tconst initial: DetachedDefaultData = {\n\t\t\t\tstate: AttachState.Detached,\n\t\t\t};\n\t\t\tlet attachmentData: AttachmentData | undefined;\n\t\t\tconst blobCount = 10;\n\t\t\tconst detachedBlobStorage = createDetachStorage(blobCount);\n\t\t\tconst error = new Error(\"uploadSummaryWithContext failure\");\n\t\t\ttry {\n\t\t\t\tawait runRetriableAttachProcess({\n\t\t\t\t\tinitialAttachmentData: initial,\n\t\t\t\t\tofflineLoadEnabled: false,\n\t\t\t\t\tsetAttachmentData: (data) => (attachmentData = data),\n\t\t\t\t\tcreateAttachmentSummary: (redirectTable) => {\n\t\t\t\t\t\tassert.strictEqual(redirectTable?.size, 10, \"redirectTable?.size\");\n\t\t\t\t\t\treturn emptySummary;\n\t\t\t\t\t},\n\t\t\t\t\tcreateOrGetStorageService: async () => ({\n\t\t\t\t\t\tcreateBlob: async () => Promise.resolve({ id: uuid() }),\n\t\t\t\t\t\tuploadSummaryWithContext: () => {\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t\tdetachedBlobStorage,\n\t\t\t\t});\n\t\t\t\tassert.fail(\"failure expected\");\n\t\t\t} catch (e) {\n\t\t\t\tassert.deepStrictEqual(e, error);\n\t\t\t}\n\n\t\t\tassert.deepStrictEqual<AttachingDataWithBlobs>(\n\t\t\t\tattachmentData,\n\t\t\t\t{\n\t\t\t\t\tstate: AttachState.Attaching,\n\t\t\t\t\tblobs: \"done\",\n\t\t\t\t\tsummary: emptySummary,\n\t\t\t\t},\n\t\t\t\t\"should have made it to attaching state\",\n\t\t\t);\n\t\t});\n\t});\n\n\tdescribe(\"from intermediate state\", () => {\n\t\tit(\"From DetachedDataWithOutstandingBlobs\", async () => {\n\t\t\tconst initial: DetachedDataWithOutstandingBlobs = {\n\t\t\t\tstate: AttachState.Detached,\n\t\t\t\tblobs: \"outstanding\",\n\t\t\t\tredirectTable: new Map(),\n\t\t\t};\n\t\t\tlet attachmentData: AttachmentData | undefined;\n\t\t\tconst blobCount = 10;\n\t\t\tconst detachedBlobStorage = createDetachStorage(blobCount);\n\t\t\tconst storageAdapter = addCallCounts({\n\t\t\t\tcreateBlob: async () => Promise.resolve({ id: uuid() }),\n\t\t\t\tuploadSummaryWithContext: async () => Promise.resolve(uuid()),\n\t\t\t});\n\t\t\tawait runRetriableAttachProcess({\n\t\t\t\tinitialAttachmentData: initial,\n\t\t\t\tofflineLoadEnabled: false,\n\t\t\t\tsetAttachmentData: (data) => (attachmentData = data),\n\t\t\t\tcreateAttachmentSummary: (redirectTable) => {\n\t\t\t\t\tassert.strictEqual(redirectTable?.size, blobCount, \"redirectTable?.size\");\n\t\t\t\t\treturn emptySummary;\n\t\t\t\t},\n\t\t\t\tcreateOrGetStorageService: async () => storageAdapter,\n\t\t\t\tdetachedBlobStorage,\n\t\t\t});\n\n\t\t\t// expect every blob to read, and uploaded\n\t\t\tassert.strictEqual(initial.redirectTable.size, blobCount, \"initial.redirectTable.size\");\n\n\t\t\tassert.strictEqual(\n\t\t\t\tdetachedBlobStorage.calls.readBlob,\n\t\t\t\tblobCount,\n\t\t\t\t\"detachedBlobStorage.calls.readBlob\",\n\t\t\t);\n\t\t\tassert.strictEqual(\n\t\t\t\tstorageAdapter.calls.createBlob,\n\t\t\t\tblobCount,\n\t\t\t\t\"storageAdapter.calls.createBlob\",\n\t\t\t);\n\n\t\t\t// after blobs are uploaded summary should be\n\t\t\tassert.strictEqual(\n\t\t\t\tstorageAdapter.calls.uploadSummaryWithContext,\n\t\t\t\t1,\n\t\t\t\t\"storageAdapter.calls.uploadSummaryWithContext\",\n\t\t\t);\n\n\t\t\tassert.strictEqual(attachmentData?.state, AttachState.Attached, \"should be attached\");\n\t\t});\n\n\t\tit(\"From AttachingDataWithBlobs\", async () => {\n\t\t\tconst initial: AttachingDataWithBlobs = {\n\t\t\t\tstate: AttachState.Attaching,\n\t\t\t\tblobs: \"done\",\n\t\t\t\tsummary: emptySummary,\n\t\t\t};\n\t\t\tlet attachmentData: AttachmentData | undefined;\n\t\t\tconst snapshot = await runRetriableAttachProcess(\n\t\t\t\tcreateProxyWithFailDefault<AttachProcessProps>({\n\t\t\t\t\tinitialAttachmentData: initial,\n\t\t\t\t\tofflineLoadEnabled: true,\n\t\t\t\t\tsetAttachmentData: (data) => (attachmentData = data),\n\t\t\t\t\tcreateOrGetStorageService: async () =>\n\t\t\t\t\t\t// only the summary should be left to upload\n\t\t\t\t\t\tcreateProxyWithFailDefault<IDocumentStorageService>({\n\t\t\t\t\t\t\tuploadSummaryWithContext: async () => Promise.resolve(uuid()),\n\t\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t\t);\n\n\t\t\tassert.strictEqual(attachmentData?.state, AttachState.Attached, \"should be attached\");\n\t\t\tassert.notStrictEqual(snapshot, undefined, \"should have snapshot\");\n\t\t});\n\n\t\tit(\"From AttachingDataWithoutBlobs\", async () => {\n\t\t\tconst initial: AttachingDataWithoutBlobs = {\n\t\t\t\tstate: AttachState.Attaching,\n\t\t\t\tblobs: \"none\",\n\t\t\t\tsummary: emptySummary,\n\t\t\t};\n\t\t\tlet attachmentData: AttachmentData | undefined;\n\t\t\tconst snapshot = await runRetriableAttachProcess(\n\t\t\t\tcreateProxyWithFailDefault<AttachProcessProps>({\n\t\t\t\t\tinitialAttachmentData: initial,\n\t\t\t\t\tofflineLoadEnabled: true,\n\t\t\t\t\tsetAttachmentData: (data) => (attachmentData = data),\n\t\t\t\t\tcreateOrGetStorageService: async (summary) => {\n\t\t\t\t\t\tassert.notStrictEqual(summary, undefined, \"data.summary\");\n\t\t\t\t\t\treturn createProxyWithFailDefault();\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t);\n\n\t\t\tassert.strictEqual(attachmentData?.state, AttachState.Attached, \"should be attached\");\n\t\t\tassert.notStrictEqual(snapshot, undefined, \"should have snapshot\");\n\t\t});\n\t});\n});\n"]}
@@ -1,88 +0,0 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
- import { strict as assert } from "assert";
6
- import { TypedEventEmitter } from "@fluid-internal/client-utils";
7
- import { CatchUpMonitor } from "../catchUpMonitor.js";
8
- class MockDeltaManagerForCatchingUp extends TypedEventEmitter {
9
- constructor(lastSequenceNumber = 5, lastKnownSeqNumber = 10) {
10
- super();
11
- this.lastSequenceNumber = lastSequenceNumber;
12
- this.lastKnownSeqNumber = lastKnownSeqNumber;
13
- }
14
- /** Simulate processing op with the given sequence number, to trigger CatchUpMonitor */
15
- emitOpWithSequenceNumber(sequenceNumber) {
16
- this.emit("op", { sequenceNumber });
17
- }
18
- /** Trigger the CatchUpMonitor by emitting op with the target sequence number */
19
- emitOpToCatchUp() {
20
- this.emitOpWithSequenceNumber(this.lastKnownSeqNumber);
21
- }
22
- static create(sequenceNumbers = {}) {
23
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
24
- return new MockDeltaManagerForCatchingUp(sequenceNumbers.lastSequenceNumber, sequenceNumbers.lastKnownSeqNumber);
25
- }
26
- }
27
- describe("CatchUpMonitor", () => {
28
- let monitor;
29
- afterEach(() => {
30
- monitor?.dispose();
31
- });
32
- it("constructor validates DeltaManager sequence number coherency", async () => {
33
- const mockDeltaManager = MockDeltaManagerForCatchingUp.create({
34
- lastSequenceNumber: 20,
35
- lastKnownSeqNumber: 15, // Should be impossible in real world
36
- });
37
- assert.throws(() => new CatchUpMonitor(mockDeltaManager, () => { }), "Expect assert when DeltaManager in invalid state");
38
- });
39
- it("Emits caughtUp event when caught up to the point it was created", () => {
40
- const mockDeltaManager = MockDeltaManagerForCatchingUp.create({
41
- lastSequenceNumber: 10,
42
- lastKnownSeqNumber: 15,
43
- });
44
- let caughtUp = false;
45
- mockDeltaManager.lastKnownSeqNumber = 20;
46
- monitor = new CatchUpMonitor(mockDeltaManager, () => {
47
- caughtUp = true;
48
- });
49
- mockDeltaManager.lastKnownSeqNumber = 25; // Shouldn't change anything about the monitor
50
- mockDeltaManager.emitOpWithSequenceNumber(19); // Less than 20
51
- assert(!caughtUp, "Shouldn't be considered caught up yet");
52
- mockDeltaManager.emitOpWithSequenceNumber(21); // Greater than 20
53
- assert(caughtUp, "Should be considered caught up now");
54
- });
55
- it("Emits caught up immediately if last known/processed sequence numbers match", () => {
56
- const mockDeltaManager = MockDeltaManagerForCatchingUp.create({
57
- lastSequenceNumber: 10,
58
- lastKnownSeqNumber: 10,
59
- });
60
- let caughtUp = false;
61
- monitor = new CatchUpMonitor(mockDeltaManager, () => {
62
- caughtUp = true;
63
- });
64
- assert(caughtUp, "caughtUp should have fired immediately");
65
- });
66
- it("Only emits caughtUp once", () => {
67
- const mockDeltaManager = MockDeltaManagerForCatchingUp.create({
68
- lastSequenceNumber: 10,
69
- lastKnownSeqNumber: 15,
70
- });
71
- let caughtUpCount = 0;
72
- monitor = new CatchUpMonitor(mockDeltaManager, () => {
73
- ++caughtUpCount;
74
- });
75
- mockDeltaManager.emitOpWithSequenceNumber(15);
76
- assert.equal(caughtUpCount, 1, "caughtUp should have fired once");
77
- mockDeltaManager.emitOpWithSequenceNumber(16);
78
- assert.equal(caughtUpCount, 1, "caughtUp should have fired only once");
79
- });
80
- it("Dispose removes all listeners", () => {
81
- const mockDeltaManager = MockDeltaManagerForCatchingUp.create();
82
- monitor = new CatchUpMonitor(mockDeltaManager, () => { });
83
- monitor.dispose();
84
- assert(monitor.disposed, "dispose() should set disposed");
85
- assert.equal(mockDeltaManager.listenerCount("op"), 0, "CatchUpMonitor.dispose should remove listener on DeltaManager");
86
- });
87
- });
88
- //# sourceMappingURL=catchUpMonitor.spec.js.map