import { DataObject } from "@fluidframework/aqueduct" ; import { assert , TelemetryNullLogger } from "@fluidframework/common-utils" ; import { IRuntimeFactory , LoaderHeader } from "@fluidframework/container-definitions" ; import { ContainerRuntime , gcBlobPrefix , gcTreeKey , ISummaryNackMessage , SummaryCollection , neverCancelledSummaryToken , } from "@fluidframework/container-runtime" ; import { IFluidDataStoreRuntime } from "@fluidframework/datastore-definitions" ; import { DriverHeader } from "@fluidframework/driver-definitions" ; import { concatGarbageCollectionStates } from "@fluidframework/garbage-collector" ; import { requestFluidObject } from "@fluidframework/runtime-utils" ; import { ITestObjectProvider } from "@fluidframework/test-utils" ; import { ITelemetryLogger } from "@fluidframework/common-definitions" ; import { ISummaryTree , SummaryType } from "@fluidframework/protocol-definitions" ; import { IGarbageCollectionState } from "@fluidframework/runtime-definitions" ; export class TestDataObject extends DataObject { public get _root ( ) { return this . root ; } public get dataStoreRuntime ( ) : IFluidDataStoreRuntime { return this . runtime ; } public get containerRuntime ( ) : ContainerRuntime { return this . context . containerRuntime as ContainerRuntime ; } } /**
  * Loads a summarizer client with the given version (if any) and returns its container runtime and summary collection.
  */ export async function loadSummarizer ( provider , runtimeFactory , sequenceNumber , summaryVersion ? ) { const requestHeader = { [ LoaderHeader . cache ] : false , [ LoaderHeader . clientDetails ] : { capabilities : { interactive : true } , type : "summarizer" } , [ DriverHeader . summarizingClient ] : true , [ LoaderHeader . reconnect ] : false , [ LoaderHeader . sequenceNumber ] : sequenceNumber , [ LoaderHeader . version ] : summaryVersion } ; const summarizer = await provider . loadContainer ( runtimeFactory , undefined , requestHeader ) ; const summaryCollection = new SummaryCollection ( summarizer . deltaManager , new TelemetryNullLogger ( ) ) ; summaryCollection . on ( "summaryNack" , ( op ) => { throw new Error ( `Received Nack for sequence#: ${ op . contents . summaryProposal . summarySequenceNumber }` ) ; } ) ; const defaultDataStore = await requestFluidObject < TestDataObject > ( summarizer , "default" ) ; return { containerRuntime : defaultDataStore . containerRuntime , summaryCollection } ; } returns export async function submitAndAckSummary ( provider , summarizerClient , logger , fullTree = false ) { await provider . ensureSynchronized ( ) ; const summarySequenceNumber = summarizerClient . containerRuntime . deltaManager . lastSequenceNumber ; const result = await summarizerClient . containerRuntime . submitSummary ( { fullTree , refreshLatestAck : false , summaryLogger : logger , cancellationToken : neverCancelledSummaryToken } ) ; assert ( result . stage === "submit" , "The summary was not submitted" ) ; const ackedSummary = await summarizerClient . summaryCollection . waitSummaryAck ( summarySequenceNumber ) ; await summarizerClient . containerRuntime . refreshLatestSummaryAck ( ackedSummary . summaryOp . contents . handle , ackedSummary . summaryAck . contents . handle , ackedSummary . summaryOp . referenceSequenceNumber , logger ) ; return { ackedSummary , summarySequenceNumber } ; } export function getGCStateFromSummary ( summary ) { const rootGCTree = summary . tree [ gcTreeKey ] ; assert ( rootGCTree ?. type === SummaryType . Tree , `GC tree not available` ) ; let rootGCState = { gcNodes : { } } ; for ( const key of Object . keys ( rootGCTree . tree ) ) { if ( ! key . startsWith ( gcBlobPrefix ) ) { continue ; } const gcBlob = rootGCTree . tree [ key ] ; assert ( gcBlob ?. type === SummaryType . Blob , `GC blob not available` ) ; const gcState = JSON . parse ( gcBlob . content as string ) as IGarbageCollectionState ; rootGCState = concatGarbageCollectionStates ( rootGCState , gcState ) ; } return rootGCState ; }