import { mochaTmpdir } from "@adpt/testutils" ; import * as fs from "fs-extra" ; import { JsonDB } from "node-json-db" ; import * as path from "path" ; import should from "should" ; import { HistoryEntry , HistoryStatus , HistoryStore } from "../../src/server/history" ; import { createLocalHistoryStore , dataDirName , dependenciesFilename , domFilename , infoFilename , observationsFilename , stateFilename , } from "../../src/server/local_history" ; async function historyDirs ( holdingLock = false , dirname ) { const rootFiles = await fs . readdir ( dirname ) ; const expectedFiles = holdingLock ? [ "dataDir.uncommitted" , "dataDir.uncommitted.lock" ] : [ ] ; const actualFiles = [ ] ; const histFiles = rootFiles . filter ( ( f ) => { switch ( f ) { case "dataDir.uncommitted" : case "dataDir.uncommitted.lock" : actualFiles . push ( f ) ; return false ; } return true ; } ) ; should ( actualFiles ) . eql ( expectedFiles ) ; return histFiles ; } describe ( "Local history store tests" , ( ) => { let hs_ ; function historyRoot ( ) { return path . join ( process . cwd ( ) , "history" ) ; } async function initLocalHistory ( ) { const db = new JsonDB ( path . resolve ( "db.json" ) , true , true ) ; hs_ = await createLocalHistoryStore ( db , "/deployments/dep1" , historyRoot ( ) , true ) ; return { db , hs : hs_ } ; } mochaTmpdir . each ( "adapt-test-statehistory" ) ; afterEach ( "cleanup history" , async ( ) => { if ( ! hs_ ) return ; await hs_ . destroy ( ) ; hs_ = undefined ; } ) ; it ( "Should init and destroy history dir" , async ( ) => { should ( await fs . pathExists ( historyRoot ( ) ) ) . be . False ( ) ; const { hs } = await initLocalHistory ( ) ; should ( await fs . pathExists ( historyRoot ( ) ) ) . be . True ( ) ; await hs . destroy ( ) ; should ( await fs . pathExists ( historyRoot ( ) ) ) . be . False ( ) ; } ) ; it ( "Should destroy history dir when locked" , async ( ) => { should ( await fs . pathExists ( historyRoot ( ) ) ) . be . False ( ) ; const { hs } = await initLocalHistory ( ) ; should ( await fs . pathExists ( historyRoot ( ) ) ) . be . True ( ) ; const dataDir = await hs . getDataDir ( HistoryStatus . complete ) ; should ( await fs . pathExists ( dataDir ) ) . be . True ( ) ; const lockPath = path . join ( historyRoot ( ) , dataDirName + ".uncommitted.lock" ) ; should ( await fs . pathExists ( lockPath ) ) . be . True ( ) ; await hs . destroy ( ) ; should ( await fs . pathExists ( historyRoot ( ) ) ) . be . False ( ) ; } ) ; it ( "Should init a local history and write entries" , async ( ) => { const { hs , db } = await initLocalHistory ( ) ; const last = await hs . last ( HistoryStatus . complete ) ; should ( last ) . be . Undefined ( ) ; const origInfo = { fileName : "somefile.tsx" , projectRoot : "/somedir" , stackName : "mystack" , } ; const dataDir = await hs . getDataDir ( HistoryStatus . complete ) ; should ( dataDir ) . equal ( path . join ( historyRoot ( ) , dataDirName + ".uncommitted" ) ) ; should ( await fs . pathExists ( dataDir ) ) . be . True ( ) ; await fs . writeFile ( path . join ( dataDir , "testfile" ) , "this is a test" ) ; const entry = { dependenciesJson : `{"depsJson":true}` , dataDir , domXml : "<Adapt/>" , stateJson : `{"stateJson":true}` , observationsJson : `{ "test": { data: { "foo": 1 }, context: {"bar": 1}  } }` , status : HistoryStatus . preAct , ... origInfo } ; await hs . commitEntry ( entry ) ; const hDirs = await historyDirs ( true , historyRoot ( ) ) ; should ( hDirs ) . have . length ( 1 ) ; const dir = path . join ( historyRoot ( ) , hDirs [ 0 ] ) ; const domXml = await fs . readFile ( path . join ( dir , domFilename ) ) ; const stateJson = await fs . readFile ( path . join ( dir , stateFilename ) ) ; const observationsJson = await fs . readFile ( path . join ( dir , observationsFilename ) ) ; const dependenciesJson = await fs . readFile ( path . join ( dir , dependenciesFilename ) ) ; const info = await fs . readJson ( path . join ( dir , infoFilename ) ) ; const committedDataDir = path . join ( dir , dataDirName ) ; const testfile = await fs . readFile ( path . join ( committedDataDir , "testfile" ) ) ; should ( domXml . toString ( ) ) . equal ( entry . domXml ) ; should ( stateJson . toString ( ) ) . equal ( entry . stateJson ) ; should ( observationsJson . toString ( ) ) . equal ( entry . observationsJson ) ; should ( dependenciesJson . toString ( ) ) . equal ( entry . dependenciesJson ) ; should ( info ) . eql ( { ... origInfo , status : "preAct" , dataDir : committedDataDir , } ) ; should ( testfile . toString ( ) ) . equal ( "this is a test" ) ; should ( db . getData ( "/deployments/dep1" ) ) . eql ( { stateDirs : hDirs } ) ; } ) ; it ( "Should reconstitute previous dataDir" , async ( ) => { const { hs } = await initLocalHistory ( ) ; const last = await hs . last ( HistoryStatus . complete ) ; should ( last ) . be . Undefined ( ) ; const origInfo = { fileName : "somefile.tsx" , projectRoot : "/somedir" , stackName : "mystack" , } ; let dataDir = await hs . getDataDir ( HistoryStatus . complete ) ; should ( dataDir ) . equal ( path . join ( historyRoot ( ) , dataDirName + ".uncommitted" ) ) ; should ( await fs . pathExists ( dataDir ) ) . be . True ( ) ; await fs . writeFile ( path . join ( dataDir , "testfile" ) , "this is a test" ) ; const entry = { dependenciesJson : `{"depsJson":true}` , dataDir , domXml : "<Adapt/>" , stateJson : `{"stateJson":true}` , observationsJson : `{ "test": { data: { "foo": 1 }, context: {"bar": 1}  } }` , status : HistoryStatus . preAct , ... origInfo } ; await hs . commitEntry ( entry ) ; let hDirs = await historyDirs ( true , historyRoot ( ) ) ; should ( hDirs ) . have . length ( 1 ) ; should ( await fs . pathExists ( dataDir ) ) . be . True ( ) ; await should ( hs . getDataDir ( HistoryStatus . complete ) ) . be . rejectedWith ( /attempting to lock dataDir.*twice/ ) ; await fs . writeFile ( path . join ( dataDir , "testfile" ) , "this has been updated" ) ; await hs . commitEntry ( { ... entry , status : HistoryStatus . success , } ) ; hDirs = await historyDirs ( false , historyRoot ( ) ) ; should ( hDirs ) . have . length ( 2 ) ; should ( await fs . pathExists ( dataDir ) ) . be . False ( ) ; dataDir = await hs . getDataDir ( HistoryStatus . preAct ) ; let testfile = await fs . readFile ( path . join ( dataDir , "testfile" ) ) ; should ( testfile . toString ( ) ) . equal ( "this is a test" ) ; await hs . releaseDataDir ( ) ; should ( await fs . pathExists ( dataDir ) ) . be . False ( ) ; dataDir = await hs . getDataDir ( HistoryStatus . complete ) ; testfile = await fs . readFile ( path . join ( dataDir , "testfile" ) ) ; should ( testfile . toString ( ) ) . equal ( "this has been updated" ) ; await hs . releaseDataDir ( ) ; should ( await fs . pathExists ( dataDir ) ) . be . False ( ) ; } ) ; } ) ;