@fluidframework/container-loader 2.0.0-rc.2.0.2 → 2.0.0-rc.3.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 (246) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/api-report/container-loader.api.md +13 -13
  3. package/dist/attachment.d.ts +6 -9
  4. package/dist/attachment.d.ts.map +1 -1
  5. package/dist/attachment.js +5 -5
  6. package/dist/attachment.js.map +1 -1
  7. package/dist/audience.d.ts +1 -1
  8. package/dist/audience.d.ts.map +1 -1
  9. package/dist/audience.js +4 -4
  10. package/dist/audience.js.map +1 -1
  11. package/dist/catchUpMonitor.d.ts +1 -1
  12. package/dist/catchUpMonitor.d.ts.map +1 -1
  13. package/dist/catchUpMonitor.js +2 -2
  14. package/dist/catchUpMonitor.js.map +1 -1
  15. package/dist/connectionManager.d.ts +4 -4
  16. package/dist/connectionManager.d.ts.map +1 -1
  17. package/dist/connectionManager.js +48 -43
  18. package/dist/connectionManager.js.map +1 -1
  19. package/dist/connectionStateHandler.d.ts +3 -3
  20. package/dist/connectionStateHandler.d.ts.map +1 -1
  21. package/dist/connectionStateHandler.js +27 -27
  22. package/dist/connectionStateHandler.js.map +1 -1
  23. package/dist/container.d.ts +9 -46
  24. package/dist/container.d.ts.map +1 -1
  25. package/dist/container.js +105 -116
  26. package/dist/container.js.map +1 -1
  27. package/dist/containerContext.d.ts +19 -7
  28. package/dist/containerContext.d.ts.map +1 -1
  29. package/dist/containerContext.js +7 -2
  30. package/dist/containerContext.js.map +1 -1
  31. package/dist/containerStorageAdapter.d.ts +3 -3
  32. package/dist/containerStorageAdapter.d.ts.map +1 -1
  33. package/dist/containerStorageAdapter.js +6 -6
  34. package/dist/containerStorageAdapter.js.map +1 -1
  35. package/dist/contracts.d.ts +4 -3
  36. package/dist/contracts.d.ts.map +1 -1
  37. package/dist/contracts.js +2 -2
  38. package/dist/contracts.js.map +1 -1
  39. package/dist/debugLogger.d.ts +2 -1
  40. package/dist/debugLogger.d.ts.map +1 -1
  41. package/dist/debugLogger.js +4 -4
  42. package/dist/debugLogger.js.map +1 -1
  43. package/dist/deltaManager.d.ts +11 -7
  44. package/dist/deltaManager.d.ts.map +1 -1
  45. package/dist/deltaManager.js +53 -50
  46. package/dist/deltaManager.js.map +1 -1
  47. package/dist/deltaQueue.d.ts +1 -1
  48. package/dist/deltaQueue.d.ts.map +1 -1
  49. package/dist/deltaQueue.js +5 -5
  50. package/dist/deltaQueue.js.map +1 -1
  51. package/dist/error.d.ts +3 -2
  52. package/dist/error.d.ts.map +1 -1
  53. package/dist/error.js +5 -5
  54. package/dist/error.js.map +1 -1
  55. package/dist/legacy.d.ts +29 -0
  56. package/dist/loader.d.ts +4 -4
  57. package/dist/loader.d.ts.map +1 -1
  58. package/dist/loader.js +23 -23
  59. package/dist/loader.js.map +1 -1
  60. package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts +2 -2
  61. package/dist/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -1
  62. package/dist/location-redirection-utilities/resolveWithLocationRedirection.js +2 -2
  63. package/dist/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -1
  64. package/dist/noopHeuristic.d.ts +1 -1
  65. package/dist/noopHeuristic.d.ts.map +1 -1
  66. package/dist/noopHeuristic.js +6 -6
  67. package/dist/noopHeuristic.js.map +1 -1
  68. package/dist/packageVersion.d.ts +1 -1
  69. package/dist/packageVersion.js +1 -1
  70. package/dist/packageVersion.js.map +1 -1
  71. package/dist/protocol.d.ts +1 -1
  72. package/dist/protocol.d.ts.map +1 -1
  73. package/dist/protocol.js +2 -2
  74. package/dist/protocol.js.map +1 -1
  75. package/dist/protocolTreeDocumentStorageService.d.ts +4 -4
  76. package/dist/protocolTreeDocumentStorageService.d.ts.map +1 -1
  77. package/dist/protocolTreeDocumentStorageService.js.map +1 -1
  78. package/dist/public.d.ts +14 -0
  79. package/dist/quorum.d.ts +1 -1
  80. package/dist/quorum.d.ts.map +1 -1
  81. package/dist/quorum.js +4 -0
  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 +86 -16
  88. package/dist/serializedStateManager.d.ts.map +1 -1
  89. package/dist/serializedStateManager.js +182 -82
  90. package/dist/serializedStateManager.js.map +1 -1
  91. package/dist/utils.d.ts +24 -9
  92. package/dist/utils.d.ts.map +1 -1
  93. package/dist/utils.js +82 -25
  94. package/dist/utils.js.map +1 -1
  95. package/internal.d.ts +11 -0
  96. package/legacy.d.ts +11 -0
  97. package/lib/attachment.d.ts +6 -9
  98. package/lib/attachment.d.ts.map +1 -1
  99. package/lib/attachment.js +1 -1
  100. package/lib/attachment.js.map +1 -1
  101. package/lib/audience.d.ts +1 -1
  102. package/lib/audience.d.ts.map +1 -1
  103. package/lib/audience.js +1 -1
  104. package/lib/audience.js.map +1 -1
  105. package/lib/catchUpMonitor.d.ts +1 -1
  106. package/lib/catchUpMonitor.d.ts.map +1 -1
  107. package/lib/catchUpMonitor.js +1 -1
  108. package/lib/catchUpMonitor.js.map +1 -1
  109. package/lib/connectionManager.d.ts +4 -4
  110. package/lib/connectionManager.d.ts.map +1 -1
  111. package/lib/connectionManager.js +11 -6
  112. package/lib/connectionManager.js.map +1 -1
  113. package/lib/connectionStateHandler.d.ts +3 -3
  114. package/lib/connectionStateHandler.d.ts.map +1 -1
  115. package/lib/connectionStateHandler.js +2 -2
  116. package/lib/connectionStateHandler.js.map +1 -1
  117. package/lib/container.d.ts +9 -46
  118. package/lib/container.d.ts.map +1 -1
  119. package/lib/container.js +37 -48
  120. package/lib/container.js.map +1 -1
  121. package/lib/containerContext.d.ts +19 -7
  122. package/lib/containerContext.d.ts.map +1 -1
  123. package/lib/containerContext.js +7 -2
  124. package/lib/containerContext.js.map +1 -1
  125. package/lib/containerStorageAdapter.d.ts +3 -3
  126. package/lib/containerStorageAdapter.d.ts.map +1 -1
  127. package/lib/containerStorageAdapter.js +2 -2
  128. package/lib/containerStorageAdapter.js.map +1 -1
  129. package/lib/contracts.d.ts +4 -3
  130. package/lib/contracts.d.ts.map +1 -1
  131. package/lib/contracts.js +1 -1
  132. package/lib/contracts.js.map +1 -1
  133. package/lib/debugLogger.d.ts +2 -1
  134. package/lib/debugLogger.d.ts.map +1 -1
  135. package/lib/debugLogger.js +1 -1
  136. package/lib/debugLogger.js.map +1 -1
  137. package/lib/deltaManager.d.ts +11 -7
  138. package/lib/deltaManager.d.ts.map +1 -1
  139. package/lib/deltaManager.js +13 -10
  140. package/lib/deltaManager.js.map +1 -1
  141. package/lib/deltaQueue.d.ts +1 -1
  142. package/lib/deltaQueue.d.ts.map +1 -1
  143. package/lib/deltaQueue.js +2 -2
  144. package/lib/deltaQueue.js.map +1 -1
  145. package/lib/error.d.ts +3 -2
  146. package/lib/error.d.ts.map +1 -1
  147. package/lib/error.js +2 -2
  148. package/lib/error.js.map +1 -1
  149. package/lib/legacy.d.ts +29 -0
  150. package/lib/loader.d.ts +4 -4
  151. package/lib/loader.d.ts.map +1 -1
  152. package/lib/loader.js +4 -4
  153. package/lib/loader.js.map +1 -1
  154. package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.ts +2 -2
  155. package/lib/location-redirection-utilities/resolveWithLocationRedirection.d.ts.map +1 -1
  156. package/lib/location-redirection-utilities/resolveWithLocationRedirection.js +2 -2
  157. package/lib/location-redirection-utilities/resolveWithLocationRedirection.js.map +1 -1
  158. package/lib/noopHeuristic.d.ts +1 -1
  159. package/lib/noopHeuristic.d.ts.map +1 -1
  160. package/lib/noopHeuristic.js +2 -2
  161. package/lib/noopHeuristic.js.map +1 -1
  162. package/lib/packageVersion.d.ts +1 -1
  163. package/lib/packageVersion.js +1 -1
  164. package/lib/packageVersion.js.map +1 -1
  165. package/lib/protocol.d.ts +1 -1
  166. package/lib/protocol.d.ts.map +1 -1
  167. package/lib/protocol.js +1 -1
  168. package/lib/protocol.js.map +1 -1
  169. package/lib/protocolTreeDocumentStorageService.d.ts +4 -4
  170. package/lib/protocolTreeDocumentStorageService.d.ts.map +1 -1
  171. package/lib/protocolTreeDocumentStorageService.js.map +1 -1
  172. package/lib/public.d.ts +14 -0
  173. package/lib/quorum.d.ts +1 -1
  174. package/lib/quorum.d.ts.map +1 -1
  175. package/lib/quorum.js +4 -0
  176. package/lib/quorum.js.map +1 -1
  177. package/lib/retriableDocumentStorageService.d.ts +2 -2
  178. package/lib/retriableDocumentStorageService.d.ts.map +1 -1
  179. package/lib/retriableDocumentStorageService.js +3 -3
  180. package/lib/retriableDocumentStorageService.js.map +1 -1
  181. package/lib/serializedStateManager.d.ts +86 -16
  182. package/lib/serializedStateManager.d.ts.map +1 -1
  183. package/lib/serializedStateManager.js +174 -77
  184. package/lib/serializedStateManager.js.map +1 -1
  185. package/lib/utils.d.ts +24 -9
  186. package/lib/utils.d.ts.map +1 -1
  187. package/lib/utils.js +69 -15
  188. package/lib/utils.js.map +1 -1
  189. package/package.json +37 -58
  190. package/src/attachment.ts +10 -8
  191. package/src/audience.ts +3 -2
  192. package/src/catchUpMonitor.ts +2 -2
  193. package/src/connectionManager.ts +27 -20
  194. package/src/connectionStateHandler.ts +7 -7
  195. package/src/container.ts +90 -143
  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 +40 -30
  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 +2 -1
  210. package/src/retriableDocumentStorageService.ts +6 -5
  211. package/src/serializedStateManager.ts +299 -111
  212. package/src/utils.ts +103 -24
  213. package/api-extractor-cjs.json +0 -8
  214. package/dist/container-loader-alpha.d.ts +0 -275
  215. package/dist/container-loader-beta.d.ts +0 -101
  216. package/dist/container-loader-public.d.ts +0 -101
  217. package/dist/container-loader-untrimmed.d.ts +0 -331
  218. package/lib/container-loader-alpha.d.ts +0 -275
  219. package/lib/container-loader-beta.d.ts +0 -101
  220. package/lib/container-loader-public.d.ts +0 -101
  221. package/lib/container-loader-untrimmed.d.ts +0 -331
  222. package/lib/test/attachment.spec.js +0 -380
  223. package/lib/test/attachment.spec.js.map +0 -1
  224. package/lib/test/catchUpMonitor.spec.js +0 -88
  225. package/lib/test/catchUpMonitor.spec.js.map +0 -1
  226. package/lib/test/connectionManager.spec.js +0 -201
  227. package/lib/test/connectionManager.spec.js.map +0 -1
  228. package/lib/test/connectionStateHandler.spec.js +0 -555
  229. package/lib/test/connectionStateHandler.spec.js.map +0 -1
  230. package/lib/test/container.spec.js +0 -64
  231. package/lib/test/container.spec.js.map +0 -1
  232. package/lib/test/deltaManager.spec.js +0 -405
  233. package/lib/test/deltaManager.spec.js.map +0 -1
  234. package/lib/test/loader.spec.js +0 -212
  235. package/lib/test/loader.spec.js.map +0 -1
  236. package/lib/test/locationRedirectionTests.spec.js +0 -44
  237. package/lib/test/locationRedirectionTests.spec.js.map +0 -1
  238. package/lib/test/serializedStateManager.spec.js +0 -148
  239. package/lib/test/serializedStateManager.spec.js.map +0 -1
  240. package/lib/test/snapshotConversionTest.spec.js +0 -79
  241. package/lib/test/snapshotConversionTest.spec.js.map +0 -1
  242. package/lib/test/types/validateContainerLoaderPrevious.generated.js +0 -38
  243. package/lib/test/types/validateContainerLoaderPrevious.generated.js.map +0 -1
  244. package/lib/test/utils.spec.js +0 -31
  245. package/lib/test/utils.spec.js.map +0 -1
  246. /package/{dist → lib}/tsdoc-metadata.json +0 -0
@@ -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":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,IAAI,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAC;AACpE,OAAO,EAAE,EAAE,IAAI,IAAI,EAAE,MAAM,MAAM,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAE9D,OAAO,EAIN,yBAAyB,GAIzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;AAE3D,MAAM,YAAY,GAAG,4BAA4B,CAChD,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,EAAE,EACpC,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,EAAE,CACpC,CAAC;AAKF,MAAM,aAAa,GAAG,CAAgC,GAAM,EAA2B,EAAE;IACxF,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE;QAChD,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;QACX,OAAO,EAAE,CAAC;IACX,CAAC,EAAE,EAAE,CAA4B,CAAC;IAElC,OAAO,IAAI,KAAK,CAA0B,GAA8B,EAAE;QACzE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAO,EAAE;YACrB,IAAI,CAAC,KAAK,OAAO,EAAE;gBAClB,OAAO,KAAK,CAAC;aACb;iBAAM;gBACN,KAAK,CAAC,CAAY,CAAC,EAAE,CAAC;gBACtB,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;aAC5B;QACF,CAAC;KACD,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAC3B,SAAiB,EACqE,EAAE;IACxF,MAAM,KAAK,GAAG,IAAI,GAAG,CACpB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/C,CAAC,CAAC,QAAQ,EAAE;QACZ,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC;KACvC,CAAC,CACF,CAAC;IAEF,OAAO,aAAa,CAAC;QACpB,IAAI,IAAI;YACP,OAAO,KAAK,CAAC,IAAI,CAAC;QACnB,CAAC;QACD,UAAU;YACT,OAAO,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QAC1B,CAAC;QACD,KAAK,CAAC,QAAQ,CAAC,EAAE;YAChB,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC9B,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,wBAAwB,EAAE,GAAG,CAAC,CAAC;YAC7D,OAAO,OAAO,CAAC;QAChB,CAAC;KACD,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,0BAA0B,GAAG,CAClC,UAAsB,EAAE,EACpB,EAAE;IACN,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE;QACzB,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAO,EAAE;YACrB,IAAI,CAAC,IAAI,CAAC,EAAE;gBACX,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;aAC5B;YAED,OAAO,IAAI,KAAK,CACf,EAAE,EACF;gBACC,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC;aAC7D,CACD,CAAC;QACH,CAAC;KACD,CAAM,CAAC;AACT,CAAC,CAAC;AAEF,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IAC1C,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QACnC,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;YAClE,MAAM,OAAO,GAAwB;gBACpC,KAAK,EAAE,WAAW,CAAC,QAAQ;aAC3B,CAAC;YACF,IAAI,cAA0C,CAAC;YAC/C,MAAM,yBAAyB,CAAC;gBAC/B,qBAAqB,EAAE,OAAO;gBAC9B,kBAAkB,EAAE,KAAK;gBACzB,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,cAAc,GAAG,IAAI,CAAC;gBACpD,uBAAuB,EAAE,CAAC,aAAa,EAAE,EAAE;oBAC1C,MAAM,CAAC,WAAW,CAAC,aAAa,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;oBAC9D,OAAO,YAAY,CAAC;gBACrB,CAAC;gBACD,yBAAyB,EAAE,KAAK,IAAI,EAAE,CACrC,0BAA0B,EAA2B;aACtD,CAAC,CAAC;YAEH,MAAM,CAAC,WAAW,CAAC,cAAc,EAAE,KAAK,EAAE,WAAW,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;QACvF,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;YACxE,MAAM,OAAO,GAAwB;gBACpC,KAAK,EAAE,WAAW,CAAC,QAAQ;aAC3B,CAAC;YACF,IAAI,cAA0C,CAAC;YAC/C,MAAM,QAAQ,GAAG,MAAM,yBAAyB,CAAC;gBAChD,qBAAqB,EAAE,OAAO;gBAC9B,kBAAkB,EAAE,IAAI;gBACxB,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,cAAc,GAAG,IAAI,CAAC;gBACpD,uBAAuB,EAAE,CAAC,aAAa,EAAE,EAAE;oBAC1C,MAAM,CAAC,WAAW,CAAC,aAAa,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;oBAC9D,OAAO,YAAY,CAAC;gBACrB,CAAC;gBACD,yBAAyB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;oBACvC,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC;oBACjE,wBAAwB,EAAE,KAAK,IAAI,EAAE,CACpC,MAAM,CAAC,IAAI,CAAC,iDAAiD,CAAC;iBAC/D,CAAC;aACF,CAAC,CAAC;YAEH,MAAM,CAAC,WAAW,CAAC,cAAc,EAAE,KAAK,EAAE,WAAW,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;YACtF,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,SAAS,EAAE,sBAAsB,CAAC,CAAC;QACpE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;YACxE,MAAM,OAAO,GAAwB;gBACpC,KAAK,EAAE,WAAW,CAAC,QAAQ;aAC3B,CAAC;YACF,IAAI,cAA0C,CAAC;YAC/C,MAAM,SAAS,GAAG,EAAE,CAAC;YACrB,MAAM,mBAAmB,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;YAC3D,MAAM,cAAc,GAAG,aAAa,CAAC;gBACpC,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC;gBACvD,wBAAwB,EAAE,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;aAC7D,CAAC,CAAC;YACH,MAAM,yBAAyB,CAAC;gBAC/B,qBAAqB,EAAE,OAAO;gBAC9B,kBAAkB,EAAE,KAAK;gBACzB,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,cAAc,GAAG,IAAI,CAAC;gBACpD,uBAAuB,EAAE,CAAC,aAAa,EAAE,EAAE;oBAC1C,MAAM,CAAC,WAAW,CAAC,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE,qBAAqB,CAAC,CAAC;oBAC1E,OAAO,YAAY,CAAC;gBACrB,CAAC;gBACD,yBAAyB,EAAE,KAAK,IAAI,EAAE,CAAC,cAAc;gBACrD,mBAAmB;aACnB,CAAC,CAAC;YAEH,0CAA0C;YAC1C,MAAM,CAAC,WAAW,CACjB,mBAAmB,CAAC,KAAK,CAAC,QAAQ,EAClC,SAAS,EACT,oCAAoC,CACpC,CAAC;YACF,MAAM,CAAC,WAAW,CACjB,cAAc,CAAC,KAAK,CAAC,UAAU,EAC/B,SAAS,EACT,iCAAiC,CACjC,CAAC;YAEF,6CAA6C;YAC7C,MAAM,CAAC,WAAW,CACjB,cAAc,CAAC,KAAK,CAAC,wBAAwB,EAC7C,CAAC,EACD,+CAA+C,CAC/C,CAAC;YAEF,MAAM,CAAC,WAAW,CAAC,cAAc,EAAE,KAAK,EAAE,WAAW,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;QACvF,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;YAC7E,MAAM,OAAO,GAAwB;gBACpC,KAAK,EAAE,WAAW,CAAC,QAAQ;aAC3B,CAAC;YACF,IAAI,cAA0C,CAAC;YAC/C,MAAM,yBAAyB,CAAC;gBAC/B,qBAAqB,EAAE,OAAO;gBAC9B,kBAAkB,EAAE,KAAK;gBACzB,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,cAAc,GAAG,IAAI,CAAC;gBACpD,uBAAuB,EAAE,CAAC,aAAa,EAAE,EAAE;oBAC1C,MAAM,CAAC,WAAW,CAAC,aAAa,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;oBAC9D,OAAO,YAAY,CAAC;gBACrB,CAAC;gBACD,yBAAyB,EAAE,KAAK,IAAI,EAAE,CAAC,0BAA0B,EAAE;gBACnE,0CAA0C;gBAC1C,gDAAgD;gBAChD,mBAAmB,EAAE,0BAA0B,CAE7C,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aACd,CAAC,CAAC;YAEH,MAAM,CAAC,WAAW,CAAC,cAAc,EAAE,KAAK,EAAE,WAAW,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;QACvF,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,2CAA2C,EAAE,GAAG,EAAE;QAC1D,EAAE,CAAC,6EAA6E,EAAE,KAAK,IAAI,EAAE;YAC5F,MAAM,OAAO,GAAwB;gBACpC,KAAK,EAAE,WAAW,CAAC,QAAQ;aAC3B,CAAC;YACF,IAAI,cAA0C,CAAC;YAC/C,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;YAC3D,IAAI;gBACH,MAAM,yBAAyB,CAC9B,0BAA0B,CAAqB;oBAC9C,qBAAqB,EAAE,OAAO;oBAC9B,mBAAmB,EAAE,SAAS;oBAC9B,uBAAuB,EAAE,GAAG,EAAE;wBAC7B,MAAM,KAAK,CAAC;oBACb,CAAC;iBACD,CAAC,CACF,CAAC;gBACF,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;aAChC;YAAC,OAAO,CAAC,EAAE;gBACX,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;aACjC;YAED,MAAM,CAAC,eAAe,CACrB,cAAc,EACd,SAAS,EACT,yCAAyC,CACzC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;YACjF,MAAM,OAAO,GAAwB;gBACpC,KAAK,EAAE,WAAW,CAAC,QAAQ;aAC3B,CAAC;YACF,IAAI,cAA0C,CAAC;YAC/C,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;YACrD,IAAI;gBACH,MAAM,yBAAyB,CAC9B,0BAA0B,CAAqB;oBAC9C,qBAAqB,EAAE,OAAO;oBAC9B,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,cAAc,GAAG,IAAI,CAAC;oBACpD,uBAAuB,EAAE,GAAG,EAAE,CAAC,YAAY;oBAC3C,mBAAmB,EAAE,SAAS;oBAC9B,yBAAyB,EAAE,GAAG,EAAE;wBAC/B,MAAM,KAAK,CAAC;oBACb,CAAC;iBACD,CAAC,CACF,CAAC;gBACF,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;aAChC;YAAC,OAAO,CAAC,EAAE;gBACX,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;aACjC;YAED,MAAM,CAAC,eAAe,CACrB,cAAc,EACd;gBACC,KAAK,EAAE,WAAW,CAAC,SAAS;gBAC5B,KAAK,EAAE,MAAM;gBACb,OAAO,EAAE,YAAY;aACrB,EACD,wCAAwC,CACxC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;YAC5E,MAAM,OAAO,GAAwB;gBACpC,KAAK,EAAE,WAAW,CAAC,QAAQ;aAC3B,CAAC;YACF,IAAI,cAA0C,CAAC;YAC/C,MAAM,SAAS,GAAG,EAAE,CAAC;YACrB,MAAM,mBAAmB,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;YAC3D,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;YAC9C,IAAI;gBACH,MAAM,yBAAyB,CAAC;oBAC/B,qBAAqB,EAAE,OAAO;oBAC9B,kBAAkB,EAAE,KAAK;oBACzB,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,cAAc,GAAG,IAAI,CAAC;oBACpD,uBAAuB,EAAE,GAAG,EAAE,CAAC,YAAY;oBAC3C,yBAAyB,EAAE,KAAK,IAAI,EAAE,CACrC,0BAA0B,CAA0B;wBACnD,UAAU,EAAE,GAAG,EAAE;4BAChB,MAAM,KAAK,CAAC;wBACb,CAAC;qBACD,CAAC;oBACH,mBAAmB;iBACnB,CAAC,CAAC;gBACH,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;aAChC;YAAC,OAAO,CAAC,EAAE;gBACX,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;aACjC;YAED,MAAM,CAAC,eAAe,CACrB,cAAc,EACd;gBACC,KAAK,EAAE,WAAW,CAAC,QAAQ;gBAC3B,KAAK,EAAE,aAAa;gBACpB,aAAa,EAAE,IAAI,GAAG,EAAE;aACxB,EACD,wCAAwC,CACxC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;YACzF,MAAM,OAAO,GAAwB;gBACpC,KAAK,EAAE,WAAW,CAAC,QAAQ;aAC3B,CAAC;YACF,IAAI,cAA0C,CAAC;YAC/C,MAAM,SAAS,GAAG,EAAE,CAAC;YACrB,MAAM,mBAAmB,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;YAC3D,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;YAC3D,IAAI;gBACH,MAAM,yBAAyB,CAAC;oBAC/B,qBAAqB,EAAE,OAAO;oBAC9B,kBAAkB,EAAE,KAAK;oBACzB,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,cAAc,GAAG,IAAI,CAAC;oBACpD,uBAAuB,EAAE,GAAG,EAAE;wBAC7B,MAAM,KAAK,CAAC;oBACb,CAAC;oBACD,yBAAyB,EAAE,KAAK,IAAI,EAAE,CACrC,0BAA0B,CAA0B;wBACnD,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC;qBACvD,CAAC;oBACH,mBAAmB;iBACnB,CAAC,CAAC;gBACH,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;aAChC;YAAC,OAAO,CAAC,EAAE;gBACX,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;aACjC;YAED,MAAM,CAAC,eAAe;YACrB,+FAA+F;YAC/F;gBACC,GAAG,cAAc;gBACjB,aAAa,EACZ,cAAc,IAAI,eAAe,IAAI,cAAc,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS;aAC5E,EACD;gBACC,KAAK,EAAE,WAAW,CAAC,QAAQ;gBAC3B,KAAK,EAAE,aAAa;gBACpB,aAAa,EAAE,IAAI,GAAG,EAAE;aACxB,EACD,wCAAwC,CACxC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2EAA2E,EAAE,KAAK,IAAI,EAAE;YAC1F,MAAM,OAAO,GAAwB;gBACpC,KAAK,EAAE,WAAW,CAAC,QAAQ;aAC3B,CAAC;YACF,IAAI,cAA0C,CAAC;YAC/C,MAAM,SAAS,GAAG,EAAE,CAAC;YACrB,MAAM,mBAAmB,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;YAC3D,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;YAC5D,IAAI;gBACH,MAAM,yBAAyB,CAAC;oBAC/B,qBAAqB,EAAE,OAAO;oBAC9B,kBAAkB,EAAE,KAAK;oBACzB,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,cAAc,GAAG,IAAI,CAAC;oBACpD,uBAAuB,EAAE,CAAC,aAAa,EAAE,EAAE;wBAC1C,MAAM,CAAC,WAAW,CAAC,aAAa,EAAE,IAAI,EAAE,EAAE,EAAE,qBAAqB,CAAC,CAAC;wBACnE,OAAO,YAAY,CAAC;oBACrB,CAAC;oBACD,yBAAyB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;wBACvC,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC;wBACvD,wBAAwB,EAAE,GAAG,EAAE;4BAC9B,MAAM,KAAK,CAAC;wBACb,CAAC;qBACD,CAAC;oBACF,mBAAmB;iBACnB,CAAC,CAAC;gBACH,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;aAChC;YAAC,OAAO,CAAC,EAAE;gBACX,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;aACjC;YAED,MAAM,CAAC,eAAe,CACrB,cAAc,EACd;gBACC,KAAK,EAAE,WAAW,CAAC,SAAS;gBAC5B,KAAK,EAAE,MAAM;gBACb,OAAO,EAAE,YAAY;aACrB,EACD,wCAAwC,CACxC,CAAC;QACH,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACxC,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;YACtD,MAAM,OAAO,GAAqC;gBACjD,KAAK,EAAE,WAAW,CAAC,QAAQ;gBAC3B,KAAK,EAAE,aAAa;gBACpB,aAAa,EAAE,IAAI,GAAG,EAAE;aACxB,CAAC;YACF,IAAI,cAA0C,CAAC;YAC/C,MAAM,SAAS,GAAG,EAAE,CAAC;YACrB,MAAM,mBAAmB,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;YAC3D,MAAM,cAAc,GAAG,aAAa,CAAC;gBACpC,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC;gBACvD,wBAAwB,EAAE,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;aAC7D,CAAC,CAAC;YACH,MAAM,yBAAyB,CAAC;gBAC/B,qBAAqB,EAAE,OAAO;gBAC9B,kBAAkB,EAAE,KAAK;gBACzB,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,cAAc,GAAG,IAAI,CAAC;gBACpD,uBAAuB,EAAE,CAAC,aAAa,EAAE,EAAE;oBAC1C,MAAM,CAAC,WAAW,CAAC,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE,qBAAqB,CAAC,CAAC;oBAC1E,OAAO,YAAY,CAAC;gBACrB,CAAC;gBACD,yBAAyB,EAAE,KAAK,IAAI,EAAE,CAAC,cAAc;gBACrD,mBAAmB;aACnB,CAAC,CAAC;YAEH,0CAA0C;YAC1C,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,4BAA4B,CAAC,CAAC;YAExF,MAAM,CAAC,WAAW,CACjB,mBAAmB,CAAC,KAAK,CAAC,QAAQ,EAClC,SAAS,EACT,oCAAoC,CACpC,CAAC;YACF,MAAM,CAAC,WAAW,CACjB,cAAc,CAAC,KAAK,CAAC,UAAU,EAC/B,SAAS,EACT,iCAAiC,CACjC,CAAC;YAEF,6CAA6C;YAC7C,MAAM,CAAC,WAAW,CACjB,cAAc,CAAC,KAAK,CAAC,wBAAwB,EAC7C,CAAC,EACD,+CAA+C,CAC/C,CAAC;YAEF,MAAM,CAAC,WAAW,CAAC,cAAc,EAAE,KAAK,EAAE,WAAW,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;QACvF,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;YAC5C,MAAM,OAAO,GAA2B;gBACvC,KAAK,EAAE,WAAW,CAAC,SAAS;gBAC5B,KAAK,EAAE,MAAM;gBACb,OAAO,EAAE,YAAY;aACrB,CAAC;YACF,IAAI,cAA0C,CAAC;YAC/C,MAAM,QAAQ,GAAG,MAAM,yBAAyB,CAC/C,0BAA0B,CAAqB;gBAC9C,qBAAqB,EAAE,OAAO;gBAC9B,kBAAkB,EAAE,IAAI;gBACxB,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,cAAc,GAAG,IAAI,CAAC;gBACpD,yBAAyB,EAAE,KAAK,IAAI,EAAE;gBACrC,4CAA4C;gBAC5C,0BAA0B,CAA0B;oBACnD,wBAAwB,EAAE,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;iBAC7D,CAAC;aACH,CAAC,CACF,CAAC;YAEF,MAAM,CAAC,WAAW,CAAC,cAAc,EAAE,KAAK,EAAE,WAAW,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;YACtF,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,SAAS,EAAE,sBAAsB,CAAC,CAAC;QACpE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;YAC/C,MAAM,OAAO,GAA8B;gBAC1C,KAAK,EAAE,WAAW,CAAC,SAAS;gBAC5B,KAAK,EAAE,MAAM;gBACb,OAAO,EAAE,YAAY;aACrB,CAAC;YACF,IAAI,cAA0C,CAAC;YAC/C,MAAM,QAAQ,GAAG,MAAM,yBAAyB,CAC/C,0BAA0B,CAAqB;gBAC9C,qBAAqB,EAAE,OAAO;gBAC9B,kBAAkB,EAAE,IAAI;gBACxB,iBAAiB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,cAAc,GAAG,IAAI,CAAC;gBACpD,yBAAyB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;oBAC5C,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;oBAC1D,OAAO,0BAA0B,EAAE,CAAC;gBACrC,CAAC;aACD,CAAC,CACF,CAAC;YAEF,MAAM,CAAC,WAAW,CAAC,cAAc,EAAE,KAAK,EAAE,WAAW,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;YACtF,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,SAAS,EAAE,sBAAsB,CAAC,CAAC;QACpE,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC","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
@@ -1 +0,0 @@
1
- {"version":3,"file":"catchUpMonitor.spec.js","sourceRoot":"","sources":["../../src/test/catchUpMonitor.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 { IDeltaManager, IDeltaManagerEvents } from \"@fluidframework/container-definitions\";\nimport { TypedEventEmitter } from \"@fluid-internal/client-utils\";\nimport { CatchUpMonitor } from \"../catchUpMonitor.js\";\n\nclass MockDeltaManagerForCatchingUp\n\textends TypedEventEmitter<IDeltaManagerEvents>\n\timplements Pick<IDeltaManager<any, any>, \"lastSequenceNumber\" | \"lastKnownSeqNumber\">\n{\n\tconstructor(\n\t\tpublic lastSequenceNumber: number = 5,\n\t\tpublic lastKnownSeqNumber: number = 10,\n\t) {\n\t\tsuper();\n\t}\n\n\t/** Simulate processing op with the given sequence number, to trigger CatchUpMonitor */\n\temitOpWithSequenceNumber(sequenceNumber: number) {\n\t\tthis.emit(\"op\", { sequenceNumber });\n\t}\n\n\t/** Trigger the CatchUpMonitor by emitting op with the target sequence number */\n\temitOpToCatchUp() {\n\t\tthis.emitOpWithSequenceNumber(this.lastKnownSeqNumber);\n\t}\n\n\tstatic create(\n\t\tsequenceNumbers: {\n\t\t\tlastSequenceNumber?: number;\n\t\t\tlastKnownSeqNumber?: number;\n\t\t} = {},\n\t): MockDeltaManagerForCatchingUp & IDeltaManager<any, any> {\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-return\n\t\treturn new MockDeltaManagerForCatchingUp(\n\t\t\tsequenceNumbers.lastSequenceNumber,\n\t\t\tsequenceNumbers.lastKnownSeqNumber,\n\t\t) as any;\n\t}\n}\n\ndescribe(\"CatchUpMonitor\", () => {\n\tlet monitor: CatchUpMonitor;\n\n\tafterEach(() => {\n\t\tmonitor?.dispose();\n\t});\n\n\tit(\"constructor validates DeltaManager sequence number coherency\", async () => {\n\t\tconst mockDeltaManager = MockDeltaManagerForCatchingUp.create({\n\t\t\tlastSequenceNumber: 20,\n\t\t\tlastKnownSeqNumber: 15, // Should be impossible in real world\n\t\t});\n\n\t\tassert.throws(\n\t\t\t() => new CatchUpMonitor(mockDeltaManager, () => {}),\n\t\t\t\"Expect assert when DeltaManager in invalid state\",\n\t\t);\n\t});\n\n\tit(\"Emits caughtUp event when caught up to the point it was created\", () => {\n\t\tconst mockDeltaManager = MockDeltaManagerForCatchingUp.create({\n\t\t\tlastSequenceNumber: 10,\n\t\t\tlastKnownSeqNumber: 15,\n\t\t});\n\t\tlet caughtUp = false;\n\n\t\tmockDeltaManager.lastKnownSeqNumber = 20;\n\t\tmonitor = new CatchUpMonitor(mockDeltaManager, () => {\n\t\t\tcaughtUp = true;\n\t\t});\n\t\tmockDeltaManager.lastKnownSeqNumber = 25; // Shouldn't change anything about the monitor\n\n\t\tmockDeltaManager.emitOpWithSequenceNumber(19); // Less than 20\n\t\tassert(!caughtUp, \"Shouldn't be considered caught up yet\");\n\t\tmockDeltaManager.emitOpWithSequenceNumber(21); // Greater than 20\n\t\tassert(caughtUp, \"Should be considered caught up now\");\n\t});\n\n\tit(\"Emits caught up immediately if last known/processed sequence numbers match\", () => {\n\t\tconst mockDeltaManager = MockDeltaManagerForCatchingUp.create({\n\t\t\tlastSequenceNumber: 10,\n\t\t\tlastKnownSeqNumber: 10,\n\t\t});\n\t\tlet caughtUp = false;\n\n\t\tmonitor = new CatchUpMonitor(mockDeltaManager, () => {\n\t\t\tcaughtUp = true;\n\t\t});\n\n\t\tassert(caughtUp, \"caughtUp should have fired immediately\");\n\t});\n\n\tit(\"Only emits caughtUp once\", () => {\n\t\tconst mockDeltaManager = MockDeltaManagerForCatchingUp.create({\n\t\t\tlastSequenceNumber: 10,\n\t\t\tlastKnownSeqNumber: 15,\n\t\t});\n\t\tlet caughtUpCount = 0;\n\n\t\tmonitor = new CatchUpMonitor(mockDeltaManager, () => {\n\t\t\t++caughtUpCount;\n\t\t});\n\n\t\tmockDeltaManager.emitOpWithSequenceNumber(15);\n\t\tassert.equal(caughtUpCount, 1, \"caughtUp should have fired once\");\n\t\tmockDeltaManager.emitOpWithSequenceNumber(16);\n\t\tassert.equal(caughtUpCount, 1, \"caughtUp should have fired only once\");\n\t});\n\n\tit(\"Dispose removes all listeners\", () => {\n\t\tconst mockDeltaManager = MockDeltaManagerForCatchingUp.create();\n\t\tmonitor = new CatchUpMonitor(mockDeltaManager, () => {});\n\n\t\tmonitor.dispose();\n\n\t\tassert(monitor.disposed, \"dispose() should set disposed\");\n\t\tassert.equal(\n\t\t\tmockDeltaManager.listenerCount(\"op\"),\n\t\t\t0,\n\t\t\t\"CatchUpMonitor.dispose should remove listener on DeltaManager\",\n\t\t);\n\t});\n});\n"]}