@fluidframework/odsp-driver 2.0.0-dev-rc.1.0.0.232845 → 2.0.0-dev-rc.2.0.0.246488
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.cjs +18 -3
- package/{.mocharc.js → .mocharc.cjs} +1 -1
- package/CHANGELOG.md +44 -0
- package/{api-extractor-esm.json → api-extractor-cjs.json} +5 -1
- package/api-extractor-lint.json +1 -1
- package/api-extractor.json +1 -1
- package/api-report/odsp-driver.api.md +11 -12
- package/dist/ReadBufferUtils.d.ts.map +1 -1
- package/dist/ReadBufferUtils.js.map +1 -1
- package/dist/WriteBufferUtils.d.ts +1 -1
- package/dist/WriteBufferUtils.d.ts.map +1 -1
- package/dist/WriteBufferUtils.js +12 -12
- package/dist/WriteBufferUtils.js.map +1 -1
- package/dist/checkUrl.d.ts.map +1 -1
- package/dist/checkUrl.js +5 -3
- package/dist/checkUrl.js.map +1 -1
- package/dist/compactSnapshotParser.d.ts.map +1 -1
- package/dist/compactSnapshotParser.js +87 -69
- package/dist/compactSnapshotParser.js.map +1 -1
- package/dist/compactSnapshotWriter.d.ts.map +1 -1
- package/dist/compactSnapshotWriter.js +25 -19
- package/dist/compactSnapshotWriter.js.map +1 -1
- package/dist/contracts.d.ts +10 -4
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/createFile.d.ts +3 -3
- package/dist/createFile.d.ts.map +1 -1
- package/dist/createFile.js +30 -27
- package/dist/createFile.js.map +1 -1
- package/dist/createNewContainerOnExistingFile.d.ts +2 -2
- package/dist/createNewContainerOnExistingFile.d.ts.map +1 -1
- package/dist/createNewContainerOnExistingFile.js +14 -14
- package/dist/createNewContainerOnExistingFile.js.map +1 -1
- package/dist/createNewModule.d.ts +2 -2
- package/dist/createNewModule.d.ts.map +1 -1
- package/dist/createNewModule.js +4 -4
- package/dist/createNewModule.js.map +1 -1
- package/dist/createNewUtils.d.ts +2 -2
- package/dist/createNewUtils.d.ts.map +1 -1
- package/dist/createNewUtils.js +12 -8
- package/dist/createNewUtils.js.map +1 -1
- package/dist/createOdspCreateContainerRequest.d.ts.map +1 -1
- package/dist/createOdspCreateContainerRequest.js +6 -2
- package/dist/createOdspCreateContainerRequest.js.map +1 -1
- package/dist/createOdspUrl.d.ts +1 -1
- package/dist/createOdspUrl.d.ts.map +1 -1
- package/dist/createOdspUrl.js.map +1 -1
- package/dist/epochTracker.d.ts +10 -9
- package/dist/epochTracker.d.ts.map +1 -1
- package/dist/epochTracker.js +66 -43
- package/dist/epochTracker.js.map +1 -1
- package/dist/fetchSnapshot.d.ts +11 -8
- package/dist/fetchSnapshot.d.ts.map +1 -1
- package/dist/fetchSnapshot.js +79 -58
- package/dist/fetchSnapshot.js.map +1 -1
- package/dist/getFileLink.d.ts.map +1 -1
- package/dist/getFileLink.js +24 -17
- package/dist/getFileLink.js.map +1 -1
- package/dist/getQueryString.d.ts.map +1 -1
- package/dist/getQueryString.js +6 -0
- package/dist/getQueryString.js.map +1 -1
- package/dist/index.d.ts +19 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -44
- package/dist/index.js.map +1 -1
- package/dist/localOdspDriver/localOdspDocumentService.d.ts +1 -1
- package/dist/localOdspDriver/localOdspDocumentService.d.ts.map +1 -1
- package/dist/localOdspDriver/localOdspDocumentService.js +5 -5
- package/dist/localOdspDriver/localOdspDocumentService.js.map +1 -1
- package/dist/localOdspDriver/localOdspDocumentServiceFactory.d.ts +8 -6
- package/dist/localOdspDriver/localOdspDocumentServiceFactory.d.ts.map +1 -1
- package/dist/localOdspDriver/localOdspDocumentServiceFactory.js +10 -9
- package/dist/localOdspDriver/localOdspDocumentServiceFactory.js.map +1 -1
- package/dist/localOdspDriver/localOdspDocumentStorageManager.d.ts +1 -1
- package/dist/localOdspDriver/localOdspDocumentStorageManager.d.ts.map +1 -1
- package/dist/localOdspDriver/localOdspDocumentStorageManager.js +6 -6
- package/dist/localOdspDriver/localOdspDocumentStorageManager.js.map +1 -1
- package/dist/odsp-driver-alpha.d.ts +27 -12
- package/dist/odsp-driver-beta.d.ts +1 -2
- package/dist/odsp-driver-public.d.ts +1 -2
- package/dist/odsp-driver-untrimmed.d.ts +29 -12
- package/dist/odspCache.d.ts +3 -3
- package/dist/odspCache.d.ts.map +1 -1
- package/dist/odspCache.js +3 -4
- package/dist/odspCache.js.map +1 -1
- package/dist/odspDelayLoadedDeltaStream.d.ts +7 -5
- package/dist/odspDelayLoadedDeltaStream.d.ts.map +1 -1
- package/dist/odspDelayLoadedDeltaStream.js +41 -28
- package/dist/odspDelayLoadedDeltaStream.js.map +1 -1
- package/dist/odspDeltaStorageService.d.ts +7 -7
- package/dist/odspDeltaStorageService.d.ts.map +1 -1
- package/dist/odspDeltaStorageService.js +5 -5
- package/dist/odspDeltaStorageService.js.map +1 -1
- package/dist/odspDocumentDeltaConnection.d.ts +1 -1
- package/dist/odspDocumentDeltaConnection.d.ts.map +1 -1
- package/dist/odspDocumentDeltaConnection.js +41 -23
- package/dist/odspDocumentDeltaConnection.js.map +1 -1
- package/dist/odspDocumentService.d.ts +6 -4
- package/dist/odspDocumentService.d.ts.map +1 -1
- package/dist/odspDocumentService.js +19 -16
- package/dist/odspDocumentService.js.map +1 -1
- package/dist/odspDocumentServiceFactory.d.ts +6 -1
- package/dist/odspDocumentServiceFactory.d.ts.map +1 -1
- package/dist/odspDocumentServiceFactory.js +9 -4
- package/dist/odspDocumentServiceFactory.js.map +1 -1
- package/dist/odspDocumentServiceFactoryCore.d.ts +4 -4
- package/dist/odspDocumentServiceFactoryCore.d.ts.map +1 -1
- package/dist/odspDocumentServiceFactoryCore.js +26 -22
- package/dist/odspDocumentServiceFactoryCore.js.map +1 -1
- package/dist/odspDocumentServiceFactoryWithCodeSplit.d.ts +1 -1
- package/dist/odspDocumentServiceFactoryWithCodeSplit.d.ts.map +1 -1
- package/dist/odspDocumentServiceFactoryWithCodeSplit.js +2 -2
- package/dist/odspDocumentServiceFactoryWithCodeSplit.js.map +1 -1
- package/dist/odspDocumentStorageManager.d.ts +15 -9
- package/dist/odspDocumentStorageManager.d.ts.map +1 -1
- package/dist/odspDocumentStorageManager.js +219 -181
- package/dist/odspDocumentStorageManager.js.map +1 -1
- package/dist/odspDocumentStorageServiceBase.d.ts +2 -4
- package/dist/odspDocumentStorageServiceBase.d.ts.map +1 -1
- package/dist/odspDocumentStorageServiceBase.js +32 -29
- package/dist/odspDocumentStorageServiceBase.js.map +1 -1
- package/dist/odspDriverUrlResolver.d.ts +5 -1
- package/dist/odspDriverUrlResolver.d.ts.map +1 -1
- package/dist/odspDriverUrlResolver.js +27 -24
- package/dist/odspDriverUrlResolver.js.map +1 -1
- package/dist/odspDriverUrlResolverForShareLink.d.ts +17 -6
- package/dist/odspDriverUrlResolverForShareLink.d.ts.map +1 -1
- package/dist/odspDriverUrlResolverForShareLink.js +49 -39
- package/dist/odspDriverUrlResolverForShareLink.js.map +1 -1
- package/dist/odspError.d.ts +1 -1
- package/dist/odspError.d.ts.map +1 -1
- package/dist/odspError.js +5 -5
- package/dist/odspError.js.map +1 -1
- package/dist/odspFluidFileLink.d.ts +1 -1
- package/dist/odspFluidFileLink.d.ts.map +1 -1
- package/dist/odspFluidFileLink.js +2 -2
- package/dist/odspFluidFileLink.js.map +1 -1
- package/dist/odspLocationRedirection.js +2 -2
- package/dist/odspLocationRedirection.js.map +1 -1
- package/dist/odspPublicUtils.d.ts +3 -0
- package/dist/odspPublicUtils.d.ts.map +1 -1
- package/dist/odspPublicUtils.js +3 -0
- package/dist/odspPublicUtils.js.map +1 -1
- package/dist/odspSnapshotParser.d.ts +1 -1
- package/dist/odspSnapshotParser.d.ts.map +1 -1
- package/dist/odspSnapshotParser.js +3 -2
- package/dist/odspSnapshotParser.js.map +1 -1
- package/dist/odspSummaryUploadManager.d.ts +1 -1
- package/dist/odspSummaryUploadManager.d.ts.map +1 -1
- package/dist/odspSummaryUploadManager.js +9 -6
- package/dist/odspSummaryUploadManager.js.map +1 -1
- package/dist/odspUrlHelper.d.ts.map +1 -1
- package/dist/odspUrlHelper.js +1 -2
- package/dist/odspUrlHelper.js.map +1 -1
- package/dist/odspUtils.d.ts +19 -7
- package/dist/odspUtils.d.ts.map +1 -1
- package/dist/odspUtils.js +61 -31
- package/dist/odspUtils.js.map +1 -1
- package/dist/opsCaching.d.ts +1 -1
- package/dist/opsCaching.d.ts.map +1 -1
- package/dist/opsCaching.js +2 -1
- package/dist/opsCaching.js.map +1 -1
- package/dist/package.json +3 -0
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/prefetchLatestSnapshot.d.ts +2 -2
- package/dist/prefetchLatestSnapshot.d.ts.map +1 -1
- package/dist/prefetchLatestSnapshot.js +17 -12
- package/dist/prefetchLatestSnapshot.js.map +1 -1
- package/dist/retryErrorsStorageAdapter.d.ts +0 -1
- package/dist/retryErrorsStorageAdapter.d.ts.map +1 -1
- package/dist/retryErrorsStorageAdapter.js +2 -5
- package/dist/retryErrorsStorageAdapter.js.map +1 -1
- package/dist/retryUtils.d.ts.map +1 -1
- package/dist/retryUtils.js +6 -2
- package/dist/retryUtils.js.map +1 -1
- package/dist/socketModule.d.ts.map +1 -1
- package/dist/socketModule.js +2 -0
- package/dist/socketModule.js.map +1 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/dist/vroom.d.ts +2 -2
- package/dist/vroom.d.ts.map +1 -1
- package/dist/vroom.js +5 -5
- package/dist/vroom.js.map +1 -1
- package/dist/zipItDataRepresentationUtils.d.ts +1 -1
- package/dist/zipItDataRepresentationUtils.d.ts.map +1 -1
- package/dist/zipItDataRepresentationUtils.js +15 -11
- package/dist/zipItDataRepresentationUtils.js.map +1 -1
- package/lib/{ReadBufferUtils.d.mts → ReadBufferUtils.d.ts} +1 -1
- package/lib/ReadBufferUtils.d.ts.map +1 -0
- package/lib/{ReadBufferUtils.mjs → ReadBufferUtils.js} +1 -1
- package/lib/ReadBufferUtils.js.map +1 -0
- package/lib/{WriteBufferUtils.d.mts → WriteBufferUtils.d.ts} +2 -2
- package/lib/WriteBufferUtils.d.ts.map +1 -0
- package/lib/{WriteBufferUtils.mjs → WriteBufferUtils.js} +2 -2
- package/lib/WriteBufferUtils.js.map +1 -0
- package/lib/{checkUrl.d.mts → checkUrl.d.ts} +1 -1
- package/lib/checkUrl.d.ts.map +1 -0
- package/lib/{checkUrl.mjs → checkUrl.js} +5 -3
- package/lib/checkUrl.js.map +1 -0
- package/lib/{compactSnapshotParser.d.mts → compactSnapshotParser.d.ts} +1 -1
- package/lib/compactSnapshotParser.d.ts.map +1 -0
- package/lib/{compactSnapshotParser.mjs → compactSnapshotParser.js} +61 -43
- package/lib/compactSnapshotParser.js.map +1 -0
- package/lib/{compactSnapshotWriter.d.mts → compactSnapshotWriter.d.ts} +1 -1
- package/lib/compactSnapshotWriter.d.ts.map +1 -0
- package/lib/{compactSnapshotWriter.mjs → compactSnapshotWriter.js} +13 -7
- package/lib/compactSnapshotWriter.js.map +1 -0
- package/lib/{constants.d.mts → constants.d.ts} +1 -1
- package/lib/constants.d.ts.map +1 -0
- package/lib/{constants.mjs → constants.js} +1 -1
- package/lib/constants.js.map +1 -0
- package/lib/{contracts.d.mts → contracts.d.ts} +11 -5
- package/lib/contracts.d.ts.map +1 -0
- package/lib/{contracts.mjs → contracts.js} +1 -1
- package/lib/contracts.js.map +1 -0
- package/lib/{contractsPublic.d.mts → contractsPublic.d.ts} +1 -1
- package/lib/contractsPublic.d.ts.map +1 -0
- package/lib/{contractsPublic.mjs → contractsPublic.js} +1 -1
- package/lib/contractsPublic.js.map +1 -0
- package/lib/{createFile.d.mts → createFile.d.ts} +4 -4
- package/lib/createFile.d.ts.map +1 -0
- package/lib/{createFile.mjs → createFile.js} +15 -12
- package/lib/createFile.js.map +1 -0
- package/lib/{createNewContainerOnExistingFile.d.mts → createNewContainerOnExistingFile.d.ts} +3 -3
- package/lib/createNewContainerOnExistingFile.d.ts.map +1 -0
- package/lib/{createNewContainerOnExistingFile.mjs → createNewContainerOnExistingFile.js} +7 -7
- package/lib/createNewContainerOnExistingFile.js.map +1 -0
- package/lib/{createNewModule.mjs → createNewModule.d.ts} +3 -3
- package/lib/createNewModule.d.ts.map +1 -0
- package/lib/{createNewModule.d.mts → createNewModule.js} +3 -3
- package/lib/createNewModule.js.map +1 -0
- package/lib/{createNewUtils.d.mts → createNewUtils.d.ts} +3 -3
- package/lib/createNewUtils.d.ts.map +1 -0
- package/lib/{createNewUtils.mjs → createNewUtils.js} +9 -5
- package/lib/createNewUtils.js.map +1 -0
- package/lib/{createOdspCreateContainerRequest.d.mts → createOdspCreateContainerRequest.d.ts} +5 -1
- package/lib/createOdspCreateContainerRequest.d.ts.map +1 -0
- package/lib/{createOdspCreateContainerRequest.mjs → createOdspCreateContainerRequest.js} +6 -2
- package/lib/createOdspCreateContainerRequest.js.map +1 -0
- package/lib/{createOdspUrl.d.mts → createOdspUrl.d.ts} +2 -2
- package/lib/createOdspUrl.d.ts.map +1 -0
- package/lib/{createOdspUrl.mjs → createOdspUrl.js} +1 -1
- package/lib/createOdspUrl.js.map +1 -0
- package/lib/{epochTracker.d.mts → epochTracker.d.ts} +11 -10
- package/lib/epochTracker.d.ts.map +1 -0
- package/lib/{epochTracker.mjs → epochTracker.js} +56 -33
- package/lib/epochTracker.js.map +1 -0
- package/lib/{fetch.d.mts → fetch.d.ts} +1 -1
- package/lib/fetch.d.ts.map +1 -0
- package/lib/{fetch.mjs → fetch.js} +1 -1
- package/lib/fetch.js.map +1 -0
- package/lib/{fetchSnapshot.d.mts → fetchSnapshot.d.ts} +12 -9
- package/lib/fetchSnapshot.d.ts.map +1 -0
- package/lib/{fetchSnapshot.mjs → fetchSnapshot.js} +61 -40
- package/lib/fetchSnapshot.js.map +1 -0
- package/lib/{getFileLink.d.mts → getFileLink.d.ts} +1 -1
- package/lib/getFileLink.d.ts.map +1 -0
- package/lib/{getFileLink.mjs → getFileLink.js} +14 -7
- package/lib/getFileLink.js.map +1 -0
- package/lib/{getQueryString.d.mts → getQueryString.d.ts} +5 -1
- package/lib/getQueryString.d.ts.map +1 -0
- package/lib/{getQueryString.mjs → getQueryString.js} +7 -1
- package/lib/getQueryString.js.map +1 -0
- package/lib/{getUrlAndHeadersWithAuth.d.mts → getUrlAndHeadersWithAuth.d.ts} +1 -1
- package/lib/getUrlAndHeadersWithAuth.d.ts.map +1 -0
- package/lib/{getUrlAndHeadersWithAuth.mjs → getUrlAndHeadersWithAuth.js} +1 -1
- package/lib/getUrlAndHeadersWithAuth.js.map +1 -0
- package/lib/{index.d.mts → index.d.ts} +20 -20
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +29 -0
- package/lib/index.js.map +1 -0
- package/lib/localOdspDriver/{localOdspDeltaStorageService.d.mts → localOdspDeltaStorageService.d.ts} +1 -1
- package/lib/localOdspDriver/localOdspDeltaStorageService.d.ts.map +1 -0
- package/lib/localOdspDriver/{localOdspDeltaStorageService.mjs → localOdspDeltaStorageService.js} +1 -1
- package/lib/localOdspDriver/localOdspDeltaStorageService.js.map +1 -0
- package/lib/localOdspDriver/{localOdspDocumentService.d.mts → localOdspDocumentService.d.ts} +2 -2
- package/lib/localOdspDriver/localOdspDocumentService.d.ts.map +1 -0
- package/lib/localOdspDriver/{localOdspDocumentService.mjs → localOdspDocumentService.js} +4 -4
- package/lib/localOdspDriver/localOdspDocumentService.js.map +1 -0
- package/lib/localOdspDriver/{localOdspDocumentServiceFactory.d.mts → localOdspDocumentServiceFactory.d.ts} +9 -7
- package/lib/localOdspDriver/localOdspDocumentServiceFactory.d.ts.map +1 -0
- package/lib/localOdspDriver/{localOdspDocumentServiceFactory.mjs → localOdspDocumentServiceFactory.js} +9 -8
- package/lib/localOdspDriver/localOdspDocumentServiceFactory.js.map +1 -0
- package/lib/localOdspDriver/{localOdspDocumentStorageManager.d.mts → localOdspDocumentStorageManager.d.ts} +2 -2
- package/lib/localOdspDriver/localOdspDocumentStorageManager.d.ts.map +1 -0
- package/lib/localOdspDriver/{localOdspDocumentStorageManager.mjs → localOdspDocumentStorageManager.js} +4 -4
- package/lib/localOdspDriver/localOdspDocumentStorageManager.js.map +1 -0
- package/lib/{odsp-driver-alpha.d.mts → odsp-driver-alpha.d.ts} +27 -12
- package/lib/{odsp-driver-public.d.mts → odsp-driver-beta.d.ts} +1 -2
- package/lib/{odsp-driver-beta.d.mts → odsp-driver-public.d.ts} +1 -2
- package/lib/{odsp-driver-untrimmed.d.mts → odsp-driver-untrimmed.d.ts} +29 -12
- package/lib/{odspCache.d.mts → odspCache.d.ts} +8 -4
- package/lib/odspCache.d.ts.map +1 -0
- package/lib/{odspCache.mjs → odspCache.js} +6 -3
- package/lib/odspCache.js.map +1 -0
- package/lib/{odspDelayLoadedDeltaStream.d.mts → odspDelayLoadedDeltaStream.d.ts} +8 -6
- package/lib/odspDelayLoadedDeltaStream.d.ts.map +1 -0
- package/lib/{odspDelayLoadedDeltaStream.mjs → odspDelayLoadedDeltaStream.js} +33 -20
- package/lib/odspDelayLoadedDeltaStream.js.map +1 -0
- package/lib/{odspDeltaStorageService.d.mts → odspDeltaStorageService.d.ts} +8 -8
- package/lib/odspDeltaStorageService.d.ts.map +1 -0
- package/lib/{odspDeltaStorageService.mjs → odspDeltaStorageService.js} +5 -5
- package/lib/odspDeltaStorageService.js.map +1 -0
- package/lib/{odspDocumentDeltaConnection.d.mts → odspDocumentDeltaConnection.d.ts} +2 -2
- package/lib/odspDocumentDeltaConnection.d.ts.map +1 -0
- package/lib/{odspDocumentDeltaConnection.mjs → odspDocumentDeltaConnection.js} +34 -16
- package/lib/odspDocumentDeltaConnection.js.map +1 -0
- package/lib/{odspDocumentService.d.mts → odspDocumentService.d.ts} +7 -5
- package/lib/odspDocumentService.d.ts.map +1 -0
- package/lib/{odspDocumentService.mjs → odspDocumentService.js} +16 -11
- package/lib/odspDocumentService.js.map +1 -0
- package/lib/{odspDocumentServiceFactory.d.mts → odspDocumentServiceFactory.d.ts} +7 -2
- package/lib/odspDocumentServiceFactory.d.ts.map +1 -0
- package/lib/{odspDocumentServiceFactory.mjs → odspDocumentServiceFactory.js} +9 -3
- package/lib/odspDocumentServiceFactory.js.map +1 -0
- package/lib/{odspDocumentServiceFactoryCore.d.mts → odspDocumentServiceFactoryCore.d.ts} +5 -5
- package/lib/odspDocumentServiceFactoryCore.d.ts.map +1 -0
- package/lib/{odspDocumentServiceFactoryCore.mjs → odspDocumentServiceFactoryCore.js} +23 -17
- package/lib/odspDocumentServiceFactoryCore.js.map +1 -0
- package/lib/{odspDocumentServiceFactoryWithCodeSplit.d.mts → odspDocumentServiceFactoryWithCodeSplit.d.ts} +2 -2
- package/lib/odspDocumentServiceFactoryWithCodeSplit.d.ts.map +1 -0
- package/lib/{odspDocumentServiceFactoryWithCodeSplit.mjs → odspDocumentServiceFactoryWithCodeSplit.js} +2 -2
- package/lib/odspDocumentServiceFactoryWithCodeSplit.js.map +1 -0
- package/lib/{odspDocumentStorageManager.d.mts → odspDocumentStorageManager.d.ts} +16 -10
- package/lib/odspDocumentStorageManager.d.ts.map +1 -0
- package/lib/{odspDocumentStorageManager.mjs → odspDocumentStorageManager.js} +207 -167
- package/lib/odspDocumentStorageManager.js.map +1 -0
- package/lib/{odspDocumentStorageServiceBase.d.mts → odspDocumentStorageServiceBase.d.ts} +3 -5
- package/lib/odspDocumentStorageServiceBase.d.ts.map +1 -0
- package/lib/{odspDocumentStorageServiceBase.mjs → odspDocumentStorageServiceBase.js} +32 -29
- package/lib/odspDocumentStorageServiceBase.js.map +1 -0
- package/lib/{odspDriverUrlResolver.d.mts → odspDriverUrlResolver.d.ts} +6 -2
- package/lib/odspDriverUrlResolver.d.ts.map +1 -0
- package/lib/{odspDriverUrlResolver.mjs → odspDriverUrlResolver.js} +24 -17
- package/lib/odspDriverUrlResolver.js.map +1 -0
- package/lib/{odspDriverUrlResolverForShareLink.d.mts → odspDriverUrlResolverForShareLink.d.ts} +18 -7
- package/lib/odspDriverUrlResolverForShareLink.d.ts.map +1 -0
- package/lib/{odspDriverUrlResolverForShareLink.mjs → odspDriverUrlResolverForShareLink.js} +41 -27
- package/lib/odspDriverUrlResolverForShareLink.js.map +1 -0
- package/lib/{odspError.d.mts → odspError.d.ts} +2 -2
- package/lib/odspError.d.ts.map +1 -0
- package/lib/{odspError.mjs → odspError.js} +4 -4
- package/lib/odspError.js.map +1 -0
- package/lib/{odspFluidFileLink.d.mts → odspFluidFileLink.d.ts} +2 -2
- package/lib/odspFluidFileLink.d.ts.map +1 -0
- package/lib/{odspFluidFileLink.mjs → odspFluidFileLink.js} +2 -2
- package/lib/odspFluidFileLink.js.map +1 -0
- package/lib/{odspLocationRedirection.d.mts → odspLocationRedirection.d.ts} +1 -1
- package/lib/odspLocationRedirection.d.ts.map +1 -0
- package/lib/{odspLocationRedirection.mjs → odspLocationRedirection.js} +2 -2
- package/lib/odspLocationRedirection.js.map +1 -0
- package/lib/{odspPublicUtils.d.mts → odspPublicUtils.d.ts} +4 -1
- package/lib/odspPublicUtils.d.ts.map +1 -0
- package/lib/{odspPublicUtils.mjs → odspPublicUtils.js} +4 -1
- package/lib/odspPublicUtils.js.map +1 -0
- package/lib/{odspSnapshotParser.d.mts → odspSnapshotParser.d.ts} +2 -2
- package/lib/odspSnapshotParser.d.ts.map +1 -0
- package/lib/{odspSnapshotParser.mjs → odspSnapshotParser.js} +4 -3
- package/lib/odspSnapshotParser.js.map +1 -0
- package/lib/{odspSummaryUploadManager.d.mts → odspSummaryUploadManager.d.ts} +2 -2
- package/lib/odspSummaryUploadManager.d.ts.map +1 -0
- package/lib/{odspSummaryUploadManager.mjs → odspSummaryUploadManager.js} +8 -5
- package/lib/odspSummaryUploadManager.js.map +1 -0
- package/lib/{odspUrlHelper.d.mts → odspUrlHelper.d.ts} +1 -1
- package/lib/odspUrlHelper.d.ts.map +1 -0
- package/lib/{odspUrlHelper.mjs → odspUrlHelper.js} +2 -3
- package/lib/odspUrlHelper.js.map +1 -0
- package/lib/{odspUtils.d.mts → odspUtils.d.ts} +20 -8
- package/lib/odspUtils.d.ts.map +1 -0
- package/lib/{odspUtils.mjs → odspUtils.js} +45 -17
- package/lib/odspUtils.js.map +1 -0
- package/lib/{opsCaching.d.mts → opsCaching.d.ts} +2 -2
- package/lib/opsCaching.d.ts.map +1 -0
- package/lib/{opsCaching.mjs → opsCaching.js} +3 -2
- package/lib/opsCaching.js.map +1 -0
- package/lib/{packageVersion.d.mts → packageVersion.d.ts} +2 -2
- package/lib/packageVersion.d.ts.map +1 -0
- package/lib/{packageVersion.mjs → packageVersion.js} +2 -2
- package/lib/packageVersion.js.map +1 -0
- package/lib/{prefetchLatestSnapshot.d.mts → prefetchLatestSnapshot.d.ts} +3 -3
- package/lib/prefetchLatestSnapshot.d.ts.map +1 -0
- package/lib/{prefetchLatestSnapshot.mjs → prefetchLatestSnapshot.js} +16 -11
- package/lib/prefetchLatestSnapshot.js.map +1 -0
- package/lib/{retryErrorsStorageAdapter.d.mts → retryErrorsStorageAdapter.d.ts} +1 -2
- package/lib/retryErrorsStorageAdapter.d.ts.map +1 -0
- package/lib/{retryErrorsStorageAdapter.mjs → retryErrorsStorageAdapter.js} +2 -5
- package/lib/retryErrorsStorageAdapter.js.map +1 -0
- package/lib/{retryUtils.d.mts → retryUtils.d.ts} +1 -1
- package/lib/retryUtils.d.ts.map +1 -0
- package/lib/{retryUtils.mjs → retryUtils.js} +6 -2
- package/lib/retryUtils.js.map +1 -0
- package/lib/{socketModule.d.mts → socketModule.d.ts} +1 -1
- package/lib/socketModule.d.ts.map +1 -0
- package/lib/{socketModule.mjs → socketModule.js} +3 -1
- package/lib/socketModule.js.map +1 -0
- package/lib/test/buildOdspShareLinkReqParams.spec.js +25 -0
- package/lib/test/buildOdspShareLinkReqParams.spec.js.map +1 -0
- package/lib/test/createNewUtilsTests.spec.js +221 -0
- package/lib/test/createNewUtilsTests.spec.js.map +1 -0
- package/lib/test/deltaStorageService.spec.js +176 -0
- package/lib/test/deltaStorageService.spec.js.map +1 -0
- package/lib/test/epochTests.spec.js +340 -0
- package/lib/test/epochTests.spec.js.map +1 -0
- package/lib/test/epochTestsWithRedemption.spec.js +119 -0
- package/lib/test/epochTestsWithRedemption.spec.js.map +1 -0
- package/lib/test/fetchSnapshot.spec.js +412 -0
- package/lib/test/fetchSnapshot.spec.js.map +1 -0
- package/lib/test/getFileLink.spec.js +62 -0
- package/lib/test/getFileLink.spec.js.map +1 -0
- package/lib/test/getUrlAndHeadersWithAuth.spec.js +66 -0
- package/lib/test/getUrlAndHeadersWithAuth.spec.js.map +1 -0
- package/lib/test/getVersions.spec.js +284 -0
- package/lib/test/getVersions.spec.js.map +1 -0
- package/lib/test/joinSessionCacheTests.spec.js +53 -0
- package/lib/test/joinSessionCacheTests.spec.js.map +1 -0
- package/lib/test/joinSessionPeriodicCall.spec.js +158 -0
- package/lib/test/joinSessionPeriodicCall.spec.js.map +1 -0
- package/lib/test/jsonSnapshotFormatTests.spec.js +107 -0
- package/lib/test/jsonSnapshotFormatTests.spec.js.map +1 -0
- package/lib/test/localOdspDriver.spec.js +177 -0
- package/lib/test/localOdspDriver.spec.js.map +1 -0
- package/lib/test/mockFetch.js +61 -0
- package/lib/test/mockFetch.js.map +1 -0
- package/lib/test/odspCreateContainer.spec.js +116 -0
- package/lib/test/odspCreateContainer.spec.js.map +1 -0
- package/lib/test/odspDriverResolverTest.spec.js +289 -0
- package/lib/test/odspDriverResolverTest.spec.js.map +1 -0
- package/lib/test/odspDriverUrlResolverForShareLink.spec.js +287 -0
- package/lib/test/odspDriverUrlResolverForShareLink.spec.js.map +1 -0
- package/lib/test/odspError.spec.js +299 -0
- package/lib/test/odspError.spec.js.map +1 -0
- package/lib/test/opsCaching.spec.js +357 -0
- package/lib/test/opsCaching.spec.js.map +1 -0
- package/lib/test/prefetchSnapshotTests.spec.js +420 -0
- package/lib/test/prefetchSnapshotTests.spec.js.map +1 -0
- package/lib/test/snapshotFormatTests.spec.js +218 -0
- package/lib/test/snapshotFormatTests.spec.js.map +1 -0
- package/lib/test/socketTests/deltaConnectionUpdateTests.spec.js +152 -0
- package/lib/test/socketTests/deltaConnectionUpdateTests.spec.js.map +1 -0
- package/lib/test/socketTests/socketMock.js +109 -0
- package/lib/test/socketTests/socketMock.js.map +1 -0
- package/lib/test/socketTests/socketTests.spec.js +256 -0
- package/lib/test/socketTests/socketTests.spec.js.map +1 -0
- package/lib/test/tokenFetch.spec.js +39 -0
- package/lib/test/tokenFetch.spec.js.map +1 -0
- package/lib/test/types/validateOdspDriverPrevious.generated.js +96 -0
- package/lib/test/types/validateOdspDriverPrevious.generated.js.map +1 -0
- package/lib/test/zipItDataRepresentationTests.spec.js +207 -0
- package/lib/test/zipItDataRepresentationTests.spec.js.map +1 -0
- package/lib/{vroom.d.mts → vroom.d.ts} +3 -3
- package/lib/vroom.d.ts.map +1 -0
- package/lib/{vroom.mjs → vroom.js} +4 -4
- package/lib/vroom.js.map +1 -0
- package/lib/{zipItDataRepresentationUtils.d.mts → zipItDataRepresentationUtils.d.ts} +2 -2
- package/lib/zipItDataRepresentationUtils.d.ts.map +1 -0
- package/lib/{zipItDataRepresentationUtils.mjs → zipItDataRepresentationUtils.js} +17 -9
- package/lib/zipItDataRepresentationUtils.js.map +1 -0
- package/package.json +90 -31
- package/src/ReadBufferUtils.ts +7 -7
- package/src/WriteBufferUtils.ts +13 -9
- package/src/checkUrl.ts +4 -2
- package/src/compactSnapshotParser.ts +87 -52
- package/src/compactSnapshotWriter.ts +19 -12
- package/src/contracts.ts +16 -4
- package/src/createFile.ts +16 -13
- package/src/createNewContainerOnExistingFile.ts +8 -8
- package/src/createNewModule.ts +2 -2
- package/src/createNewUtils.ts +19 -9
- package/src/createOdspCreateContainerRequest.ts +2 -1
- package/src/createOdspUrl.ts +1 -1
- package/src/epochTracker.ts +90 -55
- package/src/fetchSnapshot.ts +104 -47
- package/src/getFileLink.ts +21 -13
- package/src/getQueryString.ts +3 -0
- package/src/index.ts +27 -19
- package/src/localOdspDriver/localOdspDocumentService.ts +3 -3
- package/src/localOdspDriver/localOdspDocumentServiceFactory.ts +12 -11
- package/src/localOdspDriver/localOdspDocumentStorageManager.ts +5 -5
- package/src/odspCache.ts +13 -9
- package/src/odspDelayLoadedDeltaStream.ts +54 -33
- package/src/odspDeltaStorageService.ts +17 -16
- package/src/odspDocumentDeltaConnection.ts +52 -34
- package/src/odspDocumentService.ts +23 -20
- package/src/odspDocumentServiceFactory.ts +7 -2
- package/src/odspDocumentServiceFactoryCore.ts +25 -18
- package/src/odspDocumentServiceFactoryWithCodeSplit.ts +1 -1
- package/src/odspDocumentStorageManager.ts +276 -216
- package/src/odspDocumentStorageServiceBase.ts +45 -43
- package/src/odspDriverUrlResolver.ts +39 -24
- package/src/odspDriverUrlResolverForShareLink.ts +51 -31
- package/src/odspError.ts +4 -4
- package/src/odspFluidFileLink.ts +3 -3
- package/src/odspLocationRedirection.ts +1 -1
- package/src/odspPublicUtils.ts +3 -0
- package/src/odspSnapshotParser.ts +4 -3
- package/src/odspSummaryUploadManager.ts +21 -9
- package/src/odspUrlHelper.ts +2 -3
- package/src/odspUtils.ts +73 -30
- package/src/opsCaching.ts +13 -12
- package/src/packageVersion.ts +1 -1
- package/src/prefetchLatestSnapshot.ts +24 -15
- package/src/retryErrorsStorageAdapter.ts +4 -8
- package/src/retryUtils.ts +6 -2
- package/src/socketModule.ts +2 -0
- package/src/vroom.ts +6 -6
- package/src/zipItDataRepresentationUtils.ts +63 -35
- package/tsconfig.cjs.json +7 -0
- package/tsconfig.json +2 -5
- package/lib/ReadBufferUtils.d.mts.map +0 -1
- package/lib/ReadBufferUtils.mjs.map +0 -1
- package/lib/WriteBufferUtils.d.mts.map +0 -1
- package/lib/WriteBufferUtils.mjs.map +0 -1
- package/lib/checkUrl.d.mts.map +0 -1
- package/lib/checkUrl.mjs.map +0 -1
- package/lib/compactSnapshotParser.d.mts.map +0 -1
- package/lib/compactSnapshotParser.mjs.map +0 -1
- package/lib/compactSnapshotWriter.d.mts.map +0 -1
- package/lib/compactSnapshotWriter.mjs.map +0 -1
- package/lib/constants.d.mts.map +0 -1
- package/lib/constants.mjs.map +0 -1
- package/lib/contracts.d.mts.map +0 -1
- package/lib/contracts.mjs.map +0 -1
- package/lib/contractsPublic.d.mts.map +0 -1
- package/lib/contractsPublic.mjs.map +0 -1
- package/lib/createFile.d.mts.map +0 -1
- package/lib/createFile.mjs.map +0 -1
- package/lib/createNewContainerOnExistingFile.d.mts.map +0 -1
- package/lib/createNewContainerOnExistingFile.mjs.map +0 -1
- package/lib/createNewModule.d.mts.map +0 -1
- package/lib/createNewModule.mjs.map +0 -1
- package/lib/createNewUtils.d.mts.map +0 -1
- package/lib/createNewUtils.mjs.map +0 -1
- package/lib/createOdspCreateContainerRequest.d.mts.map +0 -1
- package/lib/createOdspCreateContainerRequest.mjs.map +0 -1
- package/lib/createOdspUrl.d.mts.map +0 -1
- package/lib/createOdspUrl.mjs.map +0 -1
- package/lib/epochTracker.d.mts.map +0 -1
- package/lib/epochTracker.mjs.map +0 -1
- package/lib/fetch.d.mts.map +0 -1
- package/lib/fetch.mjs.map +0 -1
- package/lib/fetchSnapshot.d.mts.map +0 -1
- package/lib/fetchSnapshot.mjs.map +0 -1
- package/lib/getFileLink.d.mts.map +0 -1
- package/lib/getFileLink.mjs.map +0 -1
- package/lib/getQueryString.d.mts.map +0 -1
- package/lib/getQueryString.mjs.map +0 -1
- package/lib/getUrlAndHeadersWithAuth.d.mts.map +0 -1
- package/lib/getUrlAndHeadersWithAuth.mjs.map +0 -1
- package/lib/index.d.mts.map +0 -1
- package/lib/index.mjs +0 -22
- package/lib/index.mjs.map +0 -1
- package/lib/localOdspDriver/localOdspDeltaStorageService.d.mts.map +0 -1
- package/lib/localOdspDriver/localOdspDeltaStorageService.mjs.map +0 -1
- package/lib/localOdspDriver/localOdspDocumentService.d.mts.map +0 -1
- package/lib/localOdspDriver/localOdspDocumentService.mjs.map +0 -1
- package/lib/localOdspDriver/localOdspDocumentServiceFactory.d.mts.map +0 -1
- package/lib/localOdspDriver/localOdspDocumentServiceFactory.mjs.map +0 -1
- package/lib/localOdspDriver/localOdspDocumentStorageManager.d.mts.map +0 -1
- package/lib/localOdspDriver/localOdspDocumentStorageManager.mjs.map +0 -1
- package/lib/odspCache.d.mts.map +0 -1
- package/lib/odspCache.mjs.map +0 -1
- package/lib/odspDelayLoadedDeltaStream.d.mts.map +0 -1
- package/lib/odspDelayLoadedDeltaStream.mjs.map +0 -1
- package/lib/odspDeltaStorageService.d.mts.map +0 -1
- package/lib/odspDeltaStorageService.mjs.map +0 -1
- package/lib/odspDocumentDeltaConnection.d.mts.map +0 -1
- package/lib/odspDocumentDeltaConnection.mjs.map +0 -1
- package/lib/odspDocumentService.d.mts.map +0 -1
- package/lib/odspDocumentService.mjs.map +0 -1
- package/lib/odspDocumentServiceFactory.d.mts.map +0 -1
- package/lib/odspDocumentServiceFactory.mjs.map +0 -1
- package/lib/odspDocumentServiceFactoryCore.d.mts.map +0 -1
- package/lib/odspDocumentServiceFactoryCore.mjs.map +0 -1
- package/lib/odspDocumentServiceFactoryWithCodeSplit.d.mts.map +0 -1
- package/lib/odspDocumentServiceFactoryWithCodeSplit.mjs.map +0 -1
- package/lib/odspDocumentStorageManager.d.mts.map +0 -1
- package/lib/odspDocumentStorageManager.mjs.map +0 -1
- package/lib/odspDocumentStorageServiceBase.d.mts.map +0 -1
- package/lib/odspDocumentStorageServiceBase.mjs.map +0 -1
- package/lib/odspDriverUrlResolver.d.mts.map +0 -1
- package/lib/odspDriverUrlResolver.mjs.map +0 -1
- package/lib/odspDriverUrlResolverForShareLink.d.mts.map +0 -1
- package/lib/odspDriverUrlResolverForShareLink.mjs.map +0 -1
- package/lib/odspError.d.mts.map +0 -1
- package/lib/odspError.mjs.map +0 -1
- package/lib/odspFluidFileLink.d.mts.map +0 -1
- package/lib/odspFluidFileLink.mjs.map +0 -1
- package/lib/odspLocationRedirection.d.mts.map +0 -1
- package/lib/odspLocationRedirection.mjs.map +0 -1
- package/lib/odspPublicUtils.d.mts.map +0 -1
- package/lib/odspPublicUtils.mjs.map +0 -1
- package/lib/odspSnapshotParser.d.mts.map +0 -1
- package/lib/odspSnapshotParser.mjs.map +0 -1
- package/lib/odspSummaryUploadManager.d.mts.map +0 -1
- package/lib/odspSummaryUploadManager.mjs.map +0 -1
- package/lib/odspUrlHelper.d.mts.map +0 -1
- package/lib/odspUrlHelper.mjs.map +0 -1
- package/lib/odspUtils.d.mts.map +0 -1
- package/lib/odspUtils.mjs.map +0 -1
- package/lib/opsCaching.d.mts.map +0 -1
- package/lib/opsCaching.mjs.map +0 -1
- package/lib/packageVersion.d.mts.map +0 -1
- package/lib/packageVersion.mjs.map +0 -1
- package/lib/prefetchLatestSnapshot.d.mts.map +0 -1
- package/lib/prefetchLatestSnapshot.mjs.map +0 -1
- package/lib/retryErrorsStorageAdapter.d.mts.map +0 -1
- package/lib/retryErrorsStorageAdapter.mjs.map +0 -1
- package/lib/retryUtils.d.mts.map +0 -1
- package/lib/retryUtils.mjs.map +0 -1
- package/lib/socketModule.d.mts.map +0 -1
- package/lib/socketModule.mjs.map +0 -1
- package/lib/vroom.d.mts.map +0 -1
- package/lib/vroom.mjs.map +0 -1
- package/lib/zipItDataRepresentationUtils.d.mts.map +0 -1
- package/lib/zipItDataRepresentationUtils.mjs.map +0 -1
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { strict as assert } from "node:assert";
|
|
6
|
+
import { OdspErrorTypes, maximumCacheDurationMs, } from "@fluidframework/odsp-driver-definitions";
|
|
7
|
+
import { ThrottlingError } from "@fluidframework/driver-utils";
|
|
8
|
+
import { createChildLogger } from "@fluidframework/telemetry-utils";
|
|
9
|
+
import { stub } from "sinon";
|
|
10
|
+
import { persistedCacheValueVersion } from "../contracts.js";
|
|
11
|
+
import { EpochTracker } from "../epochTracker.js";
|
|
12
|
+
import { LocalPersistentCache } from "../odspCache.js";
|
|
13
|
+
import { getHashedDocumentId } from "../odspPublicUtils.js";
|
|
14
|
+
import * as odspUtilsModule from "../odspUtils.js";
|
|
15
|
+
import { mockFetchOk, mockFetchSingle, createResponse } from "./mockFetch.js";
|
|
16
|
+
const createUtLocalCache = () => new LocalPersistentCache();
|
|
17
|
+
describe("Tests for Epoch Tracker", () => {
|
|
18
|
+
const siteUrl = "https://microsoft.sharepoint-df.com/siteUrl";
|
|
19
|
+
const driveId = "driveId";
|
|
20
|
+
const itemId = "itemId";
|
|
21
|
+
let epochTracker;
|
|
22
|
+
let localCache;
|
|
23
|
+
let hashedDocumentId;
|
|
24
|
+
const resolvedUrl = {
|
|
25
|
+
siteUrl,
|
|
26
|
+
driveId,
|
|
27
|
+
itemId,
|
|
28
|
+
odspResolvedUrl: true,
|
|
29
|
+
};
|
|
30
|
+
before(async () => {
|
|
31
|
+
hashedDocumentId = await getHashedDocumentId(driveId, itemId);
|
|
32
|
+
});
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
localCache = createUtLocalCache();
|
|
35
|
+
// use null logger here as we expect errors
|
|
36
|
+
epochTracker = new EpochTracker(localCache, {
|
|
37
|
+
docId: hashedDocumentId,
|
|
38
|
+
resolvedUrl,
|
|
39
|
+
}, createChildLogger());
|
|
40
|
+
});
|
|
41
|
+
afterEach(async () => {
|
|
42
|
+
await epochTracker.removeEntries().catch(() => { });
|
|
43
|
+
});
|
|
44
|
+
it("defaultCacheExpiryTimeoutMs <= maximumCacheDurationMs policy", () => {
|
|
45
|
+
// This is the maximum allowed value per the policy - 5 days
|
|
46
|
+
const expected = 432000000;
|
|
47
|
+
assert(maximumCacheDurationMs <= expected, "Actual cache expiry used must meet the policy");
|
|
48
|
+
});
|
|
49
|
+
it("Cache, old versions", async () => {
|
|
50
|
+
const cacheEntry1 = {
|
|
51
|
+
key: "key1",
|
|
52
|
+
type: "snapshot",
|
|
53
|
+
file: { docId: hashedDocumentId, resolvedUrl },
|
|
54
|
+
};
|
|
55
|
+
const cacheEntry2 = { ...cacheEntry1, key: "key2" };
|
|
56
|
+
const cacheValue1 = { val: "val1", cacheEntryTime: Date.now() };
|
|
57
|
+
const cacheValue2 = { val: "val2", cacheEntryTime: Date.now() };
|
|
58
|
+
const value1 = {
|
|
59
|
+
value: cacheValue1,
|
|
60
|
+
fluidEpoch: "epoch1",
|
|
61
|
+
version: persistedCacheValueVersion,
|
|
62
|
+
};
|
|
63
|
+
const value2 = {
|
|
64
|
+
value: cacheValue2,
|
|
65
|
+
fluidEpoch: "epoch1",
|
|
66
|
+
version: "non-existing version",
|
|
67
|
+
};
|
|
68
|
+
await localCache.put(cacheEntry1, value1);
|
|
69
|
+
await localCache.put(cacheEntry2, value2);
|
|
70
|
+
// This will set the initial epoch value in epoch tracker.
|
|
71
|
+
assert((await epochTracker.get(cacheEntry1)) === cacheValue1, "Entry 1 should continue to exist");
|
|
72
|
+
// This should not fail, just return nothing!
|
|
73
|
+
await epochTracker.get(cacheEntry2);
|
|
74
|
+
// Make sure nothing changed as result of reading data.
|
|
75
|
+
assert((await epochTracker.get(cacheEntry1)) === cacheValue1, "Entry 1 should continue to exist");
|
|
76
|
+
assert((await epochTracker.get(cacheEntry2)) === undefined, "Entry 2 should not exist");
|
|
77
|
+
});
|
|
78
|
+
it("Epoch error when fetch error from cache should throw epoch error and clear cache", async () => {
|
|
79
|
+
const cacheEntry1 = {
|
|
80
|
+
key: "key1",
|
|
81
|
+
type: "snapshot",
|
|
82
|
+
file: { docId: hashedDocumentId, resolvedUrl },
|
|
83
|
+
};
|
|
84
|
+
const cacheEntry2 = { ...cacheEntry1, key: "key2" };
|
|
85
|
+
const cacheValue1 = { val: "val1", cacheEntryTime: Date.now() };
|
|
86
|
+
const cacheValue2 = { val: "val2", cacheEntryTime: Date.now() };
|
|
87
|
+
const value1 = {
|
|
88
|
+
value: cacheValue1,
|
|
89
|
+
fluidEpoch: "epoch1",
|
|
90
|
+
version: persistedCacheValueVersion,
|
|
91
|
+
};
|
|
92
|
+
const value2 = {
|
|
93
|
+
value: cacheValue2,
|
|
94
|
+
fluidEpoch: "epoch2",
|
|
95
|
+
version: persistedCacheValueVersion,
|
|
96
|
+
};
|
|
97
|
+
await localCache.put(cacheEntry1, value1);
|
|
98
|
+
await localCache.put(cacheEntry2, value2);
|
|
99
|
+
// This will set the initial epoch value in epoch tracker.
|
|
100
|
+
assert((await epochTracker.get(cacheEntry1)) === cacheValue1, "Entry 1 should continue to exist");
|
|
101
|
+
// This should not fail, just return nothing!
|
|
102
|
+
await epochTracker.get(cacheEntry2);
|
|
103
|
+
// Make sure nothing changed as result of reading data.
|
|
104
|
+
assert((await epochTracker.get(cacheEntry1)) === cacheValue1, "Entry 1 should continue to exist");
|
|
105
|
+
assert((await epochTracker.get(cacheEntry2)) === undefined, "Entry 2 should not exist");
|
|
106
|
+
});
|
|
107
|
+
it("Epoch error when fetch response and should clear cache", async () => {
|
|
108
|
+
let success = true;
|
|
109
|
+
const cacheEntry1 = {
|
|
110
|
+
key: "key1",
|
|
111
|
+
type: "snapshot",
|
|
112
|
+
};
|
|
113
|
+
epochTracker.setEpoch("epoch1", true, "test");
|
|
114
|
+
await epochTracker.put(cacheEntry1, { val: "val1" });
|
|
115
|
+
// This will set the initial epoch value in epoch tracker.
|
|
116
|
+
await epochTracker.get(cacheEntry1);
|
|
117
|
+
try {
|
|
118
|
+
await mockFetchOk(async () => epochTracker.fetchArray("fetchUrl", {}, "test"), {}, { "x-fluid-epoch": "epoch2" });
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
success = false;
|
|
122
|
+
assert.strictEqual(error.errorType, OdspErrorTypes.fileOverwrittenInStorage, "Error should be epoch error");
|
|
123
|
+
}
|
|
124
|
+
assert((await epochTracker.get(cacheEntry1)) === undefined, "Entry in cache should be cleared");
|
|
125
|
+
assert.strictEqual(success, false, "Fetching should fail!!");
|
|
126
|
+
});
|
|
127
|
+
it("Epoch error when fetch response as json and should clear cache", async () => {
|
|
128
|
+
let success = true;
|
|
129
|
+
const cacheEntry1 = {
|
|
130
|
+
key: "key1",
|
|
131
|
+
type: "snapshot",
|
|
132
|
+
};
|
|
133
|
+
epochTracker.setEpoch("epoch1", true, "test");
|
|
134
|
+
await epochTracker.put(cacheEntry1, { val: "val1" });
|
|
135
|
+
// This will set the initial epoch value in epoch tracker.
|
|
136
|
+
await epochTracker.get(cacheEntry1);
|
|
137
|
+
try {
|
|
138
|
+
await mockFetchOk(async () => epochTracker.fetchAndParseAsJSON("fetchUrl", {}, "test"), {}, { "x-fluid-epoch": "epoch2" });
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
success = false;
|
|
142
|
+
assert.strictEqual(error.errorType, OdspErrorTypes.fileOverwrittenInStorage, "Error should be epoch error");
|
|
143
|
+
}
|
|
144
|
+
assert((await epochTracker.get(cacheEntry1)) === undefined, "Entry in cache should be cleared");
|
|
145
|
+
assert.strictEqual(success, false, "Fetching should fail!!");
|
|
146
|
+
});
|
|
147
|
+
it("Check client correlationID on error in unsuccessful fetch case", async () => {
|
|
148
|
+
let success = true;
|
|
149
|
+
const cacheEntry1 = {
|
|
150
|
+
key: "key1",
|
|
151
|
+
type: "snapshot",
|
|
152
|
+
};
|
|
153
|
+
epochTracker.setEpoch("epoch1", true, "test");
|
|
154
|
+
await epochTracker.put(cacheEntry1, { val: "val1" });
|
|
155
|
+
// This will set the initial epoch value in epoch tracker.
|
|
156
|
+
await epochTracker.get(cacheEntry1);
|
|
157
|
+
try {
|
|
158
|
+
await mockFetchOk(async () => epochTracker.fetchAndParseAsJSON("fetchUrl", {}, "test"), {}, { "x-fluid-epoch": "epoch2" });
|
|
159
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
success = false;
|
|
163
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
164
|
+
assert(error.XRequestStatsHeader !== undefined, "CorrelationId should be present");
|
|
165
|
+
}
|
|
166
|
+
assert.strictEqual(success, false, "Fetching should fail!!");
|
|
167
|
+
});
|
|
168
|
+
it("Check client correlationID on spoCommonHeaders in successful fetch case", async () => {
|
|
169
|
+
const cacheEntry1 = {
|
|
170
|
+
key: "key1",
|
|
171
|
+
type: "snapshot",
|
|
172
|
+
};
|
|
173
|
+
epochTracker.setEpoch("epoch1", true, "test");
|
|
174
|
+
await epochTracker.put(cacheEntry1, { val: "val1" });
|
|
175
|
+
// This will set the initial epoch value in epoch tracker.
|
|
176
|
+
await epochTracker.get(cacheEntry1);
|
|
177
|
+
const response = await mockFetchOk(async () => epochTracker.fetchAndParseAsJSON("fetchUrl", {}, "test"), {}, { "x-fluid-epoch": "epoch1" });
|
|
178
|
+
assert(response.propsToLog.XRequestStatsHeader !== undefined, "CorrelationId should be present");
|
|
179
|
+
});
|
|
180
|
+
it("Epoch error should not occur if response does not contain epoch", async () => {
|
|
181
|
+
let success = true;
|
|
182
|
+
const cacheEntry1 = {
|
|
183
|
+
key: "key1",
|
|
184
|
+
type: "snapshot",
|
|
185
|
+
};
|
|
186
|
+
epochTracker.setEpoch("epoch1", true, "test");
|
|
187
|
+
await epochTracker.put(cacheEntry1, { val: "val1" });
|
|
188
|
+
// This will set the initial epoch value in epoch tracker.
|
|
189
|
+
await epochTracker.get(cacheEntry1);
|
|
190
|
+
try {
|
|
191
|
+
await mockFetchOk(async () => epochTracker.fetchArray("fetchUrl", {}, "test"));
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
success = false;
|
|
195
|
+
}
|
|
196
|
+
assert.strictEqual(success, true, "Fetching should succeed!!");
|
|
197
|
+
assert.strictEqual(
|
|
198
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, unicorn/no-await-expression-member
|
|
199
|
+
(await epochTracker.get(cacheEntry1)).val, "val1", "Entry in cache should be present");
|
|
200
|
+
});
|
|
201
|
+
it("Epoch error should not occur if response contains same epoch", async () => {
|
|
202
|
+
let success = true;
|
|
203
|
+
const cacheEntry1 = {
|
|
204
|
+
key: "key1",
|
|
205
|
+
type: "snapshot",
|
|
206
|
+
};
|
|
207
|
+
epochTracker.setEpoch("epoch1", true, "test");
|
|
208
|
+
await epochTracker.put(cacheEntry1, { val: "val1" });
|
|
209
|
+
// This will set the initial epoch value in epoch tracker.
|
|
210
|
+
await epochTracker.get(cacheEntry1);
|
|
211
|
+
try {
|
|
212
|
+
await mockFetchOk(async () => epochTracker.fetchAndParseAsJSON("fetchUrl", {}, "test"), {}, { "x-fluid-epoch": "epoch1" });
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
success = false;
|
|
216
|
+
}
|
|
217
|
+
assert.strictEqual(success, true, "Fetching should succeed!!");
|
|
218
|
+
assert.strictEqual(
|
|
219
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, unicorn/no-await-expression-member
|
|
220
|
+
(await epochTracker.get(cacheEntry1)).val, "val1", "Entry in cache should be present");
|
|
221
|
+
});
|
|
222
|
+
it("Should differentiate between epoch and coherency 409 errors when coherency 409", async () => {
|
|
223
|
+
let success = true;
|
|
224
|
+
const cacheEntry1 = {
|
|
225
|
+
key: "key1",
|
|
226
|
+
type: "snapshot",
|
|
227
|
+
};
|
|
228
|
+
epochTracker.setEpoch("epoch1", true, "test");
|
|
229
|
+
await epochTracker.put(cacheEntry1, { val: "val1" });
|
|
230
|
+
// This will set the initial epoch value in epoch tracker.
|
|
231
|
+
await epochTracker.get(cacheEntry1);
|
|
232
|
+
try {
|
|
233
|
+
await mockFetchSingle(async () => epochTracker.fetchAndParseAsJSON("fetchUrl", {}, "test"), async () => createResponse({ "x-fluid-epoch": "epoch1" }, undefined, 409));
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
success = false;
|
|
237
|
+
assert.strictEqual(error.errorType, OdspErrorTypes.throttlingError, "Error should be throttling error");
|
|
238
|
+
}
|
|
239
|
+
assert.strictEqual(success, false, "Fetching should not succeed!!");
|
|
240
|
+
assert.strictEqual(
|
|
241
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, unicorn/no-await-expression-member
|
|
242
|
+
(await epochTracker.get(cacheEntry1)).val, "val1", "Entry in cache should be present because it was not epoch 409");
|
|
243
|
+
});
|
|
244
|
+
it("Should differentiate between epoch and coherency 409 errors when epoch 409", async () => {
|
|
245
|
+
let success = true;
|
|
246
|
+
const cacheEntry1 = {
|
|
247
|
+
key: "key1",
|
|
248
|
+
type: "snapshot",
|
|
249
|
+
};
|
|
250
|
+
epochTracker.setEpoch("epoch1", true, "test");
|
|
251
|
+
await epochTracker.put(cacheEntry1, { val: "val1" });
|
|
252
|
+
// This will set the initial epoch value in epoch tracker.
|
|
253
|
+
await epochTracker.get(cacheEntry1);
|
|
254
|
+
try {
|
|
255
|
+
await mockFetchSingle(async () => epochTracker.fetchAndParseAsJSON("fetchUrl", {}, "test"), async () => createResponse({ "x-fluid-epoch": "epoch2" }, undefined, 409));
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
success = false;
|
|
259
|
+
assert.strictEqual(error.errorType, OdspErrorTypes.fileOverwrittenInStorage, "Error should be epoch error");
|
|
260
|
+
}
|
|
261
|
+
assert.strictEqual(success, false, "Fetching should not succeed!!");
|
|
262
|
+
assert((await epochTracker.get(cacheEntry1)) === undefined, "Entry in cache should be absent because it was epoch 409");
|
|
263
|
+
});
|
|
264
|
+
it("Check for resolved url on LocationRedirection error", async () => {
|
|
265
|
+
let success = true;
|
|
266
|
+
const newSiteUrl = "https://microsoft.sharepoint.com/siteUrl";
|
|
267
|
+
try {
|
|
268
|
+
await mockFetchSingle(async () => epochTracker.fetchAndParseAsJSON("fetchUrl", {}, "test"), async () => createResponse({ "x-fluid-epoch": "epoch1" }, {
|
|
269
|
+
error: {
|
|
270
|
+
"message": "locationMoved",
|
|
271
|
+
"@error.redirectLocation": newSiteUrl,
|
|
272
|
+
},
|
|
273
|
+
}, 404));
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
success = false;
|
|
277
|
+
assert.strictEqual(error.errorType, OdspErrorTypes.locationRedirection, "Error should be locationRedirection error");
|
|
278
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
|
|
279
|
+
const newResolvedUrl = error.redirectUrl;
|
|
280
|
+
assert.strictEqual(newResolvedUrl.siteUrl, newSiteUrl, "New site url should match");
|
|
281
|
+
assert.strictEqual(newResolvedUrl.driveId, driveId, "driveId should remain same");
|
|
282
|
+
}
|
|
283
|
+
assert.strictEqual(success, false, "Fetching should not succeed!!");
|
|
284
|
+
});
|
|
285
|
+
it("Checks throttling errors are non-retriable when disableRetriesOnStorageThrottlingError=true", async () => {
|
|
286
|
+
const retryAfterSeconds = 1;
|
|
287
|
+
let fetchStub;
|
|
288
|
+
const epochTrackerWithHostPolicy = new EpochTracker(localCache, {
|
|
289
|
+
docId: hashedDocumentId,
|
|
290
|
+
resolvedUrl,
|
|
291
|
+
}, createChildLogger(), undefined, { disableRetriesOnStorageThrottlingError: true } /* hostPolicy */);
|
|
292
|
+
try {
|
|
293
|
+
// fetchHelper is used by epochTracker's fetch method, which we stub here to emulate throttling error
|
|
294
|
+
fetchStub = stub(odspUtilsModule, "fetchHelper");
|
|
295
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
296
|
+
fetchStub.callsFake(async () => {
|
|
297
|
+
throw new ThrottlingError("Server is throttled", retryAfterSeconds, {
|
|
298
|
+
testProp: "testProp",
|
|
299
|
+
driverVersion: "1",
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
await epochTrackerWithHostPolicy.fetch("fetchUrl", {}, "test");
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
// retoring the fetchHelper function to avoid causing errors in other tests
|
|
306
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
307
|
+
fetchStub.restore();
|
|
308
|
+
assert(error.canRetry === false, "Error should be marked as non-retriable");
|
|
309
|
+
assert(
|
|
310
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
|
|
311
|
+
error.retryAfterSeconds === retryAfterSeconds, "retryAfterSeconds should exist");
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
it("Checks throttling errors retriable when disableRetriesOnStorageThrottlingError=false", async () => {
|
|
315
|
+
let fetchStub;
|
|
316
|
+
const epochTrackerWithHostPolicy = new EpochTracker(localCache, {
|
|
317
|
+
docId: hashedDocumentId,
|
|
318
|
+
resolvedUrl,
|
|
319
|
+
}, createChildLogger(), undefined, { disableRetriesOnStorageThrottlingError: false } /* hostPolicy */);
|
|
320
|
+
try {
|
|
321
|
+
// fetchHelper is used by epochTracker's fetch method, which we stub here to emulate throttling error
|
|
322
|
+
fetchStub = stub(odspUtilsModule, "fetchHelper");
|
|
323
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
324
|
+
fetchStub.callsFake(async () => {
|
|
325
|
+
throw new ThrottlingError("Server is throttled", 1000, {
|
|
326
|
+
testProp: "testProp",
|
|
327
|
+
driverVersion: "1",
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
await epochTrackerWithHostPolicy.fetch("fetchUrl", {}, "test");
|
|
331
|
+
}
|
|
332
|
+
catch (error) {
|
|
333
|
+
// retoring the fetchHelper function to avoid causing errors in other tests
|
|
334
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
335
|
+
fetchStub.restore();
|
|
336
|
+
assert(error.canRetry === true, "Error should be retriable");
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
//# sourceMappingURL=epochTests.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"epochTests.spec.js","sourceRoot":"","sources":["../../src/test/epochTests.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EACN,cAAc,EAId,sBAAsB,GACtB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,eAAe,EAA0B,MAAM,8BAA8B,CAAC;AACvF,OAAO,EAAE,iBAAiB,EAAwB,MAAM,iCAAiC,CAAC;AAC1F,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAC7B,OAAO,EAA4B,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AACvF,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,eAAe,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAE9E,MAAM,kBAAkB,GAAG,GAAyB,EAAE,CAAC,IAAI,oBAAoB,EAAE,CAAC;AAElF,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACxC,MAAM,OAAO,GAAG,6CAA6C,CAAC;IAC9D,MAAM,OAAO,GAAG,SAAS,CAAC;IAC1B,MAAM,MAAM,GAAG,QAAQ,CAAC;IACxB,IAAI,YAA0B,CAAC;IAC/B,IAAI,UAAgC,CAAC;IACrC,IAAI,gBAAwB,CAAC;IAC7B,MAAM,WAAW,GAAG;QACnB,OAAO;QACP,OAAO;QACP,MAAM;QACN,eAAe,EAAE,IAAI;KACU,CAAC;IAEjC,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,gBAAgB,GAAG,MAAM,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,GAAG,EAAE;QACf,UAAU,GAAG,kBAAkB,EAAE,CAAC;QAClC,2CAA2C;QAC3C,YAAY,GAAG,IAAI,YAAY,CAC9B,UAAU,EACV;YACC,KAAK,EAAE,gBAAgB;YACvB,WAAW;SACX,EACD,iBAAiB,EAAE,CACnB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,KAAK,IAAI,EAAE;QACpB,MAAM,YAAY,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACvE,4DAA4D;QAC5D,MAAM,QAAQ,GAGV,SAAS,CAAC;QAEd,MAAM,CAAC,sBAAsB,IAAI,QAAQ,EAAE,+CAA+C,CAAC,CAAC;IAC7F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE,KAAK,IAAI,EAAE;QACpC,MAAM,WAAW,GAAgB;YAChC,GAAG,EAAE,MAAM;YACX,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE;SAC9C,CAAC;QACF,MAAM,WAAW,GAAgB,EAAE,GAAG,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;QACjE,MAAM,WAAW,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QAChE,MAAM,WAAW,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QAChE,MAAM,MAAM,GAA6B;YACxC,KAAK,EAAE,WAAW;YAClB,UAAU,EAAE,QAAQ;YACpB,OAAO,EAAE,0BAA0B;SACnC,CAAC;QACF,MAAM,MAAM,GAAG;YACd,KAAK,EAAE,WAAW;YAClB,UAAU,EAAE,QAAQ;YACpB,OAAO,EAAE,sBAAsB;SAC/B,CAAC;QACF,MAAM,UAAU,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAC1C,MAAM,UAAU,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAC1C,0DAA0D;QAC1D,MAAM,CACL,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,KAAK,WAAW,EACrD,kCAAkC,CAClC,CAAC;QACF,6CAA6C;QAC7C,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACpC,uDAAuD;QACvD,MAAM,CACL,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,KAAK,WAAW,EACrD,kCAAkC,CAClC,CAAC;QACF,MAAM,CAAC,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,KAAK,SAAS,EAAE,0BAA0B,CAAC,CAAC;IACzF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kFAAkF,EAAE,KAAK,IAAI,EAAE;QACjG,MAAM,WAAW,GAAgB;YAChC,GAAG,EAAE,MAAM;YACX,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE;SAC9C,CAAC;QACF,MAAM,WAAW,GAAgB,EAAE,GAAG,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;QACjE,MAAM,WAAW,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QAChE,MAAM,WAAW,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QAChE,MAAM,MAAM,GAA6B;YACxC,KAAK,EAAE,WAAW;YAClB,UAAU,EAAE,QAAQ;YACpB,OAAO,EAAE,0BAA0B;SACnC,CAAC;QACF,MAAM,MAAM,GAA6B;YACxC,KAAK,EAAE,WAAW;YAClB,UAAU,EAAE,QAAQ;YACpB,OAAO,EAAE,0BAA0B;SACnC,CAAC;QACF,MAAM,UAAU,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAC1C,MAAM,UAAU,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAC1C,0DAA0D;QAC1D,MAAM,CACL,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,KAAK,WAAW,EACrD,kCAAkC,CAClC,CAAC;QACF,6CAA6C;QAC7C,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACpC,uDAAuD;QACvD,MAAM,CACL,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,KAAK,WAAW,EACrD,kCAAkC,CAClC,CAAC;QACF,MAAM,CAAC,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,KAAK,SAAS,EAAE,0BAA0B,CAAC,CAAC;IACzF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACvE,IAAI,OAAO,GAAY,IAAI,CAAC;QAC5B,MAAM,WAAW,GAAW;YAC3B,GAAG,EAAE,MAAM;YACX,IAAI,EAAE,UAAU;SAChB,CAAC;QACF,YAAY,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QACrD,0DAA0D;QAC1D,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACpC,IAAI;YACH,MAAM,WAAW,CAChB,KAAK,IAAI,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,UAAU,EAAE,EAAE,EAAE,MAAM,CAAC,EAC3D,EAAE,EACF,EAAE,eAAe,EAAE,QAAQ,EAAE,CAC7B,CAAC;SACF;QAAC,OAAO,KAAc,EAAE;YACxB,OAAO,GAAG,KAAK,CAAC;YAChB,MAAM,CAAC,WAAW,CAChB,KAAkC,CAAC,SAAS,EAC7C,cAAc,CAAC,wBAAwB,EACvC,6BAA6B,CAC7B,CAAC;SACF;QACD,MAAM,CACL,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,KAAK,SAAS,EACnD,kCAAkC,CAClC,CAAC;QACF,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,wBAAwB,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC/E,IAAI,OAAO,GAAY,IAAI,CAAC;QAC5B,MAAM,WAAW,GAAW;YAC3B,GAAG,EAAE,MAAM;YACX,IAAI,EAAE,UAAU;SAChB,CAAC;QACF,YAAY,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QACrD,0DAA0D;QAC1D,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACpC,IAAI;YACH,MAAM,WAAW,CAChB,KAAK,IAAI,EAAE,CAAC,YAAY,CAAC,mBAAmB,CAAC,UAAU,EAAE,EAAE,EAAE,MAAM,CAAC,EACpE,EAAE,EACF,EAAE,eAAe,EAAE,QAAQ,EAAE,CAC7B,CAAC;SACF;QAAC,OAAO,KAAc,EAAE;YACxB,OAAO,GAAG,KAAK,CAAC;YAChB,MAAM,CAAC,WAAW,CAChB,KAAkC,CAAC,SAAS,EAC7C,cAAc,CAAC,wBAAwB,EACvC,6BAA6B,CAC7B,CAAC;SACF;QACD,MAAM,CACL,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,KAAK,SAAS,EACnD,kCAAkC,CAClC,CAAC;QACF,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,wBAAwB,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC/E,IAAI,OAAO,GAAY,IAAI,CAAC;QAC5B,MAAM,WAAW,GAAW;YAC3B,GAAG,EAAE,MAAM;YACX,IAAI,EAAE,UAAU;SAChB,CAAC;QACF,YAAY,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QACrD,0DAA0D;QAC1D,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACpC,IAAI;YACH,MAAM,WAAW,CAChB,KAAK,IAAI,EAAE,CAAC,YAAY,CAAC,mBAAmB,CAAC,UAAU,EAAE,EAAE,EAAE,MAAM,CAAC,EACpE,EAAE,EACF,EAAE,eAAe,EAAE,QAAQ,EAAE,CAC7B,CAAC;YACF,8DAA8D;SAC9D;QAAC,OAAO,KAAU,EAAE;YACpB,OAAO,GAAG,KAAK,CAAC;YAChB,sEAAsE;YACtE,MAAM,CAAC,KAAK,CAAC,mBAAmB,KAAK,SAAS,EAAE,iCAAiC,CAAC,CAAC;SACnF;QACD,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,wBAAwB,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yEAAyE,EAAE,KAAK,IAAI,EAAE;QACxF,MAAM,WAAW,GAAW;YAC3B,GAAG,EAAE,MAAM;YACX,IAAI,EAAE,UAAU;SAChB,CAAC;QACF,YAAY,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QACrD,0DAA0D;QAC1D,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACpC,MAAM,QAAQ,GAAG,MAAM,WAAW,CACjC,KAAK,IAAI,EAAE,CAAC,YAAY,CAAC,mBAAmB,CAAC,UAAU,EAAE,EAAE,EAAE,MAAM,CAAC,EACpE,EAAE,EACF,EAAE,eAAe,EAAE,QAAQ,EAAE,CAC7B,CAAC;QACF,MAAM,CACL,QAAQ,CAAC,UAAU,CAAC,mBAAmB,KAAK,SAAS,EACrD,iCAAiC,CACjC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAChF,IAAI,OAAO,GAAY,IAAI,CAAC;QAC5B,MAAM,WAAW,GAAW;YAC3B,GAAG,EAAE,MAAM;YACX,IAAI,EAAE,UAAU;SAChB,CAAC;QACF,YAAY,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QACrD,0DAA0D;QAC1D,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACpC,IAAI;YACH,MAAM,WAAW,CAAC,KAAK,IAAI,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,UAAU,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;SAC/E;QAAC,MAAM;YACP,OAAO,GAAG,KAAK,CAAC;SAChB;QACD,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,EAAE,2BAA2B,CAAC,CAAC;QAC/D,MAAM,CAAC,WAAW;QACjB,0GAA0G;QAC1G,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,EACzC,MAAM,EACN,kCAAkC,CAClC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC7E,IAAI,OAAO,GAAY,IAAI,CAAC;QAC5B,MAAM,WAAW,GAAW;YAC3B,GAAG,EAAE,MAAM;YACX,IAAI,EAAE,UAAU;SAChB,CAAC;QACF,YAAY,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QACrD,0DAA0D;QAC1D,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACpC,IAAI;YACH,MAAM,WAAW,CAChB,KAAK,IAAI,EAAE,CAAC,YAAY,CAAC,mBAAmB,CAAC,UAAU,EAAE,EAAE,EAAE,MAAM,CAAC,EACpE,EAAE,EACF,EAAE,eAAe,EAAE,QAAQ,EAAE,CAC7B,CAAC;SACF;QAAC,MAAM;YACP,OAAO,GAAG,KAAK,CAAC;SAChB;QACD,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,EAAE,2BAA2B,CAAC,CAAC;QAC/D,MAAM,CAAC,WAAW;QACjB,0GAA0G;QAC1G,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,EACzC,MAAM,EACN,kCAAkC,CAClC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gFAAgF,EAAE,KAAK,IAAI,EAAE;QAC/F,IAAI,OAAO,GAAY,IAAI,CAAC;QAC5B,MAAM,WAAW,GAAW;YAC3B,GAAG,EAAE,MAAM;YACX,IAAI,EAAE,UAAU;SAChB,CAAC;QACF,YAAY,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QACrD,0DAA0D;QAC1D,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACpC,IAAI;YACH,MAAM,eAAe,CACpB,KAAK,IAAI,EAAE,CAAC,YAAY,CAAC,mBAAmB,CAAC,UAAU,EAAE,EAAE,EAAE,MAAM,CAAC,EACpE,KAAK,IAAI,EAAE,CAAC,cAAc,CAAC,EAAE,eAAe,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,GAAG,CAAC,CACzE,CAAC;SACF;QAAC,OAAO,KAAc,EAAE;YACxB,OAAO,GAAG,KAAK,CAAC;YAChB,MAAM,CAAC,WAAW,CAChB,KAAkC,CAAC,SAAS,EAC7C,cAAc,CAAC,eAAe,EAC9B,kCAAkC,CAClC,CAAC;SACF;QACD,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,+BAA+B,CAAC,CAAC;QACpE,MAAM,CAAC,WAAW;QACjB,0GAA0G;QAC1G,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,EACzC,MAAM,EACN,+DAA+D,CAC/D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,KAAK,IAAI,EAAE;QAC3F,IAAI,OAAO,GAAY,IAAI,CAAC;QAC5B,MAAM,WAAW,GAAW;YAC3B,GAAG,EAAE,MAAM;YACX,IAAI,EAAE,UAAU;SAChB,CAAC;QACF,YAAY,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QACrD,0DAA0D;QAC1D,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACpC,IAAI;YACH,MAAM,eAAe,CACpB,KAAK,IAAI,EAAE,CAAC,YAAY,CAAC,mBAAmB,CAAC,UAAU,EAAE,EAAE,EAAE,MAAM,CAAC,EACpE,KAAK,IAAI,EAAE,CAAC,cAAc,CAAC,EAAE,eAAe,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,GAAG,CAAC,CACzE,CAAC;SACF;QAAC,OAAO,KAAc,EAAE;YACxB,OAAO,GAAG,KAAK,CAAC;YAChB,MAAM,CAAC,WAAW,CAChB,KAAkC,CAAC,SAAS,EAC7C,cAAc,CAAC,wBAAwB,EACvC,6BAA6B,CAC7B,CAAC;SACF;QACD,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,+BAA+B,CAAC,CAAC;QACpE,MAAM,CACL,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,KAAK,SAAS,EACnD,0DAA0D,CAC1D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACpE,IAAI,OAAO,GAAY,IAAI,CAAC;QAC5B,MAAM,UAAU,GAAG,0CAA0C,CAAC;QAC9D,IAAI;YACH,MAAM,eAAe,CACpB,KAAK,IAAI,EAAE,CAAC,YAAY,CAAC,mBAAmB,CAAC,UAAU,EAAE,EAAE,EAAE,MAAM,CAAC,EACpE,KAAK,IAAI,EAAE,CACV,cAAc,CACb,EAAE,eAAe,EAAE,QAAQ,EAAE,EAC7B;gBACC,KAAK,EAAE;oBACN,SAAS,EAAE,eAAe;oBAC1B,yBAAyB,EAAE,UAAU;iBACrC;aACD,EACD,GAAG,CACH,CACF,CAAC;SACF;QAAC,OAAO,KAAc,EAAE;YACxB,OAAO,GAAG,KAAK,CAAC;YAChB,MAAM,CAAC,WAAW,CAChB,KAAkC,CAAC,SAAS,EAC7C,cAAc,CAAC,mBAAmB,EAClC,2CAA2C,CAC3C,CAAC;YACF,mJAAmJ;YACnJ,MAAM,cAAc,GAAsB,KAAa,CAAC,WAAW,CAAC;YACpE,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,2BAA2B,CAAC,CAAC;YACpF,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,4BAA4B,CAAC,CAAC;SAClF;QACD,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,+BAA+B,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6FAA6F,EAAE,KAAK,IAAI,EAAE;QAC5G,MAAM,iBAAiB,GAAG,CAAC,CAAC;QAC5B,IAAI,SAAS,CAAC;QACd,MAAM,0BAA0B,GAAG,IAAI,YAAY,CAClD,UAAU,EACV;YACC,KAAK,EAAE,gBAAgB;YACvB,WAAW;SACX,EACD,iBAAiB,EAAE,EACnB,SAAS,EACT,EAAE,sCAAsC,EAAE,IAAI,EAAE,CAAC,gBAAgB,CACjE,CAAC;QACF,IAAI;YACH,qGAAqG;YACrG,SAAS,GAAG,IAAI,CAAC,eAAe,EAAE,aAAa,CAAC,CAAC;YACjD,yGAAyG;YACzG,SAAS,CAAC,SAAS,CAAC,KAAK,IAAI,EAAE;gBAC9B,MAAM,IAAI,eAAe,CAAC,qBAAqB,EAAE,iBAAiB,EAAE;oBACnE,QAAQ,EAAE,UAAU;oBACpB,aAAa,EAAE,GAAG;iBAClB,CAAC,CAAC;YACJ,CAAC,CAAC,CAAC;YACH,MAAM,0BAA0B,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;SAC/D;QAAC,OAAO,KAAK,EAAE;YACf,2EAA2E;YAC3E,yGAAyG;YACzG,SAAS,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,CACJ,KAAmC,CAAC,QAAQ,KAAK,KAAK,EACvD,yCAAyC,CACzC,CAAC;YACF,MAAM;YACL,0GAA0G;YACzG,KAAa,CAAC,iBAAiB,KAAK,iBAAiB,EACtD,gCAAgC,CAChC,CAAC;SACF;IACF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sFAAsF,EAAE,KAAK,IAAI,EAAE;QACrG,IAAI,SAAS,CAAC;QACd,MAAM,0BAA0B,GAAG,IAAI,YAAY,CAClD,UAAU,EACV;YACC,KAAK,EAAE,gBAAgB;YACvB,WAAW;SACX,EACD,iBAAiB,EAAE,EACnB,SAAS,EACT,EAAE,sCAAsC,EAAE,KAAK,EAAE,CAAC,gBAAgB,CAClE,CAAC;QACF,IAAI;YACH,qGAAqG;YACrG,SAAS,GAAG,IAAI,CAAC,eAAe,EAAE,aAAa,CAAC,CAAC;YACjD,yGAAyG;YACzG,SAAS,CAAC,SAAS,CAAC,KAAK,IAAI,EAAE;gBAC9B,MAAM,IAAI,eAAe,CAAC,qBAAqB,EAAE,IAAI,EAAE;oBACtD,QAAQ,EAAE,UAAU;oBACpB,aAAa,EAAE,GAAG;iBAClB,CAAC,CAAC;YACJ,CAAC,CAAC,CAAC;YACH,MAAM,0BAA0B,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;SAC/D;QAAC,OAAO,KAAK,EAAE;YACf,2EAA2E;YAC3E,yGAAyG;YACzG,SAAS,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,CAAE,KAAyB,CAAC,QAAQ,KAAK,IAAI,EAAE,2BAA2B,CAAC,CAAC;SAClF;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 \"node:assert\";\nimport { IDocumentStorageServicePolicies } from \"@fluidframework/driver-definitions\";\nimport {\n\tOdspErrorTypes,\n\tIOdspResolvedUrl,\n\tICacheEntry,\n\tIEntry,\n\tmaximumCacheDurationMs,\n} from \"@fluidframework/odsp-driver-definitions\";\nimport { ThrottlingError, type NonRetryableError } from \"@fluidframework/driver-utils\";\nimport { createChildLogger, type IFluidErrorBase } from \"@fluidframework/telemetry-utils\";\nimport { stub } from \"sinon\";\nimport { IVersionedValueWithEpoch, persistedCacheValueVersion } from \"../contracts.js\";\nimport { EpochTracker } from \"../epochTracker.js\";\nimport { LocalPersistentCache } from \"../odspCache.js\";\nimport { getHashedDocumentId } from \"../odspPublicUtils.js\";\nimport * as odspUtilsModule from \"../odspUtils.js\";\nimport { mockFetchOk, mockFetchSingle, createResponse } from \"./mockFetch.js\";\n\nconst createUtLocalCache = (): LocalPersistentCache => new LocalPersistentCache();\n\ndescribe(\"Tests for Epoch Tracker\", () => {\n\tconst siteUrl = \"https://microsoft.sharepoint-df.com/siteUrl\";\n\tconst driveId = \"driveId\";\n\tconst itemId = \"itemId\";\n\tlet epochTracker: EpochTracker;\n\tlet localCache: LocalPersistentCache;\n\tlet hashedDocumentId: string;\n\tconst resolvedUrl = {\n\t\tsiteUrl,\n\t\tdriveId,\n\t\titemId,\n\t\todspResolvedUrl: true,\n\t} as unknown as IOdspResolvedUrl;\n\n\tbefore(async () => {\n\t\thashedDocumentId = await getHashedDocumentId(driveId, itemId);\n\t});\n\n\tbeforeEach(() => {\n\t\tlocalCache = createUtLocalCache();\n\t\t// use null logger here as we expect errors\n\t\tepochTracker = new EpochTracker(\n\t\t\tlocalCache,\n\t\t\t{\n\t\t\t\tdocId: hashedDocumentId,\n\t\t\t\tresolvedUrl,\n\t\t\t},\n\t\t\tcreateChildLogger(),\n\t\t);\n\t});\n\n\tafterEach(async () => {\n\t\tawait epochTracker.removeEntries().catch(() => {});\n\t});\n\n\tit(\"defaultCacheExpiryTimeoutMs <= maximumCacheDurationMs policy\", () => {\n\t\t// This is the maximum allowed value per the policy - 5 days\n\t\tconst expected: Exclude<\n\t\t\tIDocumentStorageServicePolicies[\"maximumCacheDurationMs\"],\n\t\t\tundefined\n\t\t> = 432000000;\n\n\t\tassert(maximumCacheDurationMs <= expected, \"Actual cache expiry used must meet the policy\");\n\t});\n\n\tit(\"Cache, old versions\", async () => {\n\t\tconst cacheEntry1: ICacheEntry = {\n\t\t\tkey: \"key1\",\n\t\t\ttype: \"snapshot\",\n\t\t\tfile: { docId: hashedDocumentId, resolvedUrl },\n\t\t};\n\t\tconst cacheEntry2: ICacheEntry = { ...cacheEntry1, key: \"key2\" };\n\t\tconst cacheValue1 = { val: \"val1\", cacheEntryTime: Date.now() };\n\t\tconst cacheValue2 = { val: \"val2\", cacheEntryTime: Date.now() };\n\t\tconst value1: IVersionedValueWithEpoch = {\n\t\t\tvalue: cacheValue1,\n\t\t\tfluidEpoch: \"epoch1\",\n\t\t\tversion: persistedCacheValueVersion,\n\t\t};\n\t\tconst value2 = {\n\t\t\tvalue: cacheValue2,\n\t\t\tfluidEpoch: \"epoch1\",\n\t\t\tversion: \"non-existing version\",\n\t\t};\n\t\tawait localCache.put(cacheEntry1, value1);\n\t\tawait localCache.put(cacheEntry2, value2);\n\t\t// This will set the initial epoch value in epoch tracker.\n\t\tassert(\n\t\t\t(await epochTracker.get(cacheEntry1)) === cacheValue1,\n\t\t\t\"Entry 1 should continue to exist\",\n\t\t);\n\t\t// This should not fail, just return nothing!\n\t\tawait epochTracker.get(cacheEntry2);\n\t\t// Make sure nothing changed as result of reading data.\n\t\tassert(\n\t\t\t(await epochTracker.get(cacheEntry1)) === cacheValue1,\n\t\t\t\"Entry 1 should continue to exist\",\n\t\t);\n\t\tassert((await epochTracker.get(cacheEntry2)) === undefined, \"Entry 2 should not exist\");\n\t});\n\n\tit(\"Epoch error when fetch error from cache should throw epoch error and clear cache\", async () => {\n\t\tconst cacheEntry1: ICacheEntry = {\n\t\t\tkey: \"key1\",\n\t\t\ttype: \"snapshot\",\n\t\t\tfile: { docId: hashedDocumentId, resolvedUrl },\n\t\t};\n\t\tconst cacheEntry2: ICacheEntry = { ...cacheEntry1, key: \"key2\" };\n\t\tconst cacheValue1 = { val: \"val1\", cacheEntryTime: Date.now() };\n\t\tconst cacheValue2 = { val: \"val2\", cacheEntryTime: Date.now() };\n\t\tconst value1: IVersionedValueWithEpoch = {\n\t\t\tvalue: cacheValue1,\n\t\t\tfluidEpoch: \"epoch1\",\n\t\t\tversion: persistedCacheValueVersion,\n\t\t};\n\t\tconst value2: IVersionedValueWithEpoch = {\n\t\t\tvalue: cacheValue2,\n\t\t\tfluidEpoch: \"epoch2\",\n\t\t\tversion: persistedCacheValueVersion,\n\t\t};\n\t\tawait localCache.put(cacheEntry1, value1);\n\t\tawait localCache.put(cacheEntry2, value2);\n\t\t// This will set the initial epoch value in epoch tracker.\n\t\tassert(\n\t\t\t(await epochTracker.get(cacheEntry1)) === cacheValue1,\n\t\t\t\"Entry 1 should continue to exist\",\n\t\t);\n\t\t// This should not fail, just return nothing!\n\t\tawait epochTracker.get(cacheEntry2);\n\t\t// Make sure nothing changed as result of reading data.\n\t\tassert(\n\t\t\t(await epochTracker.get(cacheEntry1)) === cacheValue1,\n\t\t\t\"Entry 1 should continue to exist\",\n\t\t);\n\t\tassert((await epochTracker.get(cacheEntry2)) === undefined, \"Entry 2 should not exist\");\n\t});\n\n\tit(\"Epoch error when fetch response and should clear cache\", async () => {\n\t\tlet success: boolean = true;\n\t\tconst cacheEntry1: IEntry = {\n\t\t\tkey: \"key1\",\n\t\t\ttype: \"snapshot\",\n\t\t};\n\t\tepochTracker.setEpoch(\"epoch1\", true, \"test\");\n\t\tawait epochTracker.put(cacheEntry1, { val: \"val1\" });\n\t\t// This will set the initial epoch value in epoch tracker.\n\t\tawait epochTracker.get(cacheEntry1);\n\t\ttry {\n\t\t\tawait mockFetchOk(\n\t\t\t\tasync () => epochTracker.fetchArray(\"fetchUrl\", {}, \"test\"),\n\t\t\t\t{},\n\t\t\t\t{ \"x-fluid-epoch\": \"epoch2\" },\n\t\t\t);\n\t\t} catch (error: unknown) {\n\t\t\tsuccess = false;\n\t\t\tassert.strictEqual(\n\t\t\t\t(error as Partial<IFluidErrorBase>).errorType,\n\t\t\t\tOdspErrorTypes.fileOverwrittenInStorage,\n\t\t\t\t\"Error should be epoch error\",\n\t\t\t);\n\t\t}\n\t\tassert(\n\t\t\t(await epochTracker.get(cacheEntry1)) === undefined,\n\t\t\t\"Entry in cache should be cleared\",\n\t\t);\n\t\tassert.strictEqual(success, false, \"Fetching should fail!!\");\n\t});\n\n\tit(\"Epoch error when fetch response as json and should clear cache\", async () => {\n\t\tlet success: boolean = true;\n\t\tconst cacheEntry1: IEntry = {\n\t\t\tkey: \"key1\",\n\t\t\ttype: \"snapshot\",\n\t\t};\n\t\tepochTracker.setEpoch(\"epoch1\", true, \"test\");\n\t\tawait epochTracker.put(cacheEntry1, { val: \"val1\" });\n\t\t// This will set the initial epoch value in epoch tracker.\n\t\tawait epochTracker.get(cacheEntry1);\n\t\ttry {\n\t\t\tawait mockFetchOk(\n\t\t\t\tasync () => epochTracker.fetchAndParseAsJSON(\"fetchUrl\", {}, \"test\"),\n\t\t\t\t{},\n\t\t\t\t{ \"x-fluid-epoch\": \"epoch2\" },\n\t\t\t);\n\t\t} catch (error: unknown) {\n\t\t\tsuccess = false;\n\t\t\tassert.strictEqual(\n\t\t\t\t(error as Partial<IFluidErrorBase>).errorType,\n\t\t\t\tOdspErrorTypes.fileOverwrittenInStorage,\n\t\t\t\t\"Error should be epoch error\",\n\t\t\t);\n\t\t}\n\t\tassert(\n\t\t\t(await epochTracker.get(cacheEntry1)) === undefined,\n\t\t\t\"Entry in cache should be cleared\",\n\t\t);\n\t\tassert.strictEqual(success, false, \"Fetching should fail!!\");\n\t});\n\n\tit(\"Check client correlationID on error in unsuccessful fetch case\", async () => {\n\t\tlet success: boolean = true;\n\t\tconst cacheEntry1: IEntry = {\n\t\t\tkey: \"key1\",\n\t\t\ttype: \"snapshot\",\n\t\t};\n\t\tepochTracker.setEpoch(\"epoch1\", true, \"test\");\n\t\tawait epochTracker.put(cacheEntry1, { val: \"val1\" });\n\t\t// This will set the initial epoch value in epoch tracker.\n\t\tawait epochTracker.get(cacheEntry1);\n\t\ttry {\n\t\t\tawait mockFetchOk(\n\t\t\t\tasync () => epochTracker.fetchAndParseAsJSON(\"fetchUrl\", {}, \"test\"),\n\t\t\t\t{},\n\t\t\t\t{ \"x-fluid-epoch\": \"epoch2\" },\n\t\t\t);\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t} catch (error: any) {\n\t\t\tsuccess = false;\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n\t\t\tassert(error.XRequestStatsHeader !== undefined, \"CorrelationId should be present\");\n\t\t}\n\t\tassert.strictEqual(success, false, \"Fetching should fail!!\");\n\t});\n\n\tit(\"Check client correlationID on spoCommonHeaders in successful fetch case\", async () => {\n\t\tconst cacheEntry1: IEntry = {\n\t\t\tkey: \"key1\",\n\t\t\ttype: \"snapshot\",\n\t\t};\n\t\tepochTracker.setEpoch(\"epoch1\", true, \"test\");\n\t\tawait epochTracker.put(cacheEntry1, { val: \"val1\" });\n\t\t// This will set the initial epoch value in epoch tracker.\n\t\tawait epochTracker.get(cacheEntry1);\n\t\tconst response = await mockFetchOk(\n\t\t\tasync () => epochTracker.fetchAndParseAsJSON(\"fetchUrl\", {}, \"test\"),\n\t\t\t{},\n\t\t\t{ \"x-fluid-epoch\": \"epoch1\" },\n\t\t);\n\t\tassert(\n\t\t\tresponse.propsToLog.XRequestStatsHeader !== undefined,\n\t\t\t\"CorrelationId should be present\",\n\t\t);\n\t});\n\n\tit(\"Epoch error should not occur if response does not contain epoch\", async () => {\n\t\tlet success: boolean = true;\n\t\tconst cacheEntry1: IEntry = {\n\t\t\tkey: \"key1\",\n\t\t\ttype: \"snapshot\",\n\t\t};\n\t\tepochTracker.setEpoch(\"epoch1\", true, \"test\");\n\t\tawait epochTracker.put(cacheEntry1, { val: \"val1\" });\n\t\t// This will set the initial epoch value in epoch tracker.\n\t\tawait epochTracker.get(cacheEntry1);\n\t\ttry {\n\t\t\tawait mockFetchOk(async () => epochTracker.fetchArray(\"fetchUrl\", {}, \"test\"));\n\t\t} catch {\n\t\t\tsuccess = false;\n\t\t}\n\t\tassert.strictEqual(success, true, \"Fetching should succeed!!\");\n\t\tassert.strictEqual(\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, unicorn/no-await-expression-member\n\t\t\t(await epochTracker.get(cacheEntry1)).val,\n\t\t\t\"val1\",\n\t\t\t\"Entry in cache should be present\",\n\t\t);\n\t});\n\n\tit(\"Epoch error should not occur if response contains same epoch\", async () => {\n\t\tlet success: boolean = true;\n\t\tconst cacheEntry1: IEntry = {\n\t\t\tkey: \"key1\",\n\t\t\ttype: \"snapshot\",\n\t\t};\n\t\tepochTracker.setEpoch(\"epoch1\", true, \"test\");\n\t\tawait epochTracker.put(cacheEntry1, { val: \"val1\" });\n\t\t// This will set the initial epoch value in epoch tracker.\n\t\tawait epochTracker.get(cacheEntry1);\n\t\ttry {\n\t\t\tawait mockFetchOk(\n\t\t\t\tasync () => epochTracker.fetchAndParseAsJSON(\"fetchUrl\", {}, \"test\"),\n\t\t\t\t{},\n\t\t\t\t{ \"x-fluid-epoch\": \"epoch1\" },\n\t\t\t);\n\t\t} catch {\n\t\t\tsuccess = false;\n\t\t}\n\t\tassert.strictEqual(success, true, \"Fetching should succeed!!\");\n\t\tassert.strictEqual(\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, unicorn/no-await-expression-member\n\t\t\t(await epochTracker.get(cacheEntry1)).val,\n\t\t\t\"val1\",\n\t\t\t\"Entry in cache should be present\",\n\t\t);\n\t});\n\n\tit(\"Should differentiate between epoch and coherency 409 errors when coherency 409\", async () => {\n\t\tlet success: boolean = true;\n\t\tconst cacheEntry1: IEntry = {\n\t\t\tkey: \"key1\",\n\t\t\ttype: \"snapshot\",\n\t\t};\n\t\tepochTracker.setEpoch(\"epoch1\", true, \"test\");\n\t\tawait epochTracker.put(cacheEntry1, { val: \"val1\" });\n\t\t// This will set the initial epoch value in epoch tracker.\n\t\tawait epochTracker.get(cacheEntry1);\n\t\ttry {\n\t\t\tawait mockFetchSingle(\n\t\t\t\tasync () => epochTracker.fetchAndParseAsJSON(\"fetchUrl\", {}, \"test\"),\n\t\t\t\tasync () => createResponse({ \"x-fluid-epoch\": \"epoch1\" }, undefined, 409),\n\t\t\t);\n\t\t} catch (error: unknown) {\n\t\t\tsuccess = false;\n\t\t\tassert.strictEqual(\n\t\t\t\t(error as Partial<IFluidErrorBase>).errorType,\n\t\t\t\tOdspErrorTypes.throttlingError,\n\t\t\t\t\"Error should be throttling error\",\n\t\t\t);\n\t\t}\n\t\tassert.strictEqual(success, false, \"Fetching should not succeed!!\");\n\t\tassert.strictEqual(\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, unicorn/no-await-expression-member\n\t\t\t(await epochTracker.get(cacheEntry1)).val,\n\t\t\t\"val1\",\n\t\t\t\"Entry in cache should be present because it was not epoch 409\",\n\t\t);\n\t});\n\n\tit(\"Should differentiate between epoch and coherency 409 errors when epoch 409\", async () => {\n\t\tlet success: boolean = true;\n\t\tconst cacheEntry1: IEntry = {\n\t\t\tkey: \"key1\",\n\t\t\ttype: \"snapshot\",\n\t\t};\n\t\tepochTracker.setEpoch(\"epoch1\", true, \"test\");\n\t\tawait epochTracker.put(cacheEntry1, { val: \"val1\" });\n\t\t// This will set the initial epoch value in epoch tracker.\n\t\tawait epochTracker.get(cacheEntry1);\n\t\ttry {\n\t\t\tawait mockFetchSingle(\n\t\t\t\tasync () => epochTracker.fetchAndParseAsJSON(\"fetchUrl\", {}, \"test\"),\n\t\t\t\tasync () => createResponse({ \"x-fluid-epoch\": \"epoch2\" }, undefined, 409),\n\t\t\t);\n\t\t} catch (error: unknown) {\n\t\t\tsuccess = false;\n\t\t\tassert.strictEqual(\n\t\t\t\t(error as Partial<IFluidErrorBase>).errorType,\n\t\t\t\tOdspErrorTypes.fileOverwrittenInStorage,\n\t\t\t\t\"Error should be epoch error\",\n\t\t\t);\n\t\t}\n\t\tassert.strictEqual(success, false, \"Fetching should not succeed!!\");\n\t\tassert(\n\t\t\t(await epochTracker.get(cacheEntry1)) === undefined,\n\t\t\t\"Entry in cache should be absent because it was epoch 409\",\n\t\t);\n\t});\n\n\tit(\"Check for resolved url on LocationRedirection error\", async () => {\n\t\tlet success: boolean = true;\n\t\tconst newSiteUrl = \"https://microsoft.sharepoint.com/siteUrl\";\n\t\ttry {\n\t\t\tawait mockFetchSingle(\n\t\t\t\tasync () => epochTracker.fetchAndParseAsJSON(\"fetchUrl\", {}, \"test\"),\n\t\t\t\tasync () =>\n\t\t\t\t\tcreateResponse(\n\t\t\t\t\t\t{ \"x-fluid-epoch\": \"epoch1\" },\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\t\t\"message\": \"locationMoved\",\n\t\t\t\t\t\t\t\t\"@error.redirectLocation\": newSiteUrl,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t404,\n\t\t\t\t\t),\n\t\t\t);\n\t\t} catch (error: unknown) {\n\t\t\tsuccess = false;\n\t\t\tassert.strictEqual(\n\t\t\t\t(error as Partial<IFluidErrorBase>).errorType,\n\t\t\t\tOdspErrorTypes.locationRedirection,\n\t\t\t\t\"Error should be locationRedirection error\",\n\t\t\t);\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\t\tconst newResolvedUrl: IOdspResolvedUrl = (error as any).redirectUrl;\n\t\t\tassert.strictEqual(newResolvedUrl.siteUrl, newSiteUrl, \"New site url should match\");\n\t\t\tassert.strictEqual(newResolvedUrl.driveId, driveId, \"driveId should remain same\");\n\t\t}\n\t\tassert.strictEqual(success, false, \"Fetching should not succeed!!\");\n\t});\n\n\tit(\"Checks throttling errors are non-retriable when disableRetriesOnStorageThrottlingError=true\", async () => {\n\t\tconst retryAfterSeconds = 1;\n\t\tlet fetchStub;\n\t\tconst epochTrackerWithHostPolicy = new EpochTracker(\n\t\t\tlocalCache,\n\t\t\t{\n\t\t\t\tdocId: hashedDocumentId,\n\t\t\t\tresolvedUrl,\n\t\t\t},\n\t\t\tcreateChildLogger(),\n\t\t\tundefined,\n\t\t\t{ disableRetriesOnStorageThrottlingError: true } /* hostPolicy */,\n\t\t);\n\t\ttry {\n\t\t\t// fetchHelper is used by epochTracker's fetch method, which we stub here to emulate throttling error\n\t\t\tfetchStub = stub(odspUtilsModule, \"fetchHelper\");\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n\t\t\tfetchStub.callsFake(async () => {\n\t\t\t\tthrow new ThrottlingError(\"Server is throttled\", retryAfterSeconds, {\n\t\t\t\t\ttestProp: \"testProp\",\n\t\t\t\t\tdriverVersion: \"1\",\n\t\t\t\t});\n\t\t\t});\n\t\t\tawait epochTrackerWithHostPolicy.fetch(\"fetchUrl\", {}, \"test\");\n\t\t} catch (error) {\n\t\t\t// retoring the fetchHelper function to avoid causing errors in other tests\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n\t\t\tfetchStub.restore();\n\t\t\tassert(\n\t\t\t\t(error as NonRetryableError<string>).canRetry === false,\n\t\t\t\t\"Error should be marked as non-retriable\",\n\t\t\t);\n\t\t\tassert(\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access\n\t\t\t\t(error as any).retryAfterSeconds === retryAfterSeconds,\n\t\t\t\t\"retryAfterSeconds should exist\",\n\t\t\t);\n\t\t}\n\t});\n\n\tit(\"Checks throttling errors retriable when disableRetriesOnStorageThrottlingError=false\", async () => {\n\t\tlet fetchStub;\n\t\tconst epochTrackerWithHostPolicy = new EpochTracker(\n\t\t\tlocalCache,\n\t\t\t{\n\t\t\t\tdocId: hashedDocumentId,\n\t\t\t\tresolvedUrl,\n\t\t\t},\n\t\t\tcreateChildLogger(),\n\t\t\tundefined,\n\t\t\t{ disableRetriesOnStorageThrottlingError: false } /* hostPolicy */,\n\t\t);\n\t\ttry {\n\t\t\t// fetchHelper is used by epochTracker's fetch method, which we stub here to emulate throttling error\n\t\t\tfetchStub = stub(odspUtilsModule, \"fetchHelper\");\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n\t\t\tfetchStub.callsFake(async () => {\n\t\t\t\tthrow new ThrottlingError(\"Server is throttled\", 1000, {\n\t\t\t\t\ttestProp: \"testProp\",\n\t\t\t\t\tdriverVersion: \"1\",\n\t\t\t\t});\n\t\t\t});\n\t\t\tawait epochTrackerWithHostPolicy.fetch(\"fetchUrl\", {}, \"test\");\n\t\t} catch (error) {\n\t\t\t// retoring the fetchHelper function to avoid causing errors in other tests\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access\n\t\t\tfetchStub.restore();\n\t\t\tassert((error as ThrottlingError).canRetry === true, \"Error should be retriable\");\n\t\t}\n\t});\n});\n"]}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { strict as assert } from "node:assert";
|
|
6
|
+
import { Deferred } from "@fluidframework/core-utils";
|
|
7
|
+
import { MockLogger } from "@fluidframework/telemetry-utils";
|
|
8
|
+
import { OdspErrorTypes, snapshotKey, } from "@fluidframework/odsp-driver-definitions";
|
|
9
|
+
import { EpochTrackerWithRedemption } from "../epochTracker.js";
|
|
10
|
+
import { LocalPersistentCache } from "../odspCache.js";
|
|
11
|
+
import { getHashedDocumentId } from "../odspPublicUtils.js";
|
|
12
|
+
import { mockFetchSingle, mockFetchMultiple, okResponse, notFound, } from "./mockFetch.js";
|
|
13
|
+
class DeferralWithCallback extends Deferred {
|
|
14
|
+
constructor() {
|
|
15
|
+
super();
|
|
16
|
+
this.epochCallback = async () => { };
|
|
17
|
+
}
|
|
18
|
+
setCallback(epochCallback) {
|
|
19
|
+
this.epochCallback = epochCallback;
|
|
20
|
+
}
|
|
21
|
+
get promise() {
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
23
|
+
return this.epochCallback().then(() => super.promise);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
describe("Tests for Epoch Tracker With Redemption", () => {
|
|
27
|
+
const siteUrl = "https://microsoft.sharepoint-df.com/siteUrl";
|
|
28
|
+
const driveId = "driveId";
|
|
29
|
+
const itemId = "itemId";
|
|
30
|
+
const logger = new MockLogger();
|
|
31
|
+
let epochTracker;
|
|
32
|
+
let hashedDocumentId;
|
|
33
|
+
let epochCallback;
|
|
34
|
+
before(async () => {
|
|
35
|
+
hashedDocumentId = await getHashedDocumentId(driveId, itemId);
|
|
36
|
+
});
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
const resolvedUrl = {
|
|
39
|
+
siteUrl,
|
|
40
|
+
driveId,
|
|
41
|
+
itemId,
|
|
42
|
+
odspResolvedUrl: true,
|
|
43
|
+
};
|
|
44
|
+
epochTracker = new EpochTrackerWithRedemption(new LocalPersistentCache(), {
|
|
45
|
+
docId: hashedDocumentId,
|
|
46
|
+
resolvedUrl,
|
|
47
|
+
}, logger.toTelemetryLogger());
|
|
48
|
+
});
|
|
49
|
+
afterEach(async () => {
|
|
50
|
+
await epochTracker.removeEntries().catch(() => { });
|
|
51
|
+
logger.assertMatchNone([{ category: "error" }]);
|
|
52
|
+
});
|
|
53
|
+
describe("Test Suite 1", () => {
|
|
54
|
+
beforeEach(() => {
|
|
55
|
+
epochCallback = new DeferralWithCallback();
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
|
|
57
|
+
epochTracker.treesLatestDeferral = epochCallback;
|
|
58
|
+
});
|
|
59
|
+
it("joinSession call should succeed on retrying after snapshot cached read succeeds", async () => {
|
|
60
|
+
epochTracker.setEpoch("epoch1", true, "test");
|
|
61
|
+
const cacheEntry1 = {
|
|
62
|
+
type: snapshotKey,
|
|
63
|
+
key: "key1",
|
|
64
|
+
};
|
|
65
|
+
await epochTracker.put(cacheEntry1, { val: "val1" });
|
|
66
|
+
// We will trigger a successful call to return the value set in the cache after the failed joinSession call
|
|
67
|
+
epochCallback.setCallback(async () => epochTracker.get(cacheEntry1));
|
|
68
|
+
// Initial joinSession call will return 404 but after the timeout, the call will be retried and succeed
|
|
69
|
+
await mockFetchMultiple(async () => epochTracker.fetchAndParseAsJSON("fetchUrl", {}, "joinSession"), [
|
|
70
|
+
notFound,
|
|
71
|
+
async () => okResponse({ "x-fluid-epoch": "epoch1" }, {}),
|
|
72
|
+
]);
|
|
73
|
+
});
|
|
74
|
+
it("joinSession call should succeed on retrying after any network call to the file succeeds", async () => {
|
|
75
|
+
epochTracker.setEpoch("epoch1", true, "test");
|
|
76
|
+
const cacheEntry1 = {
|
|
77
|
+
type: snapshotKey,
|
|
78
|
+
key: "key1",
|
|
79
|
+
};
|
|
80
|
+
await epochTracker.put(cacheEntry1, { val: "val1" });
|
|
81
|
+
// We will trigger a successful call to return the value set in the cache after the failed joinSession call
|
|
82
|
+
epochCallback.setCallback(async () => {
|
|
83
|
+
return epochTracker.fetchAndParseAsJSON("fetchUrl", {}, "treesLatest");
|
|
84
|
+
});
|
|
85
|
+
// Initial joinSession call will return 404 but after the timeout, the call will be retried and succeed
|
|
86
|
+
await mockFetchMultiple(async () => epochTracker.fetchAndParseAsJSON("fetchUrl", {}, "joinSession"), [
|
|
87
|
+
notFound,
|
|
88
|
+
async () => okResponse({ "x-fluid-epoch": "epoch1" }, {}),
|
|
89
|
+
async () => okResponse({ "x-fluid-epoch": "epoch1" }, {}), // "joinSession"
|
|
90
|
+
]);
|
|
91
|
+
});
|
|
92
|
+
it("Requests should fail if joinSession call fails and the getLatest call also fails", async () => {
|
|
93
|
+
let success = true;
|
|
94
|
+
try {
|
|
95
|
+
epochCallback.setCallback(async () => {
|
|
96
|
+
try {
|
|
97
|
+
await mockFetchSingle(async () => epochTracker.fetchAndParseAsJSON("fetchUrl", {}, "treesLatest"), notFound, "internal");
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
assert.strictEqual(error.errorType, OdspErrorTypes.fileNotFoundOrAccessDeniedError, "Error should be file not found or access denied error");
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
await mockFetchSingle(async () => epochTracker.fetchAndParseAsJSON("fetchUrl", {}, "joinSession"), async () => notFound({ "x-fluid-epoch": "epoch1" }), "external");
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
success = false;
|
|
107
|
+
assert.strictEqual(error.errorType, OdspErrorTypes.fileNotFoundOrAccessDeniedError, "Error should be file not found or access denied error");
|
|
108
|
+
}
|
|
109
|
+
assert.strictEqual(success, false, "Join session should fail if treesLatest call has failed");
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
describe("Tests Suite 2", () => {
|
|
113
|
+
it("Failed treesLatest call should not trigger unhandled rejection event", async () => {
|
|
114
|
+
const treesLatestP = mockFetchSingle(async () => epochTracker.fetchAndParseAsJSON("fetchUrl", {}, "treesLatest"), notFound);
|
|
115
|
+
await assert.rejects(treesLatestP, "should fail without causing an unhandledRejection event.");
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
//# sourceMappingURL=epochTestsWithRedemption.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"epochTestsWithRedemption.spec.js","sourceRoot":"","sources":["../../src/test/epochTestsWithRedemption.spec.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { strict as assert } from \"node:assert\";\nimport { Deferred } from \"@fluidframework/core-utils\";\nimport { MockLogger, type IFluidErrorBase } from \"@fluidframework/telemetry-utils\";\nimport {\n\tOdspErrorTypes,\n\tIOdspResolvedUrl,\n\tIEntry,\n\tsnapshotKey,\n} from \"@fluidframework/odsp-driver-definitions\";\nimport { EpochTrackerWithRedemption } from \"../epochTracker.js\";\nimport { LocalPersistentCache } from \"../odspCache.js\";\nimport { getHashedDocumentId } from \"../odspPublicUtils.js\";\nimport {\n\tmockFetchSingle,\n\tmockFetchMultiple,\n\tokResponse,\n\tnotFound,\n\tMockResponse,\n} from \"./mockFetch.js\";\n\nclass DeferralWithCallback extends Deferred<void> {\n\tprivate epochCallback: () => Promise<unknown> = async () => {};\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\tpublic setCallback(epochCallback: () => Promise<unknown>): void {\n\t\tthis.epochCallback = epochCallback;\n\t}\n\n\tpublic get promise(): Promise<void> {\n\t\t// eslint-disable-next-line @typescript-eslint/promise-function-async\n\t\treturn this.epochCallback().then(() => super.promise);\n\t}\n}\n\ndescribe(\"Tests for Epoch Tracker With Redemption\", () => {\n\tconst siteUrl = \"https://microsoft.sharepoint-df.com/siteUrl\";\n\tconst driveId = \"driveId\";\n\tconst itemId = \"itemId\";\n\tconst logger = new MockLogger();\n\tlet epochTracker: EpochTrackerWithRedemption;\n\tlet hashedDocumentId: string;\n\tlet epochCallback: DeferralWithCallback;\n\n\tbefore(async () => {\n\t\thashedDocumentId = await getHashedDocumentId(driveId, itemId);\n\t});\n\n\tbeforeEach(() => {\n\t\tconst resolvedUrl = {\n\t\t\tsiteUrl,\n\t\t\tdriveId,\n\t\t\titemId,\n\t\t\todspResolvedUrl: true,\n\t\t} as unknown as IOdspResolvedUrl;\n\t\tepochTracker = new EpochTrackerWithRedemption(\n\t\t\tnew LocalPersistentCache(),\n\t\t\t{\n\t\t\t\tdocId: hashedDocumentId,\n\t\t\t\tresolvedUrl,\n\t\t\t},\n\t\t\tlogger.toTelemetryLogger(),\n\t\t);\n\t});\n\n\tafterEach(async () => {\n\t\tawait epochTracker.removeEntries().catch(() => {});\n\t\tlogger.assertMatchNone([{ category: \"error\" }]);\n\t});\n\n\tdescribe(\"Test Suite 1\", () => {\n\t\tbeforeEach(() => {\n\t\t\tepochCallback = new DeferralWithCallback();\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\t\t(epochTracker as any).treesLatestDeferral = epochCallback;\n\t\t});\n\t\tit(\"joinSession call should succeed on retrying after snapshot cached read succeeds\", async () => {\n\t\t\tepochTracker.setEpoch(\"epoch1\", true, \"test\");\n\t\t\tconst cacheEntry1: IEntry = {\n\t\t\t\ttype: snapshotKey,\n\t\t\t\tkey: \"key1\",\n\t\t\t};\n\t\t\tawait epochTracker.put(cacheEntry1, { val: \"val1\" });\n\n\t\t\t// We will trigger a successful call to return the value set in the cache after the failed joinSession call\n\t\t\tepochCallback.setCallback(async () => epochTracker.get(cacheEntry1));\n\n\t\t\t// Initial joinSession call will return 404 but after the timeout, the call will be retried and succeed\n\t\t\tawait mockFetchMultiple(\n\t\t\t\tasync () => epochTracker.fetchAndParseAsJSON(\"fetchUrl\", {}, \"joinSession\"),\n\t\t\t\t[\n\t\t\t\t\tnotFound,\n\t\t\t\t\tasync (): Promise<MockResponse> =>\n\t\t\t\t\t\tokResponse({ \"x-fluid-epoch\": \"epoch1\" }, {}),\n\t\t\t\t],\n\t\t\t);\n\t\t});\n\n\t\tit(\"joinSession call should succeed on retrying after any network call to the file succeeds\", async () => {\n\t\t\tepochTracker.setEpoch(\"epoch1\", true, \"test\");\n\t\t\tconst cacheEntry1: IEntry = {\n\t\t\t\ttype: snapshotKey,\n\t\t\t\tkey: \"key1\",\n\t\t\t};\n\t\t\tawait epochTracker.put(cacheEntry1, { val: \"val1\" });\n\n\t\t\t// We will trigger a successful call to return the value set in the cache after the failed joinSession call\n\t\t\tepochCallback.setCallback(async () => {\n\t\t\t\treturn epochTracker.fetchAndParseAsJSON(\"fetchUrl\", {}, \"treesLatest\");\n\t\t\t});\n\n\t\t\t// Initial joinSession call will return 404 but after the timeout, the call will be retried and succeed\n\t\t\tawait mockFetchMultiple(\n\t\t\t\tasync () => epochTracker.fetchAndParseAsJSON(\"fetchUrl\", {}, \"joinSession\"),\n\t\t\t\t[\n\t\t\t\t\tnotFound, // joinSession\n\t\t\t\t\tasync (): Promise<MockResponse> =>\n\t\t\t\t\t\tokResponse({ \"x-fluid-epoch\": \"epoch1\" }, {}), // \"treesLatest\"\n\t\t\t\t\tasync (): Promise<MockResponse> =>\n\t\t\t\t\t\tokResponse({ \"x-fluid-epoch\": \"epoch1\" }, {}), // \"joinSession\"\n\t\t\t\t],\n\t\t\t);\n\t\t});\n\n\t\tit(\"Requests should fail if joinSession call fails and the getLatest call also fails\", async () => {\n\t\t\tlet success: boolean = true;\n\n\t\t\ttry {\n\t\t\t\tepochCallback.setCallback(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait mockFetchSingle(\n\t\t\t\t\t\t\tasync () =>\n\t\t\t\t\t\t\t\tepochTracker.fetchAndParseAsJSON(\"fetchUrl\", {}, \"treesLatest\"),\n\t\t\t\t\t\t\tnotFound,\n\t\t\t\t\t\t\t\"internal\",\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\t(error as Partial<IFluidErrorBase>).errorType,\n\t\t\t\t\t\t\tOdspErrorTypes.fileNotFoundOrAccessDeniedError,\n\t\t\t\t\t\t\t\"Error should be file not found or access denied error\",\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tawait mockFetchSingle(\n\t\t\t\t\tasync () => epochTracker.fetchAndParseAsJSON(\"fetchUrl\", {}, \"joinSession\"),\n\t\t\t\t\tasync () => notFound({ \"x-fluid-epoch\": \"epoch1\" }),\n\t\t\t\t\t\"external\",\n\t\t\t\t);\n\t\t\t} catch (error: unknown) {\n\t\t\t\tsuccess = false;\n\t\t\t\tassert.strictEqual(\n\t\t\t\t\t(error as Partial<IFluidErrorBase>).errorType,\n\t\t\t\t\tOdspErrorTypes.fileNotFoundOrAccessDeniedError,\n\t\t\t\t\t\"Error should be file not found or access denied error\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tassert.strictEqual(\n\t\t\t\tsuccess,\n\t\t\t\tfalse,\n\t\t\t\t\"Join session should fail if treesLatest call has failed\",\n\t\t\t);\n\t\t});\n\t});\n\n\tdescribe(\"Tests Suite 2\", () => {\n\t\tit(\"Failed treesLatest call should not trigger unhandled rejection event\", async () => {\n\t\t\tconst treesLatestP = mockFetchSingle(\n\t\t\t\tasync () => epochTracker.fetchAndParseAsJSON(\"fetchUrl\", {}, \"treesLatest\"),\n\t\t\t\tnotFound,\n\t\t\t);\n\t\t\tawait assert.rejects(\n\t\t\t\ttreesLatestP,\n\t\t\t\t\"should fail without causing an unhandledRejection event.\",\n\t\t\t);\n\t\t});\n\t});\n});\n"]}
|