@fluidframework/container-runtime 2.0.0-dev-rc.3.0.0.250606 → 2.0.0-dev-rc.3.0.0.254274

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 (486) hide show
  1. package/api-report/container-runtime.api.md +35 -34
  2. package/dist/batchTracker.d.ts.map +1 -1
  3. package/dist/batchTracker.js +4 -4
  4. package/dist/batchTracker.js.map +1 -1
  5. package/dist/blobManager.d.ts +31 -23
  6. package/dist/blobManager.d.ts.map +1 -1
  7. package/dist/blobManager.js +81 -99
  8. package/dist/blobManager.js.map +1 -1
  9. package/dist/channelCollection.d.ts +4 -2
  10. package/dist/channelCollection.d.ts.map +1 -1
  11. package/dist/channelCollection.js +75 -72
  12. package/dist/channelCollection.js.map +1 -1
  13. package/dist/connectionTelemetry.d.ts +1 -1
  14. package/dist/connectionTelemetry.d.ts.map +1 -1
  15. package/dist/connectionTelemetry.js +16 -16
  16. package/dist/connectionTelemetry.js.map +1 -1
  17. package/dist/container-runtime-alpha.d.ts +64 -36
  18. package/dist/container-runtime-beta.d.ts +28 -28
  19. package/dist/container-runtime-public.d.ts +28 -28
  20. package/dist/container-runtime-untrimmed.d.ts +68 -39
  21. package/dist/containerHandleContext.d.ts.map +1 -1
  22. package/dist/containerHandleContext.js +2 -2
  23. package/dist/containerHandleContext.js.map +1 -1
  24. package/dist/containerRuntime.d.ts +12 -8
  25. package/dist/containerRuntime.d.ts.map +1 -1
  26. package/dist/containerRuntime.js +197 -162
  27. package/dist/containerRuntime.js.map +1 -1
  28. package/dist/dataStore.d.ts +1 -1
  29. package/dist/dataStore.d.ts.map +1 -1
  30. package/dist/dataStore.js +7 -7
  31. package/dist/dataStore.js.map +1 -1
  32. package/dist/dataStoreContext.d.ts +9 -9
  33. package/dist/dataStoreContext.d.ts.map +1 -1
  34. package/dist/dataStoreContext.js +72 -62
  35. package/dist/dataStoreContext.js.map +1 -1
  36. package/dist/dataStoreContexts.d.ts.map +1 -1
  37. package/dist/dataStoreContexts.js +11 -11
  38. package/dist/dataStoreContexts.js.map +1 -1
  39. package/dist/dataStoreRegistry.d.ts +1 -1
  40. package/dist/dataStoreRegistry.d.ts.map +1 -1
  41. package/dist/dataStoreRegistry.js +2 -2
  42. package/dist/dataStoreRegistry.js.map +1 -1
  43. package/dist/deltaManagerSummarizerProxy.d.ts +1 -1
  44. package/dist/deltaManagerSummarizerProxy.d.ts.map +1 -1
  45. package/dist/deltaManagerSummarizerProxy.js.map +1 -1
  46. package/dist/deltaScheduler.d.ts.map +1 -1
  47. package/dist/deltaScheduler.js +6 -6
  48. package/dist/deltaScheduler.js.map +1 -1
  49. package/dist/error.d.ts +1 -1
  50. package/dist/error.d.ts.map +1 -1
  51. package/dist/error.js +4 -4
  52. package/dist/error.js.map +1 -1
  53. package/dist/gc/garbageCollection.d.ts +2 -1
  54. package/dist/gc/garbageCollection.d.ts.map +1 -1
  55. package/dist/gc/garbageCollection.js +20 -20
  56. package/dist/gc/garbageCollection.js.map +1 -1
  57. package/dist/gc/gcConfigs.d.ts +1 -1
  58. package/dist/gc/gcConfigs.d.ts.map +1 -1
  59. package/dist/gc/gcConfigs.js +4 -5
  60. package/dist/gc/gcConfigs.js.map +1 -1
  61. package/dist/gc/gcDefinitions.d.ts +3 -2
  62. package/dist/gc/gcDefinitions.d.ts.map +1 -1
  63. package/dist/gc/gcDefinitions.js.map +1 -1
  64. package/dist/gc/gcHelpers.d.ts +5 -1
  65. package/dist/gc/gcHelpers.d.ts.map +1 -1
  66. package/dist/gc/gcHelpers.js +21 -12
  67. package/dist/gc/gcHelpers.js.map +1 -1
  68. package/dist/gc/gcSummaryStateTracker.d.ts +1 -1
  69. package/dist/gc/gcSummaryStateTracker.d.ts.map +1 -1
  70. package/dist/gc/gcSummaryStateTracker.js +11 -11
  71. package/dist/gc/gcSummaryStateTracker.js.map +1 -1
  72. package/dist/gc/gcTelemetry.d.ts +2 -1
  73. package/dist/gc/gcTelemetry.d.ts.map +1 -1
  74. package/dist/gc/gcTelemetry.js +11 -9
  75. package/dist/gc/gcTelemetry.js.map +1 -1
  76. package/dist/gc/gcUnreferencedStateTracker.d.ts.map +1 -1
  77. package/dist/gc/gcUnreferencedStateTracker.js +6 -6
  78. package/dist/gc/gcUnreferencedStateTracker.js.map +1 -1
  79. package/dist/gc/index.d.ts +1 -1
  80. package/dist/gc/index.d.ts.map +1 -1
  81. package/dist/gc/index.js +2 -1
  82. package/dist/gc/index.js.map +1 -1
  83. package/dist/messageTypes.d.ts +2 -2
  84. package/dist/messageTypes.d.ts.map +1 -1
  85. package/dist/messageTypes.js.map +1 -1
  86. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  87. package/dist/opLifecycle/batchManager.js.map +1 -1
  88. package/dist/opLifecycle/definitions.d.ts +1 -1
  89. package/dist/opLifecycle/definitions.d.ts.map +1 -1
  90. package/dist/opLifecycle/definitions.js.map +1 -1
  91. package/dist/opLifecycle/opCompressor.d.ts.map +1 -1
  92. package/dist/opLifecycle/opCompressor.js +5 -5
  93. package/dist/opLifecycle/opCompressor.js.map +1 -1
  94. package/dist/opLifecycle/opDecompressor.d.ts.map +1 -1
  95. package/dist/opLifecycle/opDecompressor.js +12 -12
  96. package/dist/opLifecycle/opDecompressor.js.map +1 -1
  97. package/dist/opLifecycle/opGroupingManager.d.ts.map +1 -1
  98. package/dist/opLifecycle/opGroupingManager.js +7 -7
  99. package/dist/opLifecycle/opGroupingManager.js.map +1 -1
  100. package/dist/opLifecycle/opSplitter.d.ts +1 -1
  101. package/dist/opLifecycle/opSplitter.d.ts.map +1 -1
  102. package/dist/opLifecycle/opSplitter.js +17 -17
  103. package/dist/opLifecycle/opSplitter.js.map +1 -1
  104. package/dist/opLifecycle/outbox.d.ts +2 -1
  105. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  106. package/dist/opLifecycle/outbox.js +13 -13
  107. package/dist/opLifecycle/outbox.js.map +1 -1
  108. package/dist/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  109. package/dist/opLifecycle/remoteMessageProcessor.js.map +1 -1
  110. package/dist/packageVersion.d.ts +1 -1
  111. package/dist/packageVersion.js +1 -1
  112. package/dist/packageVersion.js.map +1 -1
  113. package/dist/pendingStateManager.d.ts.map +1 -1
  114. package/dist/pendingStateManager.js +18 -18
  115. package/dist/pendingStateManager.js.map +1 -1
  116. package/dist/scheduleManager.d.ts.map +1 -1
  117. package/dist/scheduleManager.js +24 -24
  118. package/dist/scheduleManager.js.map +1 -1
  119. package/dist/storageServiceWithAttachBlobs.d.ts +2 -2
  120. package/dist/storageServiceWithAttachBlobs.d.ts.map +1 -1
  121. package/dist/storageServiceWithAttachBlobs.js +2 -2
  122. package/dist/storageServiceWithAttachBlobs.js.map +1 -1
  123. package/dist/summary/documentSchema.d.ts +37 -6
  124. package/dist/summary/documentSchema.d.ts.map +1 -1
  125. package/dist/summary/documentSchema.js +58 -21
  126. package/dist/summary/documentSchema.js.map +1 -1
  127. package/dist/summary/orderedClientElection.d.ts.map +1 -1
  128. package/dist/summary/orderedClientElection.js +7 -7
  129. package/dist/summary/orderedClientElection.js.map +1 -1
  130. package/dist/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
  131. package/dist/summary/runWhileConnectedCoordinator.js +3 -3
  132. package/dist/summary/runWhileConnectedCoordinator.js.map +1 -1
  133. package/dist/summary/runningSummarizer.d.ts +1 -1
  134. package/dist/summary/runningSummarizer.d.ts.map +1 -1
  135. package/dist/summary/runningSummarizer.js +16 -16
  136. package/dist/summary/runningSummarizer.js.map +1 -1
  137. package/dist/summary/summarizer.d.ts +2 -1
  138. package/dist/summary/summarizer.d.ts.map +1 -1
  139. package/dist/summary/summarizer.js +12 -12
  140. package/dist/summary/summarizer.js.map +1 -1
  141. package/dist/summary/summarizerClientElection.d.ts.map +1 -1
  142. package/dist/summary/summarizerClientElection.js.map +1 -1
  143. package/dist/summary/summarizerHeuristics.d.ts.map +1 -1
  144. package/dist/summary/summarizerHeuristics.js +2 -2
  145. package/dist/summary/summarizerHeuristics.js.map +1 -1
  146. package/dist/summary/summarizerNode/summarizerNode.d.ts +2 -1
  147. package/dist/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  148. package/dist/summary/summarizerNode/summarizerNode.js +28 -28
  149. package/dist/summary/summarizerNode/summarizerNode.js.map +1 -1
  150. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts +2 -1
  151. package/dist/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  152. package/dist/summary/summarizerNode/summarizerNodeUtils.js +3 -3
  153. package/dist/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  154. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -1
  155. package/dist/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  156. package/dist/summary/summarizerNode/summarizerNodeWithGc.js +14 -14
  157. package/dist/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  158. package/dist/summary/summarizerTypes.d.ts +4 -2
  159. package/dist/summary/summarizerTypes.d.ts.map +1 -1
  160. package/dist/summary/summarizerTypes.js.map +1 -1
  161. package/dist/summary/summaryCollection.js +7 -7
  162. package/dist/summary/summaryCollection.js.map +1 -1
  163. package/dist/summary/summaryFormat.d.ts +1 -1
  164. package/dist/summary/summaryFormat.d.ts.map +1 -1
  165. package/dist/summary/summaryFormat.js +8 -8
  166. package/dist/summary/summaryFormat.js.map +1 -1
  167. package/dist/summary/summaryGenerator.d.ts +3 -2
  168. package/dist/summary/summaryGenerator.d.ts.map +1 -1
  169. package/dist/summary/summaryGenerator.js +16 -16
  170. package/dist/summary/summaryGenerator.js.map +1 -1
  171. package/dist/summary/summaryManager.d.ts.map +1 -1
  172. package/dist/summary/summaryManager.js +15 -14
  173. package/dist/summary/summaryManager.js.map +1 -1
  174. package/lib/batchTracker.d.ts.map +1 -1
  175. package/lib/batchTracker.js +2 -2
  176. package/lib/batchTracker.js.map +1 -1
  177. package/lib/blobManager.d.ts +31 -23
  178. package/lib/blobManager.d.ts.map +1 -1
  179. package/lib/blobManager.js +46 -64
  180. package/lib/blobManager.js.map +1 -1
  181. package/lib/channelCollection.d.ts +4 -2
  182. package/lib/channelCollection.d.ts.map +1 -1
  183. package/lib/channelCollection.js +10 -7
  184. package/lib/channelCollection.js.map +1 -1
  185. package/lib/connectionTelemetry.d.ts +1 -1
  186. package/lib/connectionTelemetry.d.ts.map +1 -1
  187. package/lib/connectionTelemetry.js +2 -2
  188. package/lib/connectionTelemetry.js.map +1 -1
  189. package/lib/container-runtime-alpha.d.ts +64 -36
  190. package/lib/container-runtime-beta.d.ts +28 -28
  191. package/lib/container-runtime-public.d.ts +28 -28
  192. package/lib/container-runtime-untrimmed.d.ts +68 -39
  193. package/lib/containerHandleContext.d.ts.map +1 -1
  194. package/lib/containerHandleContext.js +1 -1
  195. package/lib/containerHandleContext.js.map +1 -1
  196. package/lib/containerRuntime.d.ts +12 -8
  197. package/lib/containerRuntime.d.ts.map +1 -1
  198. package/lib/containerRuntime.js +76 -39
  199. package/lib/containerRuntime.js.map +1 -1
  200. package/lib/dataStore.d.ts +1 -1
  201. package/lib/dataStore.d.ts.map +1 -1
  202. package/lib/dataStore.js +2 -2
  203. package/lib/dataStore.js.map +1 -1
  204. package/lib/dataStoreContext.d.ts +9 -9
  205. package/lib/dataStoreContext.d.ts.map +1 -1
  206. package/lib/dataStoreContext.js +18 -8
  207. package/lib/dataStoreContext.js.map +1 -1
  208. package/lib/dataStoreContexts.d.ts.map +1 -1
  209. package/lib/dataStoreContexts.js +2 -2
  210. package/lib/dataStoreContexts.js.map +1 -1
  211. package/lib/dataStoreRegistry.d.ts +1 -1
  212. package/lib/dataStoreRegistry.d.ts.map +1 -1
  213. package/lib/dataStoreRegistry.js +1 -1
  214. package/lib/dataStoreRegistry.js.map +1 -1
  215. package/lib/deltaManagerSummarizerProxy.d.ts +1 -1
  216. package/lib/deltaManagerSummarizerProxy.d.ts.map +1 -1
  217. package/lib/deltaManagerSummarizerProxy.js.map +1 -1
  218. package/lib/deltaScheduler.d.ts.map +1 -1
  219. package/lib/deltaScheduler.js +1 -1
  220. package/lib/deltaScheduler.js.map +1 -1
  221. package/lib/error.d.ts +1 -1
  222. package/lib/error.d.ts.map +1 -1
  223. package/lib/error.js +2 -2
  224. package/lib/error.js.map +1 -1
  225. package/lib/gc/garbageCollection.d.ts +2 -1
  226. package/lib/gc/garbageCollection.d.ts.map +1 -1
  227. package/lib/gc/garbageCollection.js +4 -4
  228. package/lib/gc/garbageCollection.js.map +1 -1
  229. package/lib/gc/gcConfigs.d.ts +1 -1
  230. package/lib/gc/gcConfigs.d.ts.map +1 -1
  231. package/lib/gc/gcConfigs.js +4 -5
  232. package/lib/gc/gcConfigs.js.map +1 -1
  233. package/lib/gc/gcDefinitions.d.ts +3 -2
  234. package/lib/gc/gcDefinitions.d.ts.map +1 -1
  235. package/lib/gc/gcDefinitions.js.map +1 -1
  236. package/lib/gc/gcHelpers.d.ts +5 -1
  237. package/lib/gc/gcHelpers.d.ts.map +1 -1
  238. package/lib/gc/gcHelpers.js +10 -2
  239. package/lib/gc/gcHelpers.js.map +1 -1
  240. package/lib/gc/gcSummaryStateTracker.d.ts +1 -1
  241. package/lib/gc/gcSummaryStateTracker.d.ts.map +1 -1
  242. package/lib/gc/gcSummaryStateTracker.js +2 -2
  243. package/lib/gc/gcSummaryStateTracker.js.map +1 -1
  244. package/lib/gc/gcTelemetry.d.ts +2 -1
  245. package/lib/gc/gcTelemetry.d.ts.map +1 -1
  246. package/lib/gc/gcTelemetry.js +3 -1
  247. package/lib/gc/gcTelemetry.js.map +1 -1
  248. package/lib/gc/gcUnreferencedStateTracker.d.ts.map +1 -1
  249. package/lib/gc/gcUnreferencedStateTracker.js +2 -2
  250. package/lib/gc/gcUnreferencedStateTracker.js.map +1 -1
  251. package/lib/gc/index.d.ts +1 -1
  252. package/lib/gc/index.d.ts.map +1 -1
  253. package/lib/gc/index.js +1 -1
  254. package/lib/gc/index.js.map +1 -1
  255. package/lib/messageTypes.d.ts +2 -2
  256. package/lib/messageTypes.d.ts.map +1 -1
  257. package/lib/messageTypes.js.map +1 -1
  258. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  259. package/lib/opLifecycle/batchManager.js.map +1 -1
  260. package/lib/opLifecycle/definitions.d.ts +1 -1
  261. package/lib/opLifecycle/definitions.d.ts.map +1 -1
  262. package/lib/opLifecycle/definitions.js.map +1 -1
  263. package/lib/opLifecycle/opCompressor.d.ts.map +1 -1
  264. package/lib/opLifecycle/opCompressor.js +2 -2
  265. package/lib/opLifecycle/opCompressor.js.map +1 -1
  266. package/lib/opLifecycle/opDecompressor.d.ts.map +1 -1
  267. package/lib/opLifecycle/opDecompressor.js +2 -2
  268. package/lib/opLifecycle/opDecompressor.js.map +1 -1
  269. package/lib/opLifecycle/opGroupingManager.d.ts.map +1 -1
  270. package/lib/opLifecycle/opGroupingManager.js +2 -2
  271. package/lib/opLifecycle/opGroupingManager.js.map +1 -1
  272. package/lib/opLifecycle/opSplitter.d.ts +1 -1
  273. package/lib/opLifecycle/opSplitter.d.ts.map +1 -1
  274. package/lib/opLifecycle/opSplitter.js +2 -2
  275. package/lib/opLifecycle/opSplitter.js.map +1 -1
  276. package/lib/opLifecycle/outbox.d.ts +2 -1
  277. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  278. package/lib/opLifecycle/outbox.js +2 -2
  279. package/lib/opLifecycle/outbox.js.map +1 -1
  280. package/lib/opLifecycle/remoteMessageProcessor.d.ts.map +1 -1
  281. package/lib/opLifecycle/remoteMessageProcessor.js.map +1 -1
  282. package/lib/packageVersion.d.ts +1 -1
  283. package/lib/packageVersion.js +1 -1
  284. package/lib/packageVersion.js.map +1 -1
  285. package/lib/pendingStateManager.d.ts.map +1 -1
  286. package/lib/pendingStateManager.js +2 -2
  287. package/lib/pendingStateManager.js.map +1 -1
  288. package/lib/scheduleManager.d.ts.map +1 -1
  289. package/lib/scheduleManager.js +3 -3
  290. package/lib/scheduleManager.js.map +1 -1
  291. package/lib/storageServiceWithAttachBlobs.d.ts +2 -2
  292. package/lib/storageServiceWithAttachBlobs.d.ts.map +1 -1
  293. package/lib/storageServiceWithAttachBlobs.js +1 -1
  294. package/lib/storageServiceWithAttachBlobs.js.map +1 -1
  295. package/lib/summary/documentSchema.d.ts +37 -6
  296. package/lib/summary/documentSchema.d.ts.map +1 -1
  297. package/lib/summary/documentSchema.js +48 -11
  298. package/lib/summary/documentSchema.js.map +1 -1
  299. package/lib/summary/orderedClientElection.d.ts.map +1 -1
  300. package/lib/summary/orderedClientElection.js +2 -2
  301. package/lib/summary/orderedClientElection.js.map +1 -1
  302. package/lib/summary/runWhileConnectedCoordinator.d.ts.map +1 -1
  303. package/lib/summary/runWhileConnectedCoordinator.js +1 -1
  304. package/lib/summary/runWhileConnectedCoordinator.js.map +1 -1
  305. package/lib/summary/runningSummarizer.d.ts +1 -1
  306. package/lib/summary/runningSummarizer.d.ts.map +1 -1
  307. package/lib/summary/runningSummarizer.js +2 -2
  308. package/lib/summary/runningSummarizer.js.map +1 -1
  309. package/lib/summary/summarizer.d.ts +2 -1
  310. package/lib/summary/summarizer.d.ts.map +1 -1
  311. package/lib/summary/summarizer.js +2 -2
  312. package/lib/summary/summarizer.js.map +1 -1
  313. package/lib/summary/summarizerClientElection.d.ts.map +1 -1
  314. package/lib/summary/summarizerClientElection.js.map +1 -1
  315. package/lib/summary/summarizerHeuristics.d.ts.map +1 -1
  316. package/lib/summary/summarizerHeuristics.js +1 -1
  317. package/lib/summary/summarizerHeuristics.js.map +1 -1
  318. package/lib/summary/summarizerNode/summarizerNode.d.ts +2 -1
  319. package/lib/summary/summarizerNode/summarizerNode.d.ts.map +1 -1
  320. package/lib/summary/summarizerNode/summarizerNode.js +4 -4
  321. package/lib/summary/summarizerNode/summarizerNode.js.map +1 -1
  322. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts +2 -1
  323. package/lib/summary/summarizerNode/summarizerNodeUtils.d.ts.map +1 -1
  324. package/lib/summary/summarizerNode/summarizerNodeUtils.js +1 -1
  325. package/lib/summary/summarizerNode/summarizerNodeUtils.js.map +1 -1
  326. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts +2 -1
  327. package/lib/summary/summarizerNode/summarizerNodeWithGc.d.ts.map +1 -1
  328. package/lib/summary/summarizerNode/summarizerNodeWithGc.js +3 -3
  329. package/lib/summary/summarizerNode/summarizerNodeWithGc.js.map +1 -1
  330. package/lib/summary/summarizerTypes.d.ts +4 -2
  331. package/lib/summary/summarizerTypes.d.ts.map +1 -1
  332. package/lib/summary/summarizerTypes.js.map +1 -1
  333. package/lib/summary/summaryCollection.js +1 -1
  334. package/lib/summary/summaryCollection.js.map +1 -1
  335. package/lib/summary/summaryFormat.d.ts +1 -1
  336. package/lib/summary/summaryFormat.d.ts.map +1 -1
  337. package/lib/summary/summaryFormat.js +3 -3
  338. package/lib/summary/summaryFormat.js.map +1 -1
  339. package/lib/summary/summaryGenerator.d.ts +3 -2
  340. package/lib/summary/summaryGenerator.d.ts.map +1 -1
  341. package/lib/summary/summaryGenerator.js +3 -3
  342. package/lib/summary/summaryGenerator.js.map +1 -1
  343. package/lib/summary/summaryManager.d.ts.map +1 -1
  344. package/lib/summary/summaryManager.js +9 -8
  345. package/lib/summary/summaryManager.js.map +1 -1
  346. package/lib/tsdoc-metadata.json +11 -0
  347. package/package.json +25 -37
  348. package/src/batchTracker.ts +3 -2
  349. package/src/blobManager.ts +87 -56
  350. package/src/channelCollection.ts +19 -12
  351. package/src/connectionTelemetry.ts +4 -4
  352. package/src/containerHandleContext.ts +2 -1
  353. package/src/containerRuntime.ts +115 -70
  354. package/src/dataStore.ts +5 -3
  355. package/src/dataStoreContext.ts +30 -15
  356. package/src/dataStoreContexts.ts +4 -2
  357. package/src/dataStoreRegistry.ts +2 -2
  358. package/src/deltaManagerSummarizerProxy.ts +1 -1
  359. package/src/deltaScheduler.ts +2 -1
  360. package/src/error.ts +2 -2
  361. package/src/gc/garbageCollection.ts +8 -7
  362. package/src/gc/gcConfigs.ts +5 -8
  363. package/src/gc/gcDefinitions.ts +4 -4
  364. package/src/gc/gcHelpers.ts +21 -4
  365. package/src/gc/gcSummaryStateTracker.ts +5 -3
  366. package/src/gc/gcTelemetry.ts +7 -1
  367. package/src/gc/gcUnreferencedStateTracker.ts +3 -2
  368. package/src/gc/index.ts +1 -0
  369. package/src/messageTypes.ts +3 -2
  370. package/src/opLifecycle/batchManager.ts +1 -0
  371. package/src/opLifecycle/definitions.ts +2 -1
  372. package/src/opLifecycle/opCompressor.ts +4 -2
  373. package/src/opLifecycle/opDecompressor.ts +3 -2
  374. package/src/opLifecycle/opGroupingManager.ts +3 -2
  375. package/src/opLifecycle/opSplitter.ts +5 -3
  376. package/src/opLifecycle/outbox.ts +6 -3
  377. package/src/opLifecycle/remoteMessageProcessor.ts +2 -0
  378. package/src/packageVersion.ts +1 -1
  379. package/src/pendingStateManager.ts +4 -4
  380. package/src/scheduleManager.ts +5 -4
  381. package/src/storageServiceWithAttachBlobs.ts +2 -2
  382. package/src/summary/documentSchema.ts +71 -12
  383. package/src/summary/orderedClientElection.ts +4 -6
  384. package/src/summary/runWhileConnectedCoordinator.ts +2 -1
  385. package/src/summary/runningSummarizer.ts +4 -2
  386. package/src/summary/summarizer.ts +5 -3
  387. package/src/summary/summarizerClientElection.ts +1 -0
  388. package/src/summary/summarizerHeuristics.ts +3 -1
  389. package/src/summary/summarizerNode/summarizerNode.ts +10 -8
  390. package/src/summary/summarizerNode/summarizerNodeUtils.ts +3 -2
  391. package/src/summary/summarizerNode/summarizerNodeWithGc.ts +14 -6
  392. package/src/summary/summarizerTypes.ts +6 -2
  393. package/src/summary/summaryCollection.ts +1 -1
  394. package/src/summary/summaryFormat.ts +7 -8
  395. package/src/summary/summaryGenerator.ts +5 -8
  396. package/src/summary/summaryManager.ts +14 -11
  397. package/lib/test/batchTracker.spec.js +0 -88
  398. package/lib/test/batchTracker.spec.js.map +0 -1
  399. package/lib/test/blobManager.spec.js +0 -835
  400. package/lib/test/blobManager.spec.js.map +0 -1
  401. package/lib/test/channelCollection.spec.js +0 -138
  402. package/lib/test/channelCollection.spec.js.map +0 -1
  403. package/lib/test/containerRuntime.spec.js +0 -1750
  404. package/lib/test/containerRuntime.spec.js.map +0 -1
  405. package/lib/test/dataStoreContext.spec.js +0 -771
  406. package/lib/test/dataStoreContext.spec.js.map +0 -1
  407. package/lib/test/dataStoreCreation.spec.js +0 -303
  408. package/lib/test/dataStoreCreation.spec.js.map +0 -1
  409. package/lib/test/dataStoreRegistry.spec.js +0 -26
  410. package/lib/test/dataStoreRegistry.spec.js.map +0 -1
  411. package/lib/test/documentSchema.spec.js +0 -282
  412. package/lib/test/documentSchema.spec.js.map +0 -1
  413. package/lib/test/fuzz/fuzzUtils.js +0 -70
  414. package/lib/test/fuzz/fuzzUtils.js.map +0 -1
  415. package/lib/test/fuzz/summarizer.fuzz.spec.js +0 -33
  416. package/lib/test/fuzz/summarizer.fuzz.spec.js.map +0 -1
  417. package/lib/test/fuzz/summarizerFuzzMocks.js +0 -180
  418. package/lib/test/fuzz/summarizerFuzzMocks.js.map +0 -1
  419. package/lib/test/fuzz/summarizerFuzzSuite.js +0 -109
  420. package/lib/test/fuzz/summarizerFuzzSuite.js.map +0 -1
  421. package/lib/test/gc/garbageCollection.spec.js +0 -1464
  422. package/lib/test/gc/garbageCollection.spec.js.map +0 -1
  423. package/lib/test/gc/gcConfigs.spec.js +0 -689
  424. package/lib/test/gc/gcConfigs.spec.js.map +0 -1
  425. package/lib/test/gc/gcHelpers.spec.js +0 -110
  426. package/lib/test/gc/gcHelpers.spec.js.map +0 -1
  427. package/lib/test/gc/gcReferenceGraphAlgorithm.spec.js +0 -68
  428. package/lib/test/gc/gcReferenceGraphAlgorithm.spec.js.map +0 -1
  429. package/lib/test/gc/gcStats.spec.js +0 -390
  430. package/lib/test/gc/gcStats.spec.js.map +0 -1
  431. package/lib/test/gc/gcSummaryStateTracker.spec.js +0 -228
  432. package/lib/test/gc/gcSummaryStateTracker.spec.js.map +0 -1
  433. package/lib/test/gc/gcTelemetry.spec.js +0 -530
  434. package/lib/test/gc/gcTelemetry.spec.js.map +0 -1
  435. package/lib/test/gc/gcUnitTestHelpers.js +0 -29
  436. package/lib/test/gc/gcUnitTestHelpers.js.map +0 -1
  437. package/lib/test/gc/gcUnreferencedStateTracker.spec.js +0 -192
  438. package/lib/test/gc/gcUnreferencedStateTracker.spec.js.map +0 -1
  439. package/lib/test/getPendingBlobs.spec.js +0 -193
  440. package/lib/test/getPendingBlobs.spec.js.map +0 -1
  441. package/lib/test/hardwareStats.spec.js +0 -93
  442. package/lib/test/hardwareStats.spec.js.map +0 -1
  443. package/lib/test/index.js +0 -6
  444. package/lib/test/index.js.map +0 -1
  445. package/lib/test/opLifecycle/OpGroupingManager.spec.js +0 -202
  446. package/lib/test/opLifecycle/OpGroupingManager.spec.js.map +0 -1
  447. package/lib/test/opLifecycle/batchManager.spec.js +0 -189
  448. package/lib/test/opLifecycle/batchManager.spec.js.map +0 -1
  449. package/lib/test/opLifecycle/opCompressor.spec.js +0 -73
  450. package/lib/test/opLifecycle/opCompressor.spec.js.map +0 -1
  451. package/lib/test/opLifecycle/opDecompressor.spec.js +0 -223
  452. package/lib/test/opLifecycle/opDecompressor.spec.js.map +0 -1
  453. package/lib/test/opLifecycle/opSplitter.spec.js +0 -287
  454. package/lib/test/opLifecycle/opSplitter.spec.js.map +0 -1
  455. package/lib/test/opLifecycle/outbox.spec.js +0 -783
  456. package/lib/test/opLifecycle/outbox.spec.js.map +0 -1
  457. package/lib/test/opLifecycle/remoteMessageProcessor.spec.js +0 -220
  458. package/lib/test/opLifecycle/remoteMessageProcessor.spec.js.map +0 -1
  459. package/lib/test/pendingStateManager.spec.js +0 -329
  460. package/lib/test/pendingStateManager.spec.js.map +0 -1
  461. package/lib/test/scheduleManager.spec.js +0 -270
  462. package/lib/test/scheduleManager.spec.js.map +0 -1
  463. package/lib/test/summarizerNode.spec.js +0 -326
  464. package/lib/test/summarizerNode.spec.js.map +0 -1
  465. package/lib/test/summarizerNodeWithGc.spec.js +0 -318
  466. package/lib/test/summarizerNodeWithGc.spec.js.map +0 -1
  467. package/lib/test/summary/orderedClientElection.spec.js +0 -535
  468. package/lib/test/summary/orderedClientElection.spec.js.map +0 -1
  469. package/lib/test/summary/runningSummarizer.spec.js +0 -1349
  470. package/lib/test/summary/runningSummarizer.spec.js.map +0 -1
  471. package/lib/test/summary/summarizer.spec.js +0 -29
  472. package/lib/test/summary/summarizer.spec.js.map +0 -1
  473. package/lib/test/summary/summarizerClientElection.spec.js +0 -436
  474. package/lib/test/summary/summarizerClientElection.spec.js.map +0 -1
  475. package/lib/test/summary/summarizerHeuristics.spec.js +0 -289
  476. package/lib/test/summary/summarizerHeuristics.spec.js.map +0 -1
  477. package/lib/test/summary/summaryCollection.spec.js +0 -200
  478. package/lib/test/summary/summaryCollection.spec.js.map +0 -1
  479. package/lib/test/summary/summaryManager.spec.js +0 -430
  480. package/lib/test/summary/summaryManager.spec.js.map +0 -1
  481. package/lib/test/summary/testQuorumClients.js +0 -34
  482. package/lib/test/summary/testQuorumClients.js.map +0 -1
  483. package/lib/test/throttler.spec.js +0 -175
  484. package/lib/test/throttler.spec.js.map +0 -1
  485. package/lib/test/types/validateContainerRuntimePrevious.generated.js +0 -182
  486. package/lib/test/types/validateContainerRuntimePrevious.generated.js.map +0 -1
@@ -1,223 +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 { IsoBuffer } from "@fluid-internal/client-utils";
7
- import { MockLogger } from "@fluidframework/telemetry-utils";
8
- import { compress } from "lz4js";
9
- import { ContainerMessageType } from "../../index.js";
10
- import { OpDecompressor } from "../../opLifecycle/index.js";
11
- function generateCompressedBatchMessage(length) {
12
- const batch = [];
13
- for (let i = 0; i < length; i++) {
14
- // Actual Op and contents aren't important. Values are not realistic.
15
- batch.push({
16
- type: ContainerMessageType.FluidDataStoreOp,
17
- contents: `value${i}`,
18
- });
19
- }
20
- const contentsAsBuffer = new TextEncoder().encode(JSON.stringify(batch));
21
- const compressedContents = compress(contentsAsBuffer);
22
- const compressedContent = IsoBuffer.from(compressedContents).toString("base64");
23
- const messageBase = {
24
- contents: { packedContents: compressedContent },
25
- metadata: { meta: "data" },
26
- clientId: "clientId",
27
- sequenceNumber: 1,
28
- minimumSequenceNumber: 1,
29
- clientSequenceNumber: 1,
30
- referenceSequenceNumber: 1,
31
- type: "type",
32
- timestamp: 1,
33
- compression: "lz4",
34
- };
35
- // Single compressed message won't have batch metadata
36
- if (length === 1) {
37
- return messageBase;
38
- }
39
- return {
40
- ...messageBase,
41
- // TODO: It's not clear if this shallow clone is required, as opposed to just setting "batch" to false.
42
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
43
- metadata: { ...messageBase.metadata, batch: true },
44
- };
45
- }
46
- const emptyMessage = {
47
- contents: undefined,
48
- clientId: "clientId",
49
- sequenceNumber: 1,
50
- minimumSequenceNumber: 1,
51
- clientSequenceNumber: 1,
52
- referenceSequenceNumber: 1,
53
- type: "type",
54
- timestamp: 1,
55
- };
56
- const endBatchEmptyMessage = {
57
- contents: {},
58
- metadata: { batch: false },
59
- clientId: "clientId",
60
- sequenceNumber: 1,
61
- minimumSequenceNumber: 1,
62
- clientSequenceNumber: 1,
63
- referenceSequenceNumber: 1,
64
- type: "type",
65
- timestamp: 1,
66
- };
67
- describe("OpDecompressor", () => {
68
- const mockLogger = new MockLogger();
69
- let decompressor;
70
- beforeEach(() => {
71
- mockLogger.clear();
72
- decompressor = new OpDecompressor(mockLogger);
73
- });
74
- it("Processes single compressed op", () => {
75
- let message = generateCompressedBatchMessage(1);
76
- decompressor.decompressAndStore(message);
77
- assert.equal(decompressor.currentlyUnrolling, true);
78
- message = decompressor.unroll(message);
79
- assert.strictEqual(message.contents.contents, "value0");
80
- assert.strictEqual(message.metadata?.compressed, undefined);
81
- assert.strictEqual(message.compression, undefined);
82
- });
83
- // Back-compat self healing mechanism for ADO:3538
84
- it("Processes single compressed op without compression markers", () => {
85
- let message = {
86
- ...generateCompressedBatchMessage(1),
87
- compression: undefined,
88
- };
89
- decompressor.decompressAndStore(message);
90
- assert.equal(decompressor.currentlyUnrolling, true);
91
- message = decompressor.unroll(message);
92
- assert.strictEqual(message.contents.contents, "value0");
93
- assert.strictEqual(message.metadata?.compressed, undefined);
94
- assert.strictEqual(message.compression, undefined);
95
- mockLogger.assertMatch([
96
- {
97
- eventName: "OpDecompressor:LegacyCompression",
98
- category: "generic",
99
- },
100
- ]);
101
- });
102
- it("Expecting only lz4 compression", () => {
103
- assert.throws(() => decompressor.decompressAndStore({
104
- ...generateCompressedBatchMessage(5),
105
- compression: "gzip",
106
- }));
107
- });
108
- it("Processes multiple compressed ops", () => {
109
- const rootMessage = generateCompressedBatchMessage(5);
110
- decompressor.decompressAndStore(rootMessage);
111
- assert.equal(decompressor.currentlyUnrolling, true);
112
- const firstMessage = decompressor.unroll(rootMessage);
113
- assert.strictEqual(firstMessage.contents.contents, "value0");
114
- assert.strictEqual(firstMessage.metadata?.compressed, undefined);
115
- assert.strictEqual(firstMessage.compression, undefined);
116
- for (let i = 1; i < 4; i++) {
117
- assert.equal(decompressor.currentlyUnrolling, true);
118
- const message = decompressor.unroll(emptyMessage);
119
- assert.strictEqual(message.contents.contents, `value${i}`);
120
- assert.strictEqual(message.metadata?.compressed, undefined);
121
- assert.strictEqual(message.compression, undefined);
122
- }
123
- assert.equal(decompressor.currentlyUnrolling, true);
124
- const lastMessage = decompressor.unroll(endBatchEmptyMessage);
125
- assert.strictEqual(lastMessage.contents.contents, "value4");
126
- assert.strictEqual(lastMessage.metadata?.compressed, undefined);
127
- assert.strictEqual(lastMessage.compression, undefined);
128
- });
129
- it("Expecting empty messages in the middle of the compressed batch", () => {
130
- const rootMessage = generateCompressedBatchMessage(5);
131
- decompressor.decompressAndStore(rootMessage);
132
- assert.equal(decompressor.currentlyUnrolling, true);
133
- const firstMessage = decompressor.unroll(rootMessage);
134
- assert.strictEqual(firstMessage.contents.contents, "value0");
135
- assert.equal(decompressor.currentlyUnrolling, true);
136
- assert.throws(() => decompressor.unroll({ ...emptyMessage, contents: {} }));
137
- });
138
- it("Processes multiple batches of compressed ops", () => {
139
- const rootMessage = generateCompressedBatchMessage(5);
140
- decompressor.decompressAndStore(rootMessage);
141
- assert.equal(decompressor.currentlyUnrolling, true);
142
- const firstMessage = decompressor.unroll(rootMessage);
143
- assert.strictEqual(firstMessage.contents.contents, "value0");
144
- for (let i = 1; i < 4; i++) {
145
- assert.equal(decompressor.currentlyUnrolling, true);
146
- const message = decompressor.unroll(emptyMessage);
147
- assert.strictEqual(message.contents.contents, `value${i}`);
148
- }
149
- assert.equal(decompressor.currentlyUnrolling, true);
150
- const lastMessage = decompressor.unroll(endBatchEmptyMessage);
151
- assert.strictEqual(lastMessage.contents.contents, "value4");
152
- const nextRootMessage = generateCompressedBatchMessage(3);
153
- decompressor.decompressAndStore(nextRootMessage);
154
- assert.equal(decompressor.currentlyUnrolling, true);
155
- const nextFirstMessage = decompressor.unroll(nextRootMessage);
156
- assert.strictEqual(nextFirstMessage.contents.contents, "value0");
157
- assert.equal(decompressor.currentlyUnrolling, true);
158
- const middleMessage = decompressor.unroll(emptyMessage);
159
- assert.strictEqual(middleMessage.contents.contents, "value1");
160
- assert.equal(decompressor.currentlyUnrolling, true);
161
- const endBatchMessage = decompressor.unroll(endBatchEmptyMessage);
162
- assert.strictEqual(endBatchMessage.contents.contents, "value2");
163
- });
164
- it("Ignores ops without compression", () => {
165
- const rootMessages = [
166
- {
167
- // Back-compat self healing mechanism for ADO:3538,
168
- // the message should have a `packedContents` property.
169
- contents: { some: "contents" },
170
- metadata: { meta: "data" },
171
- clientId: "clientId",
172
- sequenceNumber: 1,
173
- term: 1,
174
- minimumSequenceNumber: 1,
175
- clientSequenceNumber: 1,
176
- referenceSequenceNumber: 1,
177
- type: "type",
178
- timestamp: 1,
179
- },
180
- {
181
- // Back-compat self healing mechanism for ADO:3538,
182
- contents: { packedContents: "packedContents is not base64 encoded" },
183
- metadata: { meta: "data" },
184
- clientId: "clientId",
185
- sequenceNumber: 1,
186
- term: 1,
187
- minimumSequenceNumber: 1,
188
- clientSequenceNumber: 1,
189
- referenceSequenceNumber: 1,
190
- type: "type",
191
- timestamp: 1,
192
- },
193
- {
194
- // Back-compat self healing mechanism for ADO:3538,
195
- contents: { packedContents: "YmFzZTY0IGNvbnRlbnQ=", some: "contents" },
196
- metadata: { meta: "data" },
197
- clientId: "clientId",
198
- sequenceNumber: 1,
199
- term: 1,
200
- minimumSequenceNumber: 1,
201
- clientSequenceNumber: 1,
202
- referenceSequenceNumber: 1,
203
- type: "type",
204
- timestamp: 1,
205
- },
206
- {
207
- metadata: { meta: "data" },
208
- clientId: "clientId",
209
- sequenceNumber: 1,
210
- term: 1,
211
- minimumSequenceNumber: 1,
212
- clientSequenceNumber: 1,
213
- referenceSequenceNumber: 1,
214
- type: "type",
215
- timestamp: 1,
216
- },
217
- ];
218
- for (const rootMessage of rootMessages) {
219
- assert.equal(decompressor.isCompressedMessage(rootMessage), false);
220
- }
221
- });
222
- });
223
- //# sourceMappingURL=opDecompressor.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"opDecompressor.spec.js","sourceRoot":"","sources":["../../../src/test/opLifecycle/opDecompressor.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,IAAI,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAGzD,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEtD,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAS5D,SAAS,8BAA8B,CAAC,MAAc;IACrD,MAAM,KAAK,GAAqC,EAAE,CAAC;IACnD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE;QAChC,qEAAqE;QACrE,KAAK,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,oBAAoB,CAAC,gBAAgB;YAC3C,QAAQ,EAAE,QAAQ,CAAC,EAA0B;SAC7C,CAAC,CAAC;KACH;IAED,MAAM,gBAAgB,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IACzE,MAAM,kBAAkB,GAAG,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACtD,MAAM,iBAAiB,GAAG,SAAS,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAEhF,MAAM,WAAW,GAA8B;QAC9C,QAAQ,EAAE,EAAE,cAAc,EAAE,iBAAiB,EAAE;QAC/C,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;QAC1B,QAAQ,EAAE,UAAU;QACpB,cAAc,EAAE,CAAC;QACjB,qBAAqB,EAAE,CAAC;QACxB,oBAAoB,EAAE,CAAC;QACvB,uBAAuB,EAAE,CAAC;QAC1B,IAAI,EAAE,MAAM;QACZ,SAAS,EAAE,CAAC;QACZ,WAAW,EAAE,KAAK;KAClB,CAAC;IAEF,sDAAsD;IACtD,IAAI,MAAM,KAAK,CAAC,EAAE;QACjB,OAAO,WAAW,CAAC;KACnB;IAED,OAAO;QACN,GAAG,WAAW;QACd,uGAAuG;QACvG,4EAA4E;QAC5E,QAAQ,EAAE,EAAE,GAAI,WAAW,CAAC,QAAgB,EAAE,KAAK,EAAE,IAAI,EAAE;KAC3D,CAAC;AACH,CAAC;AAED,MAAM,YAAY,GAA8B;IAC/C,QAAQ,EAAE,SAAS;IACnB,QAAQ,EAAE,UAAU;IACpB,cAAc,EAAE,CAAC;IACjB,qBAAqB,EAAE,CAAC;IACxB,oBAAoB,EAAE,CAAC;IACvB,uBAAuB,EAAE,CAAC;IAC1B,IAAI,EAAE,MAAM;IACZ,SAAS,EAAE,CAAC;CACZ,CAAC;AAEF,MAAM,oBAAoB,GAA8B;IACvD,QAAQ,EAAE,EAAE;IACZ,QAAQ,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;IAC1B,QAAQ,EAAE,UAAU;IACpB,cAAc,EAAE,CAAC;IACjB,qBAAqB,EAAE,CAAC;IACxB,oBAAoB,EAAE,CAAC;IACvB,uBAAuB,EAAE,CAAC;IAC1B,IAAI,EAAE,MAAM;IACZ,SAAS,EAAE,CAAC;CACZ,CAAC;AAEF,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC/B,MAAM,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC;IACpC,IAAI,YAA4B,CAAC;IACjC,UAAU,CAAC,GAAG,EAAE;QACf,UAAU,CAAC,KAAK,EAAE,CAAC;QACnB,YAAY,GAAG,IAAI,cAAc,CAAC,UAAU,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACzC,IAAI,OAAO,GAAG,8BAA8B,CAAC,CAAC,CAAC,CAAC;QAChD,YAAY,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;QACpD,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACvC,MAAM,CAAC,WAAW,CAAE,OAAO,CAAC,QAAiC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAClF,MAAM,CAAC,WAAW,CAChB,OAAO,CAAC,QAAiD,EAAE,UAAU,EACtE,SAAS,CACT,CAAC;QACF,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,kDAAkD;IAClD,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACrE,IAAI,OAAO,GAA8B;YACxC,GAAG,8BAA8B,CAAC,CAAC,CAAC;YACpC,WAAW,EAAE,SAAS;SACtB,CAAC;QACF,YAAY,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;QACpD,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEvC,MAAM,CAAC,WAAW,CAAE,OAAO,CAAC,QAAiC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAClF,MAAM,CAAC,WAAW,CAChB,OAAO,CAAC,QAAiD,EAAE,UAAU,EACtE,SAAS,CACT,CAAC;QACF,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QAEnD,UAAU,CAAC,WAAW,CAAC;YACtB;gBACC,SAAS,EAAE,kCAAkC;gBAC7C,QAAQ,EAAE,SAAS;aACnB;SACD,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAClB,YAAY,CAAC,kBAAkB,CAAC;YAC/B,GAAG,8BAA8B,CAAC,CAAC,CAAC;YACpC,WAAW,EAAE,MAAM;SACnB,CAAC,CACF,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC5C,MAAM,WAAW,GAAG,8BAA8B,CAAC,CAAC,CAAC,CAAC;QACtD,YAAY,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;QACpD,MAAM,YAAY,GAAG,YAAY,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAEtD,MAAM,CAAC,WAAW,CAAE,YAAY,CAAC,QAAiC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACvF,MAAM,CAAC,WAAW,CAChB,YAAY,CAAC,QAAiD,EAAE,UAAU,EAC3E,SAAS,CACT,CAAC;QACF,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QAExD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;YAC3B,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;YACpD,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YAClD,MAAM,CAAC,WAAW,CAAE,OAAO,CAAC,QAAiC,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;YACrF,MAAM,CAAC,WAAW,CAChB,OAAO,CAAC,QAAiD,EAAE,UAAU,EACtE,SAAS,CACT,CAAC;YACF,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;SACnD;QAED,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;QACpD,MAAM,WAAW,GAAG,YAAY,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAC9D,MAAM,CAAC,WAAW,CAAE,WAAW,CAAC,QAAiC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACtF,MAAM,CAAC,WAAW,CAChB,WAAW,CAAC,QAAiD,EAAE,UAAU,EAC1E,SAAS,CACT,CAAC;QACF,MAAM,CAAC,WAAW,CAAC,WAAW,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACzE,MAAM,WAAW,GAAG,8BAA8B,CAAC,CAAC,CAAC,CAAC;QACtD,YAAY,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;QACpD,MAAM,YAAY,GAAG,YAAY,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAEtD,MAAM,CAAC,WAAW,CAAE,YAAY,CAAC,QAAiC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAEvF,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;QACpD,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,GAAG,YAAY,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACvD,MAAM,WAAW,GAAG,8BAA8B,CAAC,CAAC,CAAC,CAAC;QACtD,YAAY,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;QACpD,MAAM,YAAY,GAAG,YAAY,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAEtD,MAAM,CAAC,WAAW,CAAE,YAAY,CAAC,QAAiC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAEvF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;YAC3B,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;YACpD,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YAClD,MAAM,CAAC,WAAW,CAAE,OAAO,CAAC,QAAiC,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;SACrF;QAED,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;QACpD,MAAM,WAAW,GAAG,YAAY,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAC9D,MAAM,CAAC,WAAW,CAAE,WAAW,CAAC,QAAiC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAEtF,MAAM,eAAe,GAAG,8BAA8B,CAAC,CAAC,CAAC,CAAC;QAC1D,YAAY,CAAC,kBAAkB,CAAC,eAAe,CAAC,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;QACpD,MAAM,gBAAgB,GAAG,YAAY,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;QAC9D,MAAM,CAAC,WAAW,CAAE,gBAAgB,CAAC,QAAiC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAE3F,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;QACpD,MAAM,aAAa,GAAG,YAAY,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QACxD,MAAM,CAAC,WAAW,CAAE,aAAa,CAAC,QAAiC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAExF,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;QACpD,MAAM,eAAe,GAAG,YAAY,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAClE,MAAM,CAAC,WAAW,CAAE,eAAe,CAAC,QAAiC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC3F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QAC1C,MAAM,YAAY,GAAG;YACpB;gBACC,mDAAmD;gBACnD,uDAAuD;gBACvD,QAAQ,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE;gBAC9B,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;gBAC1B,QAAQ,EAAE,UAAU;gBACpB,cAAc,EAAE,CAAC;gBACjB,IAAI,EAAE,CAAC;gBACP,qBAAqB,EAAE,CAAC;gBACxB,oBAAoB,EAAE,CAAC;gBACvB,uBAAuB,EAAE,CAAC;gBAC1B,IAAI,EAAE,MAAM;gBACZ,SAAS,EAAE,CAAC;aACZ;YACD;gBACC,mDAAmD;gBACnD,QAAQ,EAAE,EAAE,cAAc,EAAE,sCAAsC,EAAE;gBACpE,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;gBAC1B,QAAQ,EAAE,UAAU;gBACpB,cAAc,EAAE,CAAC;gBACjB,IAAI,EAAE,CAAC;gBACP,qBAAqB,EAAE,CAAC;gBACxB,oBAAoB,EAAE,CAAC;gBACvB,uBAAuB,EAAE,CAAC;gBAC1B,IAAI,EAAE,MAAM;gBACZ,SAAS,EAAE,CAAC;aACZ;YACD;gBACC,mDAAmD;gBACnD,QAAQ,EAAE,EAAE,cAAc,EAAE,sBAAsB,EAAE,IAAI,EAAE,UAAU,EAAE;gBACtE,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;gBAC1B,QAAQ,EAAE,UAAU;gBACpB,cAAc,EAAE,CAAC;gBACjB,IAAI,EAAE,CAAC;gBACP,qBAAqB,EAAE,CAAC;gBACxB,oBAAoB,EAAE,CAAC;gBACvB,uBAAuB,EAAE,CAAC;gBAC1B,IAAI,EAAE,MAAM;gBACZ,SAAS,EAAE,CAAC;aACZ;YACD;gBACC,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;gBAC1B,QAAQ,EAAE,UAAU;gBACpB,cAAc,EAAE,CAAC;gBACjB,IAAI,EAAE,CAAC;gBACP,qBAAqB,EAAE,CAAC;gBACxB,oBAAoB,EAAE,CAAC;gBACvB,uBAAuB,EAAE,CAAC;gBAC1B,IAAI,EAAE,MAAM;gBACZ,SAAS,EAAE,CAAC;aACZ;SACD,CAAC;QAEF,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE;YACvC,MAAM,CAAC,KAAK,CACX,YAAY,CAAC,mBAAmB,CAAC,WAAwC,CAAC,EAC1E,KAAK,CACL,CAAC;SACF;IACF,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 { IsoBuffer } from \"@fluid-internal/client-utils\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\nimport type { IEnvelope } from \"@fluidframework/runtime-definitions\";\nimport { MockLogger } from \"@fluidframework/telemetry-utils\";\nimport { compress } from \"lz4js\";\nimport { ContainerMessageType } from \"../../index.js\";\nimport type { InboundContainerRuntimeMessage } from \"../../messageTypes.js\";\nimport { OpDecompressor } from \"../../opLifecycle/index.js\";\n\n/**\n * Format of test messages generated in this test.\n */\ninterface ITestMessageContents {\n\tcontents: string;\n}\n\nfunction generateCompressedBatchMessage(length: number): ISequencedDocumentMessage {\n\tconst batch: InboundContainerRuntimeMessage[] = [];\n\tfor (let i = 0; i < length; i++) {\n\t\t// Actual Op and contents aren't important. Values are not realistic.\n\t\tbatch.push({\n\t\t\ttype: ContainerMessageType.FluidDataStoreOp,\n\t\t\tcontents: `value${i}` as unknown as IEnvelope,\n\t\t});\n\t}\n\n\tconst contentsAsBuffer = new TextEncoder().encode(JSON.stringify(batch));\n\tconst compressedContents = compress(contentsAsBuffer);\n\tconst compressedContent = IsoBuffer.from(compressedContents).toString(\"base64\");\n\n\tconst messageBase: ISequencedDocumentMessage = {\n\t\tcontents: { packedContents: compressedContent },\n\t\tmetadata: { meta: \"data\" },\n\t\tclientId: \"clientId\",\n\t\tsequenceNumber: 1,\n\t\tminimumSequenceNumber: 1,\n\t\tclientSequenceNumber: 1,\n\t\treferenceSequenceNumber: 1,\n\t\ttype: \"type\",\n\t\ttimestamp: 1,\n\t\tcompression: \"lz4\",\n\t};\n\n\t// Single compressed message won't have batch metadata\n\tif (length === 1) {\n\t\treturn messageBase;\n\t}\n\n\treturn {\n\t\t...messageBase,\n\t\t// TODO: It's not clear if this shallow clone is required, as opposed to just setting \"batch\" to false.\n\t\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n\t\tmetadata: { ...(messageBase.metadata as any), batch: true },\n\t};\n}\n\nconst emptyMessage: ISequencedDocumentMessage = {\n\tcontents: undefined,\n\tclientId: \"clientId\",\n\tsequenceNumber: 1,\n\tminimumSequenceNumber: 1,\n\tclientSequenceNumber: 1,\n\treferenceSequenceNumber: 1,\n\ttype: \"type\",\n\ttimestamp: 1,\n};\n\nconst endBatchEmptyMessage: ISequencedDocumentMessage = {\n\tcontents: {},\n\tmetadata: { batch: false },\n\tclientId: \"clientId\",\n\tsequenceNumber: 1,\n\tminimumSequenceNumber: 1,\n\tclientSequenceNumber: 1,\n\treferenceSequenceNumber: 1,\n\ttype: \"type\",\n\ttimestamp: 1,\n};\n\ndescribe(\"OpDecompressor\", () => {\n\tconst mockLogger = new MockLogger();\n\tlet decompressor: OpDecompressor;\n\tbeforeEach(() => {\n\t\tmockLogger.clear();\n\t\tdecompressor = new OpDecompressor(mockLogger);\n\t});\n\n\tit(\"Processes single compressed op\", () => {\n\t\tlet message = generateCompressedBatchMessage(1);\n\t\tdecompressor.decompressAndStore(message);\n\t\tassert.equal(decompressor.currentlyUnrolling, true);\n\t\tmessage = decompressor.unroll(message);\n\t\tassert.strictEqual((message.contents as ITestMessageContents).contents, \"value0\");\n\t\tassert.strictEqual(\n\t\t\t(message.metadata as { compressed?: unknown } | undefined)?.compressed,\n\t\t\tundefined,\n\t\t);\n\t\tassert.strictEqual(message.compression, undefined);\n\t});\n\n\t// Back-compat self healing mechanism for ADO:3538\n\tit(\"Processes single compressed op without compression markers\", () => {\n\t\tlet message: ISequencedDocumentMessage = {\n\t\t\t...generateCompressedBatchMessage(1),\n\t\t\tcompression: undefined,\n\t\t};\n\t\tdecompressor.decompressAndStore(message);\n\t\tassert.equal(decompressor.currentlyUnrolling, true);\n\t\tmessage = decompressor.unroll(message);\n\n\t\tassert.strictEqual((message.contents as ITestMessageContents).contents, \"value0\");\n\t\tassert.strictEqual(\n\t\t\t(message.metadata as { compressed?: unknown } | undefined)?.compressed,\n\t\t\tundefined,\n\t\t);\n\t\tassert.strictEqual(message.compression, undefined);\n\n\t\tmockLogger.assertMatch([\n\t\t\t{\n\t\t\t\teventName: \"OpDecompressor:LegacyCompression\",\n\t\t\t\tcategory: \"generic\",\n\t\t\t},\n\t\t]);\n\t});\n\n\tit(\"Expecting only lz4 compression\", () => {\n\t\tassert.throws(() =>\n\t\t\tdecompressor.decompressAndStore({\n\t\t\t\t...generateCompressedBatchMessage(5),\n\t\t\t\tcompression: \"gzip\",\n\t\t\t}),\n\t\t);\n\t});\n\n\tit(\"Processes multiple compressed ops\", () => {\n\t\tconst rootMessage = generateCompressedBatchMessage(5);\n\t\tdecompressor.decompressAndStore(rootMessage);\n\t\tassert.equal(decompressor.currentlyUnrolling, true);\n\t\tconst firstMessage = decompressor.unroll(rootMessage);\n\n\t\tassert.strictEqual((firstMessage.contents as ITestMessageContents).contents, \"value0\");\n\t\tassert.strictEqual(\n\t\t\t(firstMessage.metadata as { compressed?: unknown } | undefined)?.compressed,\n\t\t\tundefined,\n\t\t);\n\t\tassert.strictEqual(firstMessage.compression, undefined);\n\n\t\tfor (let i = 1; i < 4; i++) {\n\t\t\tassert.equal(decompressor.currentlyUnrolling, true);\n\t\t\tconst message = decompressor.unroll(emptyMessage);\n\t\t\tassert.strictEqual((message.contents as ITestMessageContents).contents, `value${i}`);\n\t\t\tassert.strictEqual(\n\t\t\t\t(message.metadata as { compressed?: unknown } | undefined)?.compressed,\n\t\t\t\tundefined,\n\t\t\t);\n\t\t\tassert.strictEqual(message.compression, undefined);\n\t\t}\n\n\t\tassert.equal(decompressor.currentlyUnrolling, true);\n\t\tconst lastMessage = decompressor.unroll(endBatchEmptyMessage);\n\t\tassert.strictEqual((lastMessage.contents as ITestMessageContents).contents, \"value4\");\n\t\tassert.strictEqual(\n\t\t\t(lastMessage.metadata as { compressed?: unknown } | undefined)?.compressed,\n\t\t\tundefined,\n\t\t);\n\t\tassert.strictEqual(lastMessage.compression, undefined);\n\t});\n\n\tit(\"Expecting empty messages in the middle of the compressed batch\", () => {\n\t\tconst rootMessage = generateCompressedBatchMessage(5);\n\t\tdecompressor.decompressAndStore(rootMessage);\n\t\tassert.equal(decompressor.currentlyUnrolling, true);\n\t\tconst firstMessage = decompressor.unroll(rootMessage);\n\n\t\tassert.strictEqual((firstMessage.contents as ITestMessageContents).contents, \"value0\");\n\n\t\tassert.equal(decompressor.currentlyUnrolling, true);\n\t\tassert.throws(() => decompressor.unroll({ ...emptyMessage, contents: {} }));\n\t});\n\n\tit(\"Processes multiple batches of compressed ops\", () => {\n\t\tconst rootMessage = generateCompressedBatchMessage(5);\n\t\tdecompressor.decompressAndStore(rootMessage);\n\t\tassert.equal(decompressor.currentlyUnrolling, true);\n\t\tconst firstMessage = decompressor.unroll(rootMessage);\n\n\t\tassert.strictEqual((firstMessage.contents as ITestMessageContents).contents, \"value0\");\n\n\t\tfor (let i = 1; i < 4; i++) {\n\t\t\tassert.equal(decompressor.currentlyUnrolling, true);\n\t\t\tconst message = decompressor.unroll(emptyMessage);\n\t\t\tassert.strictEqual((message.contents as ITestMessageContents).contents, `value${i}`);\n\t\t}\n\n\t\tassert.equal(decompressor.currentlyUnrolling, true);\n\t\tconst lastMessage = decompressor.unroll(endBatchEmptyMessage);\n\t\tassert.strictEqual((lastMessage.contents as ITestMessageContents).contents, \"value4\");\n\n\t\tconst nextRootMessage = generateCompressedBatchMessage(3);\n\t\tdecompressor.decompressAndStore(nextRootMessage);\n\t\tassert.equal(decompressor.currentlyUnrolling, true);\n\t\tconst nextFirstMessage = decompressor.unroll(nextRootMessage);\n\t\tassert.strictEqual((nextFirstMessage.contents as ITestMessageContents).contents, \"value0\");\n\n\t\tassert.equal(decompressor.currentlyUnrolling, true);\n\t\tconst middleMessage = decompressor.unroll(emptyMessage);\n\t\tassert.strictEqual((middleMessage.contents as ITestMessageContents).contents, \"value1\");\n\n\t\tassert.equal(decompressor.currentlyUnrolling, true);\n\t\tconst endBatchMessage = decompressor.unroll(endBatchEmptyMessage);\n\t\tassert.strictEqual((endBatchMessage.contents as ITestMessageContents).contents, \"value2\");\n\t});\n\n\tit(\"Ignores ops without compression\", () => {\n\t\tconst rootMessages = [\n\t\t\t{\n\t\t\t\t// Back-compat self healing mechanism for ADO:3538,\n\t\t\t\t// the message should have a `packedContents` property.\n\t\t\t\tcontents: { some: \"contents\" },\n\t\t\t\tmetadata: { meta: \"data\" },\n\t\t\t\tclientId: \"clientId\",\n\t\t\t\tsequenceNumber: 1,\n\t\t\t\tterm: 1,\n\t\t\t\tminimumSequenceNumber: 1,\n\t\t\t\tclientSequenceNumber: 1,\n\t\t\t\treferenceSequenceNumber: 1,\n\t\t\t\ttype: \"type\",\n\t\t\t\ttimestamp: 1,\n\t\t\t},\n\t\t\t{\n\t\t\t\t// Back-compat self healing mechanism for ADO:3538,\n\t\t\t\tcontents: { packedContents: \"packedContents is not base64 encoded\" },\n\t\t\t\tmetadata: { meta: \"data\" },\n\t\t\t\tclientId: \"clientId\",\n\t\t\t\tsequenceNumber: 1,\n\t\t\t\tterm: 1,\n\t\t\t\tminimumSequenceNumber: 1,\n\t\t\t\tclientSequenceNumber: 1,\n\t\t\t\treferenceSequenceNumber: 1,\n\t\t\t\ttype: \"type\",\n\t\t\t\ttimestamp: 1,\n\t\t\t},\n\t\t\t{\n\t\t\t\t// Back-compat self healing mechanism for ADO:3538,\n\t\t\t\tcontents: { packedContents: \"YmFzZTY0IGNvbnRlbnQ=\", some: \"contents\" },\n\t\t\t\tmetadata: { meta: \"data\" },\n\t\t\t\tclientId: \"clientId\",\n\t\t\t\tsequenceNumber: 1,\n\t\t\t\tterm: 1,\n\t\t\t\tminimumSequenceNumber: 1,\n\t\t\t\tclientSequenceNumber: 1,\n\t\t\t\treferenceSequenceNumber: 1,\n\t\t\t\ttype: \"type\",\n\t\t\t\ttimestamp: 1,\n\t\t\t},\n\t\t\t{\n\t\t\t\tmetadata: { meta: \"data\" },\n\t\t\t\tclientId: \"clientId\",\n\t\t\t\tsequenceNumber: 1,\n\t\t\t\tterm: 1,\n\t\t\t\tminimumSequenceNumber: 1,\n\t\t\t\tclientSequenceNumber: 1,\n\t\t\t\treferenceSequenceNumber: 1,\n\t\t\t\ttype: \"type\",\n\t\t\t\ttimestamp: 1,\n\t\t\t},\n\t\t];\n\n\t\tfor (const rootMessage of rootMessages) {\n\t\t\tassert.equal(\n\t\t\t\tdecompressor.isCompressedMessage(rootMessage as ISequencedDocumentMessage),\n\t\t\t\tfalse,\n\t\t\t);\n\t\t}\n\t});\n});\n"]}
@@ -1,287 +0,0 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
- /* eslint-disable @typescript-eslint/no-non-null-assertion */
6
- import { strict as assert } from "assert";
7
- import * as crypto from "crypto";
8
- import { ContainerMessageType } from "@fluidframework/container-runtime-previous";
9
- import { MockLogger } from "@fluidframework/telemetry-utils";
10
- import { CompressionAlgorithms } from "../../containerRuntime.js";
11
- import { OpSplitter, isChunkedMessage, splitOp, } from "../../opLifecycle/index.js";
12
- function typeFromBatchedOp(op) {
13
- assert(op.contents !== undefined);
14
- return JSON.parse(op.contents).type;
15
- }
16
- describe("OpSplitter", () => {
17
- const batchesSubmitted = [];
18
- const mockSubmitBatchFn = (batch, referenceSequenceNumber) => {
19
- batchesSubmitted.push({ messages: batch, referenceSequenceNumber });
20
- return batchesSubmitted.length;
21
- };
22
- beforeEach(() => {
23
- batchesSubmitted.splice(0);
24
- mockLogger.clear();
25
- });
26
- const chunkSizeInBytes = 50 * 1024;
27
- const maxBatchSizeInBytes = 10 * 50 * 1024;
28
- const mockLogger = new MockLogger();
29
- it("Reconstruct original chunked op", () => {
30
- const op1 = generateChunkableOp(chunkSizeInBytes * 2);
31
- const op2 = generateChunkableOp(chunkSizeInBytes * 3);
32
- const chunks1 = wrapChunkedOps(splitOp(op1, chunkSizeInBytes), "testClient1");
33
- const chunks2 = wrapChunkedOps(splitOp(op2, chunkSizeInBytes), "testClient2");
34
- const opSplitter = new OpSplitter([], mockSubmitBatchFn, 0, maxBatchSizeInBytes, mockLogger);
35
- assert.equal(opSplitter.processChunk(chunks1[0]).isFinalChunk, false);
36
- assert.equal(opSplitter.processChunk(chunks2[0]).isFinalChunk, false);
37
- assert.equal(opSplitter.processChunk(chunks1[1]).isFinalChunk, false);
38
- assert.equal(opSplitter.processChunk(chunks2[1]).isFinalChunk, false);
39
- const chunks1LastResult = opSplitter.processChunk(chunks1[2]);
40
- // The last chunk will reconstruct the original message
41
- assert.equal(chunks1LastResult.isFinalChunk, true);
42
- assertSameMessage(chunks1LastResult.message, op1);
43
- assert.equal(opSplitter.chunks.size, 1);
44
- assert.equal(opSplitter.processChunk(chunks2[2]).isFinalChunk, false);
45
- const chunks2LastResult = opSplitter.processChunk(chunks2[3]);
46
- // The last chunk will reconstruct the original message
47
- assert.equal(chunks2LastResult.isFinalChunk, true);
48
- assertSameMessage(chunks2LastResult.message, op2);
49
- assert.equal(opSplitter.chunks.size, 0);
50
- });
51
- it("Reconstruct original chunked op with extra empty op", () => {
52
- const op1 = generateChunkableOp(chunkSizeInBytes * 2);
53
- const op2 = generateChunkableOp(chunkSizeInBytes * 3);
54
- const chunks1 = wrapChunkedOps(splitOp(op1, chunkSizeInBytes, true), "testClient1");
55
- const chunks2 = wrapChunkedOps(splitOp(op2, chunkSizeInBytes, true), "testClient2");
56
- const opSplitter = new OpSplitter([], mockSubmitBatchFn, 0, maxBatchSizeInBytes, mockLogger);
57
- assert.equal(opSplitter.processChunk(chunks1[0]).isFinalChunk, false);
58
- assert.equal(opSplitter.processChunk(chunks2[0]).isFinalChunk, false);
59
- assert.equal(opSplitter.processChunk(chunks1[1]).isFinalChunk, false);
60
- assert.equal(opSplitter.processChunk(chunks2[1]).isFinalChunk, false);
61
- assert.equal(opSplitter.processChunk(chunks1[2]).isFinalChunk, false);
62
- const chunks1LastResult = opSplitter.processChunk(chunks1[3]);
63
- // The last chunk will reconstruct the original message
64
- assert.equal(chunks1LastResult.isFinalChunk, true);
65
- assertSameMessage(chunks1LastResult.message, op1);
66
- assert.equal(opSplitter.chunks.size, 1);
67
- assert.equal(opSplitter.processChunk(chunks2[2]).isFinalChunk, false);
68
- assert.equal(opSplitter.processChunk(chunks2[3]).isFinalChunk, false);
69
- const chunks2LastResult = opSplitter.processChunk(chunks2[4]);
70
- // The last chunk will reconstruct the original message
71
- assert.equal(chunks2LastResult.isFinalChunk, true);
72
- assertSameMessage(chunks2LastResult.message, op2);
73
- assert.equal(opSplitter.chunks.size, 0);
74
- });
75
- it("Reconstruct original chunked op with initial chunks", () => {
76
- const op = generateChunkableOp(chunkSizeInBytes * 3);
77
- const chunks = wrapChunkedOps(splitOp(op, chunkSizeInBytes), "testClient");
78
- const opSplitter = new OpSplitter([], mockSubmitBatchFn, 0, maxBatchSizeInBytes, mockLogger);
79
- opSplitter.processChunk(chunks[0]);
80
- opSplitter.processChunk(chunks[1]);
81
- const otherOpSplitter = new OpSplitter(Array.from(opSplitter.chunks), mockSubmitBatchFn, 0, maxBatchSizeInBytes, mockLogger);
82
- opSplitter.clearPartialChunks("testClient");
83
- otherOpSplitter.processChunk(chunks[2]);
84
- const processResult = otherOpSplitter.processChunk(chunks[3]);
85
- assert.equal(processResult.isFinalChunk, true);
86
- assertSameMessage(processResult.message, op);
87
- });
88
- it("Clear chunks", () => {
89
- const chunks = wrapChunkedOps(splitOp(generateChunkableOp(chunkSizeInBytes * 3), chunkSizeInBytes), "testClient");
90
- const opSplitter = new OpSplitter([], mockSubmitBatchFn, 0, maxBatchSizeInBytes, mockLogger);
91
- opSplitter.processChunk(chunks[0]);
92
- assert.equal(opSplitter.chunks.size, 1);
93
- opSplitter.clearPartialChunks("noClient");
94
- assert.equal(opSplitter.chunks.size, 1);
95
- opSplitter.clearPartialChunks("testClient");
96
- assert.equal(opSplitter.chunks.size, 0);
97
- });
98
- it("Throw when processing out-of-order chunks", () => {
99
- const chunks = wrapChunkedOps(splitOp(generateChunkableOp(chunkSizeInBytes * 3), chunkSizeInBytes), "testClient1");
100
- const opSplitter = new OpSplitter([], mockSubmitBatchFn, 0, maxBatchSizeInBytes, mockLogger);
101
- assert.throws(() => opSplitter.processChunk(chunks[2]));
102
- });
103
- it("Don't accept non-chunked ops", () => {
104
- const chunks = wrapChunkedOps(splitOp(generateChunkableOp(chunkSizeInBytes * 3), chunkSizeInBytes), "testClient1").map((op) => {
105
- op.contents.type = ContainerMessageType.FluidDataStoreOp;
106
- return op;
107
- });
108
- const opSplitter = new OpSplitter([], mockSubmitBatchFn, 0, maxBatchSizeInBytes, mockLogger);
109
- for (const op of chunks) {
110
- assert.deepStrictEqual(isChunkedMessage(op), false);
111
- assert.throws(() => opSplitter.processChunk(op));
112
- }
113
- });
114
- it("Chunk metadata", () => {
115
- const originalOp = generateChunkableOp(chunkSizeInBytes * 4);
116
- const chunks = splitOp(originalOp, chunkSizeInBytes);
117
- assert.equal(chunks
118
- .slice(0, -1)
119
- .every((chunk) => chunk.originalCompression === undefined &&
120
- chunk.originalMetadata === undefined), true);
121
- const lastChunk = chunks[chunks.length - 1];
122
- assert.deepStrictEqual(lastChunk.originalMetadata, originalOp.metadata);
123
- assert.equal(lastChunk.originalCompression, originalOp.compression);
124
- });
125
- it("Batch split invariants", () => {
126
- const opSplitter = new OpSplitter([], mockSubmitBatchFn, 50, maxBatchSizeInBytes, mockLogger);
127
- const regularMessage = generateChunkableOp(20);
128
- const compressedMessage = { ...regularMessage, metadata: { compressed: true } };
129
- // Empty batch
130
- assert.throws(() => opSplitter.splitFirstBatchMessage({
131
- content: [compressedMessage],
132
- contentSizeInBytes: 0,
133
- referenceSequenceNumber: 0,
134
- }));
135
- // Empty batch
136
- assert.throws(() => opSplitter.splitFirstBatchMessage({
137
- content: [],
138
- contentSizeInBytes: 1,
139
- referenceSequenceNumber: 0,
140
- }));
141
- // Batch is too small to be chunked
142
- assert.throws(() => opSplitter.splitFirstBatchMessage({
143
- content: [compressedMessage],
144
- contentSizeInBytes: 1,
145
- referenceSequenceNumber: 0,
146
- }));
147
- // Batch is not compressed
148
- assert.throws(() => opSplitter.splitFirstBatchMessage({
149
- content: [regularMessage],
150
- contentSizeInBytes: 3,
151
- referenceSequenceNumber: 0,
152
- }));
153
- // Misconfigured op splitter
154
- assert.throws(() => new OpSplitter([], mockSubmitBatchFn, 0, maxBatchSizeInBytes, mockLogger).splitFirstBatchMessage({
155
- content: [compressedMessage],
156
- contentSizeInBytes: 3,
157
- referenceSequenceNumber: 0,
158
- }));
159
- // Old loader
160
- assert.throws(() => new OpSplitter([], undefined, 0, maxBatchSizeInBytes, mockLogger).splitFirstBatchMessage({
161
- content: [compressedMessage],
162
- contentSizeInBytes: 3,
163
- referenceSequenceNumber: 0,
164
- }));
165
- // Misconfigured op splitter
166
- assert.throws(() => new OpSplitter([], mockSubmitBatchFn, 2, 1, mockLogger).splitFirstBatchMessage({
167
- content: [compressedMessage],
168
- contentSizeInBytes: 3,
169
- referenceSequenceNumber: 0,
170
- }));
171
- // Not enabled
172
- assert.throws(() => new OpSplitter([], mockSubmitBatchFn, Number.POSITIVE_INFINITY, maxBatchSizeInBytes, mockLogger).splitFirstBatchMessage({
173
- content: [compressedMessage],
174
- contentSizeInBytes: 3,
175
- referenceSequenceNumber: 0,
176
- }));
177
- });
178
- describe("Compressed batches", () => {
179
- [false, true].forEach((extraOp) => {
180
- it(`Split compressed batch with multiple messages with${extraOp ? "" : "out"} extra empty op.`, () => {
181
- const chunkSize = 20;
182
- const opSplitter = new OpSplitter([], mockSubmitBatchFn, chunkSize, extraOp ? chunkSize * 2 : maxBatchSizeInBytes, mockLogger);
183
- const largeMessage = generateChunkableOp(100);
184
- const emptyMessage = generateChunkableOp(0);
185
- const result = opSplitter.splitFirstBatchMessage({
186
- content: [largeMessage, emptyMessage, emptyMessage, emptyMessage],
187
- contentSizeInBytes: largeMessage.contents?.length ?? 0,
188
- referenceSequenceNumber: 0,
189
- });
190
- assert.equal(batchesSubmitted.length, 5 + (extraOp ? 1 : 0));
191
- for (const batch of batchesSubmitted) {
192
- assert.equal(batch.messages.length, 1);
193
- assert.equal(typeFromBatchedOp(batch.messages[0]), ContainerMessageType.ChunkedOp);
194
- assert.equal(batch.referenceSequenceNumber, 0);
195
- }
196
- assert.equal(result.content.length, 4);
197
- const lastChunk = JSON.parse(result.content[0].contents).contents;
198
- assert.equal(lastChunk.chunkId, lastChunk.totalChunks);
199
- assert.deepStrictEqual(result.content.slice(1), new Array(3).fill(emptyMessage));
200
- assert.equal(!extraOp ||
201
- JSON.parse(result.content[0].contents).contents?.contents?.length === 0, true);
202
- assert.notEqual(result.contentSizeInBytes, largeMessage.contents?.length ?? 0);
203
- const contentSentSeparately = batchesSubmitted.map((x) => JSON.parse(x.messages[0].contents)
204
- .contents.contents);
205
- const sentContent = [...contentSentSeparately, lastChunk.contents].reduce((accumulator, current) => `${accumulator}${current}`);
206
- assert.equal(sentContent, largeMessage.contents);
207
- assert(mockLogger.matchEvents([
208
- {
209
- eventName: "OpSplitter:CompressedChunkedBatch",
210
- length: result.content.length,
211
- chunks: 100 / 20 + 1 + (extraOp ? 1 : 0),
212
- chunkSizeInBytes: 20,
213
- },
214
- ]));
215
- });
216
- it(`Split compressed batch with single message with${extraOp ? "" : "out"} extra empty op.`, () => {
217
- const chunkSize = 20;
218
- const opSplitter = new OpSplitter([], mockSubmitBatchFn, 20, extraOp ? chunkSize * 2 : maxBatchSizeInBytes, mockLogger);
219
- const largeMessage = generateChunkableOp(100);
220
- const result = opSplitter.splitFirstBatchMessage({
221
- content: [largeMessage],
222
- contentSizeInBytes: largeMessage.contents?.length ?? 0,
223
- referenceSequenceNumber: 0,
224
- });
225
- assert.equal(batchesSubmitted.length, 5 + (extraOp ? 1 : 0));
226
- for (const batch of batchesSubmitted) {
227
- assert.equal(batch.messages.length, 1);
228
- assert.equal(typeFromBatchedOp(batch.messages[0]), ContainerMessageType.ChunkedOp);
229
- assert.equal(batch.referenceSequenceNumber, 0);
230
- }
231
- assert.equal(result.content.length, 1);
232
- assert.notEqual(result.contentSizeInBytes, largeMessage.contents?.length ?? 0);
233
- const lastChunk = JSON.parse(result.content[0].contents).contents;
234
- assert.equal(lastChunk.chunkId, lastChunk.totalChunks);
235
- assert.equal(!extraOp ||
236
- JSON.parse(result.content[0].contents).contents?.contents?.length === 0, true);
237
- assert.notEqual(result.contentSizeInBytes, largeMessage.contents?.length ?? 0);
238
- const contentSentSeparately = batchesSubmitted.map((x) => JSON.parse(x.messages[0].contents)
239
- .contents.contents);
240
- const sentContent = [...contentSentSeparately, lastChunk.contents].reduce((accumulator, current) => `${accumulator}${current}`);
241
- assert.equal(sentContent, largeMessage.contents);
242
- assert(mockLogger.matchEvents([
243
- {
244
- eventName: "OpSplitter:CompressedChunkedBatch",
245
- length: result.content.length,
246
- chunks: 100 / 20 + 1 + (extraOp ? 1 : 0),
247
- chunkSizeInBytes: 20,
248
- },
249
- ]));
250
- });
251
- });
252
- });
253
- const assertSameMessage = (result, original) => {
254
- assert.deepStrictEqual(result.contents, JSON.parse(original.contents));
255
- // type = "component" is used to force 1.3 to crash on compressed & chunked ops, as it does not understand it.
256
- // 2.x does not care about type, as it will get right type after decompressing the op.
257
- // see code & comment in splitOp()
258
- assert.strictEqual(result.type, "component");
259
- assert.strictEqual(result.metadata, original.metadata);
260
- assert.strictEqual(result.compression, original.compression);
261
- };
262
- const generateChunkableOp = (contentSizeInBytes) => {
263
- const contents = {
264
- // There should be a type here, but there is no validation for that,
265
- // and tests would need to be adjusted (sizing and assumptions) if we add it here.
266
- // type: ContainerMessageType.FluidDataStoreOp,
267
- value: crypto.randomBytes(contentSizeInBytes / 2).toString("hex"),
268
- };
269
- return {
270
- referenceSequenceNumber: Infinity,
271
- metadata: { meta: "data" },
272
- compression: CompressionAlgorithms.lz4,
273
- contents: JSON.stringify(contents),
274
- };
275
- };
276
- const wrapChunkedOps = (ops, clientId) => ops.map((op) => {
277
- const result = {
278
- contents: {
279
- type: ContainerMessageType.ChunkedOp,
280
- contents: op,
281
- },
282
- clientId,
283
- };
284
- return result;
285
- });
286
- });
287
- //# sourceMappingURL=opSplitter.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"opSplitter.spec.js","sourceRoot":"","sources":["../../../src/test/opLifecycle/opSplitter.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\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\n\nimport { strict as assert } from \"assert\";\nimport * as crypto from \"crypto\";\nimport { IBatchMessage } from \"@fluidframework/container-definitions\";\nimport { ContainerMessageType } from \"@fluidframework/container-runtime-previous\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/protocol-definitions\";\nimport { MockLogger } from \"@fluidframework/telemetry-utils\";\nimport { CompressionAlgorithms } from \"../../containerRuntime.js\";\nimport {\n\tBatchMessage,\n\tIChunkedOp,\n\tOpSplitter,\n\tisChunkedMessage,\n\tsplitOp,\n} from \"../../opLifecycle/index.js\";\n\nfunction typeFromBatchedOp(op: IBatchMessage) {\n\tassert(op.contents !== undefined);\n\treturn JSON.parse(op.contents).type as string;\n}\n\ndescribe(\"OpSplitter\", () => {\n\tconst batchesSubmitted: { messages: IBatchMessage[]; referenceSequenceNumber?: number }[] = [];\n\n\tconst mockSubmitBatchFn = (\n\t\tbatch: IBatchMessage[],\n\t\treferenceSequenceNumber?: number,\n\t): number => {\n\t\tbatchesSubmitted.push({ messages: batch, referenceSequenceNumber });\n\t\treturn batchesSubmitted.length;\n\t};\n\n\tbeforeEach(() => {\n\t\tbatchesSubmitted.splice(0);\n\t\tmockLogger.clear();\n\t});\n\n\tconst chunkSizeInBytes = 50 * 1024;\n\tconst maxBatchSizeInBytes = 10 * 50 * 1024;\n\tconst mockLogger = new MockLogger();\n\n\tit(\"Reconstruct original chunked op\", () => {\n\t\tconst op1 = generateChunkableOp(chunkSizeInBytes * 2);\n\t\tconst op2 = generateChunkableOp(chunkSizeInBytes * 3);\n\t\tconst chunks1 = wrapChunkedOps(splitOp(op1, chunkSizeInBytes), \"testClient1\");\n\t\tconst chunks2 = wrapChunkedOps(splitOp(op2, chunkSizeInBytes), \"testClient2\");\n\t\tconst opSplitter = new OpSplitter(\n\t\t\t[],\n\t\t\tmockSubmitBatchFn,\n\t\t\t0,\n\t\t\tmaxBatchSizeInBytes,\n\t\t\tmockLogger,\n\t\t);\n\n\t\tassert.equal(opSplitter.processChunk(chunks1[0]).isFinalChunk, false);\n\t\tassert.equal(opSplitter.processChunk(chunks2[0]).isFinalChunk, false);\n\n\t\tassert.equal(opSplitter.processChunk(chunks1[1]).isFinalChunk, false);\n\t\tassert.equal(opSplitter.processChunk(chunks2[1]).isFinalChunk, false);\n\n\t\tconst chunks1LastResult = opSplitter.processChunk(chunks1[2]);\n\t\t// The last chunk will reconstruct the original message\n\t\tassert.equal(chunks1LastResult.isFinalChunk, true);\n\t\tassertSameMessage(chunks1LastResult.message, op1);\n\t\tassert.equal(opSplitter.chunks.size, 1);\n\n\t\tassert.equal(opSplitter.processChunk(chunks2[2]).isFinalChunk, false);\n\n\t\tconst chunks2LastResult = opSplitter.processChunk(chunks2[3]);\n\t\t// The last chunk will reconstruct the original message\n\t\tassert.equal(chunks2LastResult.isFinalChunk, true);\n\t\tassertSameMessage(chunks2LastResult.message, op2);\n\n\t\tassert.equal(opSplitter.chunks.size, 0);\n\t});\n\n\tit(\"Reconstruct original chunked op with extra empty op\", () => {\n\t\tconst op1 = generateChunkableOp(chunkSizeInBytes * 2);\n\t\tconst op2 = generateChunkableOp(chunkSizeInBytes * 3);\n\t\tconst chunks1 = wrapChunkedOps(splitOp(op1, chunkSizeInBytes, true), \"testClient1\");\n\t\tconst chunks2 = wrapChunkedOps(splitOp(op2, chunkSizeInBytes, true), \"testClient2\");\n\t\tconst opSplitter = new OpSplitter(\n\t\t\t[],\n\t\t\tmockSubmitBatchFn,\n\t\t\t0,\n\t\t\tmaxBatchSizeInBytes,\n\t\t\tmockLogger,\n\t\t);\n\n\t\tassert.equal(opSplitter.processChunk(chunks1[0]).isFinalChunk, false);\n\t\tassert.equal(opSplitter.processChunk(chunks2[0]).isFinalChunk, false);\n\n\t\tassert.equal(opSplitter.processChunk(chunks1[1]).isFinalChunk, false);\n\t\tassert.equal(opSplitter.processChunk(chunks2[1]).isFinalChunk, false);\n\n\t\tassert.equal(opSplitter.processChunk(chunks1[2]).isFinalChunk, false);\n\n\t\tconst chunks1LastResult = opSplitter.processChunk(chunks1[3]);\n\t\t// The last chunk will reconstruct the original message\n\t\tassert.equal(chunks1LastResult.isFinalChunk, true);\n\t\tassertSameMessage(chunks1LastResult.message, op1);\n\t\tassert.equal(opSplitter.chunks.size, 1);\n\n\t\tassert.equal(opSplitter.processChunk(chunks2[2]).isFinalChunk, false);\n\t\tassert.equal(opSplitter.processChunk(chunks2[3]).isFinalChunk, false);\n\n\t\tconst chunks2LastResult = opSplitter.processChunk(chunks2[4]);\n\t\t// The last chunk will reconstruct the original message\n\t\tassert.equal(chunks2LastResult.isFinalChunk, true);\n\t\tassertSameMessage(chunks2LastResult.message, op2);\n\n\t\tassert.equal(opSplitter.chunks.size, 0);\n\t});\n\n\tit(\"Reconstruct original chunked op with initial chunks\", () => {\n\t\tconst op = generateChunkableOp(chunkSizeInBytes * 3);\n\t\tconst chunks = wrapChunkedOps(splitOp(op, chunkSizeInBytes), \"testClient\");\n\t\tconst opSplitter = new OpSplitter(\n\t\t\t[],\n\t\t\tmockSubmitBatchFn,\n\t\t\t0,\n\t\t\tmaxBatchSizeInBytes,\n\t\t\tmockLogger,\n\t\t);\n\t\topSplitter.processChunk(chunks[0]);\n\t\topSplitter.processChunk(chunks[1]);\n\n\t\tconst otherOpSplitter = new OpSplitter(\n\t\t\tArray.from(opSplitter.chunks),\n\t\t\tmockSubmitBatchFn,\n\t\t\t0,\n\t\t\tmaxBatchSizeInBytes,\n\t\t\tmockLogger,\n\t\t);\n\t\topSplitter.clearPartialChunks(\"testClient\");\n\n\t\totherOpSplitter.processChunk(chunks[2]);\n\n\t\tconst processResult = otherOpSplitter.processChunk(chunks[3]);\n\t\tassert.equal(processResult.isFinalChunk, true);\n\t\tassertSameMessage(processResult.message, op);\n\t});\n\n\tit(\"Clear chunks\", () => {\n\t\tconst chunks = wrapChunkedOps(\n\t\t\tsplitOp(generateChunkableOp(chunkSizeInBytes * 3), chunkSizeInBytes),\n\t\t\t\"testClient\",\n\t\t);\n\t\tconst opSplitter = new OpSplitter(\n\t\t\t[],\n\t\t\tmockSubmitBatchFn,\n\t\t\t0,\n\t\t\tmaxBatchSizeInBytes,\n\t\t\tmockLogger,\n\t\t);\n\t\topSplitter.processChunk(chunks[0]);\n\n\t\tassert.equal(opSplitter.chunks.size, 1);\n\t\topSplitter.clearPartialChunks(\"noClient\");\n\t\tassert.equal(opSplitter.chunks.size, 1);\n\t\topSplitter.clearPartialChunks(\"testClient\");\n\t\tassert.equal(opSplitter.chunks.size, 0);\n\t});\n\n\tit(\"Throw when processing out-of-order chunks\", () => {\n\t\tconst chunks = wrapChunkedOps(\n\t\t\tsplitOp(generateChunkableOp(chunkSizeInBytes * 3), chunkSizeInBytes),\n\t\t\t\"testClient1\",\n\t\t);\n\t\tconst opSplitter = new OpSplitter(\n\t\t\t[],\n\t\t\tmockSubmitBatchFn,\n\t\t\t0,\n\t\t\tmaxBatchSizeInBytes,\n\t\t\tmockLogger,\n\t\t);\n\t\tassert.throws(() => opSplitter.processChunk(chunks[2]));\n\t});\n\n\tit(\"Don't accept non-chunked ops\", () => {\n\t\tconst chunks = wrapChunkedOps(\n\t\t\tsplitOp(generateChunkableOp(chunkSizeInBytes * 3), chunkSizeInBytes),\n\t\t\t\"testClient1\",\n\t\t).map((op) => {\n\t\t\t(op.contents as any).type = ContainerMessageType.FluidDataStoreOp;\n\t\t\treturn op;\n\t\t});\n\t\tconst opSplitter = new OpSplitter(\n\t\t\t[],\n\t\t\tmockSubmitBatchFn,\n\t\t\t0,\n\t\t\tmaxBatchSizeInBytes,\n\t\t\tmockLogger,\n\t\t);\n\t\tfor (const op of chunks) {\n\t\t\tassert.deepStrictEqual(isChunkedMessage(op), false);\n\t\t\tassert.throws(() => opSplitter.processChunk(op));\n\t\t}\n\t});\n\n\tit(\"Chunk metadata\", () => {\n\t\tconst originalOp = generateChunkableOp(chunkSizeInBytes * 4);\n\t\tconst chunks = splitOp(originalOp, chunkSizeInBytes);\n\t\tassert.equal(\n\t\t\tchunks\n\t\t\t\t.slice(0, -1)\n\t\t\t\t.every(\n\t\t\t\t\t(chunk) =>\n\t\t\t\t\t\tchunk.originalCompression === undefined &&\n\t\t\t\t\t\tchunk.originalMetadata === undefined,\n\t\t\t\t),\n\t\t\ttrue,\n\t\t);\n\n\t\tconst lastChunk = chunks[chunks.length - 1];\n\t\tassert.deepStrictEqual(lastChunk.originalMetadata, originalOp.metadata);\n\t\tassert.equal(lastChunk.originalCompression, originalOp.compression);\n\t});\n\n\tit(\"Batch split invariants\", () => {\n\t\tconst opSplitter = new OpSplitter(\n\t\t\t[],\n\t\t\tmockSubmitBatchFn,\n\t\t\t50,\n\t\t\tmaxBatchSizeInBytes,\n\t\t\tmockLogger,\n\t\t);\n\t\tconst regularMessage = generateChunkableOp(20);\n\t\tconst compressedMessage = { ...regularMessage, metadata: { compressed: true } };\n\n\t\t// Empty batch\n\t\tassert.throws(() =>\n\t\t\topSplitter.splitFirstBatchMessage({\n\t\t\t\tcontent: [compressedMessage],\n\t\t\t\tcontentSizeInBytes: 0,\n\t\t\t\treferenceSequenceNumber: 0,\n\t\t\t}),\n\t\t);\n\n\t\t// Empty batch\n\t\tassert.throws(() =>\n\t\t\topSplitter.splitFirstBatchMessage({\n\t\t\t\tcontent: [],\n\t\t\t\tcontentSizeInBytes: 1,\n\t\t\t\treferenceSequenceNumber: 0,\n\t\t\t}),\n\t\t);\n\n\t\t// Batch is too small to be chunked\n\t\tassert.throws(() =>\n\t\t\topSplitter.splitFirstBatchMessage({\n\t\t\t\tcontent: [compressedMessage],\n\t\t\t\tcontentSizeInBytes: 1,\n\t\t\t\treferenceSequenceNumber: 0,\n\t\t\t}),\n\t\t);\n\n\t\t// Batch is not compressed\n\t\tassert.throws(() =>\n\t\t\topSplitter.splitFirstBatchMessage({\n\t\t\t\tcontent: [regularMessage],\n\t\t\t\tcontentSizeInBytes: 3,\n\t\t\t\treferenceSequenceNumber: 0,\n\t\t\t}),\n\t\t);\n\n\t\t// Misconfigured op splitter\n\t\tassert.throws(() =>\n\t\t\tnew OpSplitter(\n\t\t\t\t[],\n\t\t\t\tmockSubmitBatchFn,\n\t\t\t\t0,\n\t\t\t\tmaxBatchSizeInBytes,\n\t\t\t\tmockLogger,\n\t\t\t).splitFirstBatchMessage({\n\t\t\t\tcontent: [compressedMessage],\n\t\t\t\tcontentSizeInBytes: 3,\n\t\t\t\treferenceSequenceNumber: 0,\n\t\t\t}),\n\t\t);\n\n\t\t// Old loader\n\t\tassert.throws(() =>\n\t\t\tnew OpSplitter(\n\t\t\t\t[],\n\t\t\t\tundefined,\n\t\t\t\t0,\n\t\t\t\tmaxBatchSizeInBytes,\n\t\t\t\tmockLogger,\n\t\t\t).splitFirstBatchMessage({\n\t\t\t\tcontent: [compressedMessage],\n\t\t\t\tcontentSizeInBytes: 3,\n\t\t\t\treferenceSequenceNumber: 0,\n\t\t\t}),\n\t\t);\n\n\t\t// Misconfigured op splitter\n\t\tassert.throws(() =>\n\t\t\tnew OpSplitter([], mockSubmitBatchFn, 2, 1, mockLogger).splitFirstBatchMessage({\n\t\t\t\tcontent: [compressedMessage],\n\t\t\t\tcontentSizeInBytes: 3,\n\t\t\t\treferenceSequenceNumber: 0,\n\t\t\t}),\n\t\t);\n\n\t\t// Not enabled\n\t\tassert.throws(() =>\n\t\t\tnew OpSplitter(\n\t\t\t\t[],\n\t\t\t\tmockSubmitBatchFn,\n\t\t\t\tNumber.POSITIVE_INFINITY,\n\t\t\t\tmaxBatchSizeInBytes,\n\t\t\t\tmockLogger,\n\t\t\t).splitFirstBatchMessage({\n\t\t\t\tcontent: [compressedMessage],\n\t\t\t\tcontentSizeInBytes: 3,\n\t\t\t\treferenceSequenceNumber: 0,\n\t\t\t}),\n\t\t);\n\t});\n\n\tdescribe(\"Compressed batches\", () => {\n\t\t[false, true].forEach((extraOp) => {\n\t\t\tit(`Split compressed batch with multiple messages with${\n\t\t\t\textraOp ? \"\" : \"out\"\n\t\t\t} extra empty op.`, () => {\n\t\t\t\tconst chunkSize = 20;\n\t\t\t\tconst opSplitter = new OpSplitter(\n\t\t\t\t\t[],\n\t\t\t\t\tmockSubmitBatchFn,\n\t\t\t\t\tchunkSize,\n\t\t\t\t\textraOp ? chunkSize * 2 : maxBatchSizeInBytes,\n\t\t\t\t\tmockLogger,\n\t\t\t\t);\n\t\t\t\tconst largeMessage = generateChunkableOp(100);\n\t\t\t\tconst emptyMessage = generateChunkableOp(0);\n\n\t\t\t\tconst result = opSplitter.splitFirstBatchMessage({\n\t\t\t\t\tcontent: [largeMessage, emptyMessage, emptyMessage, emptyMessage],\n\t\t\t\t\tcontentSizeInBytes: largeMessage.contents?.length ?? 0,\n\t\t\t\t\treferenceSequenceNumber: 0,\n\t\t\t\t});\n\n\t\t\t\tassert.equal(batchesSubmitted.length, 5 + (extraOp ? 1 : 0));\n\t\t\t\tfor (const batch of batchesSubmitted) {\n\t\t\t\t\tassert.equal(batch.messages.length, 1);\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\ttypeFromBatchedOp(batch.messages[0]),\n\t\t\t\t\t\tContainerMessageType.ChunkedOp,\n\t\t\t\t\t);\n\t\t\t\t\tassert.equal(batch.referenceSequenceNumber, 0);\n\t\t\t\t}\n\n\t\t\t\tassert.equal(result.content.length, 4);\n\t\t\t\tconst lastChunk = JSON.parse(result.content[0].contents!).contents as IChunkedOp;\n\t\t\t\tassert.equal(lastChunk.chunkId, lastChunk.totalChunks);\n\t\t\t\tassert.deepStrictEqual(result.content.slice(1), new Array(3).fill(emptyMessage));\n\t\t\t\tassert.equal(\n\t\t\t\t\t!extraOp ||\n\t\t\t\t\t\tJSON.parse(result.content[0].contents!).contents?.contents?.length === 0,\n\t\t\t\t\ttrue,\n\t\t\t\t);\n\t\t\t\tassert.notEqual(result.contentSizeInBytes, largeMessage.contents?.length ?? 0);\n\t\t\t\tconst contentSentSeparately = batchesSubmitted.map(\n\t\t\t\t\t(x) =>\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tJSON.parse((x.messages[0] as BatchMessage).contents!)\n\t\t\t\t\t\t\t\t.contents as IChunkedOp\n\t\t\t\t\t\t).contents,\n\t\t\t\t);\n\t\t\t\tconst sentContent = [...contentSentSeparately, lastChunk.contents].reduce(\n\t\t\t\t\t(accumulator, current) => `${accumulator}${current}`,\n\t\t\t\t);\n\t\t\t\tassert.equal(sentContent, largeMessage.contents);\n\n\t\t\t\tassert(\n\t\t\t\t\tmockLogger.matchEvents([\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\teventName: \"OpSplitter:CompressedChunkedBatch\",\n\t\t\t\t\t\t\tlength: result.content.length,\n\t\t\t\t\t\t\tchunks: 100 / 20 + 1 + (extraOp ? 1 : 0),\n\t\t\t\t\t\t\tchunkSizeInBytes: 20,\n\t\t\t\t\t\t},\n\t\t\t\t\t]),\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tit(`Split compressed batch with single message with${\n\t\t\t\textraOp ? \"\" : \"out\"\n\t\t\t} extra empty op.`, () => {\n\t\t\t\tconst chunkSize = 20;\n\t\t\t\tconst opSplitter = new OpSplitter(\n\t\t\t\t\t[],\n\t\t\t\t\tmockSubmitBatchFn,\n\t\t\t\t\t20,\n\t\t\t\t\textraOp ? chunkSize * 2 : maxBatchSizeInBytes,\n\t\t\t\t\tmockLogger,\n\t\t\t\t);\n\t\t\t\tconst largeMessage = generateChunkableOp(100);\n\n\t\t\t\tconst result = opSplitter.splitFirstBatchMessage({\n\t\t\t\t\tcontent: [largeMessage],\n\t\t\t\t\tcontentSizeInBytes: largeMessage.contents?.length ?? 0,\n\t\t\t\t\treferenceSequenceNumber: 0,\n\t\t\t\t});\n\n\t\t\t\tassert.equal(batchesSubmitted.length, 5 + (extraOp ? 1 : 0));\n\t\t\t\tfor (const batch of batchesSubmitted) {\n\t\t\t\t\tassert.equal(batch.messages.length, 1);\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\ttypeFromBatchedOp(batch.messages[0]),\n\t\t\t\t\t\tContainerMessageType.ChunkedOp,\n\t\t\t\t\t);\n\t\t\t\t\tassert.equal(batch.referenceSequenceNumber, 0);\n\t\t\t\t}\n\n\t\t\t\tassert.equal(result.content.length, 1);\n\t\t\t\tassert.notEqual(result.contentSizeInBytes, largeMessage.contents?.length ?? 0);\n\t\t\t\tconst lastChunk = JSON.parse(result.content[0].contents!).contents as IChunkedOp;\n\t\t\t\tassert.equal(lastChunk.chunkId, lastChunk.totalChunks);\n\t\t\t\tassert.equal(\n\t\t\t\t\t!extraOp ||\n\t\t\t\t\t\tJSON.parse(result.content[0].contents!).contents?.contents?.length === 0,\n\t\t\t\t\ttrue,\n\t\t\t\t);\n\t\t\t\tassert.notEqual(result.contentSizeInBytes, largeMessage.contents?.length ?? 0);\n\t\t\t\tconst contentSentSeparately = batchesSubmitted.map(\n\t\t\t\t\t(x) =>\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\tJSON.parse((x.messages[0] as BatchMessage).contents!)\n\t\t\t\t\t\t\t\t.contents as IChunkedOp\n\t\t\t\t\t\t).contents,\n\t\t\t\t);\n\t\t\t\tconst sentContent = [...contentSentSeparately, lastChunk.contents].reduce(\n\t\t\t\t\t(accumulator, current) => `${accumulator}${current}`,\n\t\t\t\t);\n\t\t\t\tassert.equal(sentContent, largeMessage.contents);\n\n\t\t\t\tassert(\n\t\t\t\t\tmockLogger.matchEvents([\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\teventName: \"OpSplitter:CompressedChunkedBatch\",\n\t\t\t\t\t\t\tlength: result.content.length,\n\t\t\t\t\t\t\tchunks: 100 / 20 + 1 + (extraOp ? 1 : 0),\n\t\t\t\t\t\t\tchunkSizeInBytes: 20,\n\t\t\t\t\t\t},\n\t\t\t\t\t]),\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\t});\n\tconst assertSameMessage = (result: ISequencedDocumentMessage, original: BatchMessage) => {\n\t\tassert.deepStrictEqual(result.contents, JSON.parse(original.contents!));\n\t\t// type = \"component\" is used to force 1.3 to crash on compressed & chunked ops, as it does not understand it.\n\t\t// 2.x does not care about type, as it will get right type after decompressing the op.\n\t\t// see code & comment in splitOp()\n\t\tassert.strictEqual(result.type, \"component\");\n\t\tassert.strictEqual(result.metadata, original.metadata);\n\t\tassert.strictEqual(result.compression, original.compression);\n\t};\n\n\tconst generateChunkableOp = (contentSizeInBytes: number): BatchMessage => {\n\t\tconst contents = {\n\t\t\t// There should be a type here, but there is no validation for that,\n\t\t\t// and tests would need to be adjusted (sizing and assumptions) if we add it here.\n\t\t\t// type: ContainerMessageType.FluidDataStoreOp,\n\t\t\tvalue: crypto.randomBytes(contentSizeInBytes / 2).toString(\"hex\"),\n\t\t};\n\t\treturn {\n\t\t\treferenceSequenceNumber: Infinity,\n\t\t\tmetadata: { meta: \"data\" },\n\t\t\tcompression: CompressionAlgorithms.lz4,\n\t\t\tcontents: JSON.stringify(contents),\n\t\t};\n\t};\n\n\tconst wrapChunkedOps = (ops: IChunkedOp[], clientId: string): ISequencedDocumentMessage[] =>\n\t\tops.map((op) => {\n\t\t\tconst result = {\n\t\t\t\tcontents: {\n\t\t\t\t\ttype: ContainerMessageType.ChunkedOp,\n\t\t\t\t\tcontents: op,\n\t\t\t\t},\n\t\t\t\tclientId,\n\t\t\t};\n\n\t\t\treturn result as ISequencedDocumentMessage;\n\t\t});\n});\n"]}