import * as fs from 'fs' ; import * as path from 'path' ; import * as os from 'os' ; import * as net from 'net' ; import { withDir , DirectoryResult } from 'tmp-promise' ; import _ from 'lodash' ; import { Logger } from '../src/logging' ; import { Service , ServiceStatus , Api } from '../src' ; import { StartService , ShutdownMethod } from '../src/service' ; import { ServerOptions } from 'http' ; import { ServerOptions as HttpsServerOptions , RequestOptions } from 'https' ; /*******************************************************************************
 * Utils
 ******************************************************************************/ /** Construct a promise to a service command. */ export function testService ( command , args , shutdownMethod = ShutdownMethod . CloseStdin ) { return new Promise ( resolve => resolve ( { command , args , shutdownMethod } ) ) ; } /**
 * Expect the given process ID to not exist.
 */ export const expectProcessToBeGone = ( pid , signal = 0 ) : void => { expect ( ( ) => process . kill ( pid , signal ) ) . toThrow ( ) ; } ; return export const collectEvents = ( service ) : ServiceStatus [ ] => { const events = [ ] ; service . events . on ( 'statusChanged' , status => events . push ( status ) ) ; return events ; } ; export function delay ( ms ) { return new Promise ( resolve => setTimeout ( resolve , ms ) ) ; } param path param options return export function makeRequest ( api , path , options ? ) { return Object . assign ( { } , api . requestParams , { path : api . requestParams . path + path , } , options ) ; } /**
 * Adds the current working directory to the PATH, only when running
 * under Windows.
 *
 * This means that the wallet and node executables can be "installed"
 * in the source directory.
 *
 * If the node backend is run in a different working directory,
 * Windows will still be able to find the executables
 */ export function setupExecPath ( ) { if ( process . platform === 'win32' ) { const cwd = process . cwd ( ) ; const paths = ( process . env . PATH || '' ) . split ( path . delimiter ) . filter ( p => p !== cwd ) ; paths . unshift ( cwd ) ; process . env . PATH = paths . join ( path . delimiter ) ; console . info ( 'PATH=' + process . env . PATH ) ; } } /**
 * Resolve the cardano-node configuration directory from the environment.
 * This would usually be provided by nix-shell.
 */ export function getShelleyConfigDir ( networkName ) { const base = process . env . CARDANO_NODE_CONFIGS ; if ( ! base ) { const msg = 'CARDANO_NODE_CONFIGS environment variable is not set. The tests will not work.' ; console . error ( msg ) ; throw new Error ( msg ) ; } return path . resolve ( base , networkName ) ; } /**
 * Get path of data files in the typescript sources.
 * The __dirname variable points to the compiled .js file in dist/test/.
 */ export const testDataDir = path . resolve ( __dirname , '..' , '..' , 'test' , 'data' ) ; /**
 * Set up a temporary directory containing configuration files for
 * Shelley mainnet.
 *
 * This is needed because files in the cardano-node configuration file
 * are resolved relative to the current working directory, rather than
 * relative to the path of the config file.
 *
 * The temporary directory is deleted after the callback completes,
 * unless the environment variable `NO_CLEANUP` is set.
 */ export async function withMainnetConfigDir < T > ( cb ) { const mainnet = getShelleyConfigDir ( 'mainnet' ) ; return await withDir ( async ( o ) => { const configs = _ . mapValues ( { configuration : 'configuration.json' , genesisByron : 'genesis-byron.json' , genesisShelley : 'genesis-shelley.json' , genesisAlonzo : 'genesis-alonzo.json' , topology : 'topology.json' , } , ( f ) => { return { src : path . join ( mainnet , f ) , dst : path . join ( o . path , f ) , } ; } ) ; for ( const [ name , file ] of _ . toPairs ( configs ) ) { if ( name === 'configuration' ) { const config = await fs . promises . readFile ( configs . configuration . src , 'utf-8' ) ; const configFixed = config . replace ( /^.*SocketPath.*$/gm , '' ) ; await fs . promises . writeFile ( configs . configuration . dst , configFixed ) ; } else { await fs . promises . copyFile ( file . src , file . dst ) ; } } return await cb ( o . path ) ; } , { unsafeCleanup : true , keep : ! ! process . env . NO_CLEANUP , prefix : 'launcher-test-config-' , } ) ; } returns export function listExternalAddresses ( family ? ) { const isExternal = ( iface ) : boolean => ( ! family || iface . family === family ) && ! iface . internal && iface . address != '0' ; const externalAddrs = ( iface ) => isExternal ( iface ) ? [ iface . address ] : [ ] ; const ifaceAddrs = ( ifaces ) => ifaces ? _ . map ( ifaces , externalAddrs ) : [ ] ; return _ . flattenDeep ( _ . map ( os . networkInterfaces ( ) , ifaceAddrs ) ) ; } /** Try to make a connection to a port and return whether this succeeded. */ export function testPort ( host , port , logger ) { const addr = { host , port } ; logger . info ( `Testing TCP port ${ addr . host }:${ addr . port }...` ) ; return new Promise ( resolve => { const client = new net . Socket ( ) ; client . connect ( addr , ( ) => { logger . info ( `... port accepted a connection` ) ; resolve ( true ) ; } ) ; client . on ( 'error' , err => { logger . info ( `... port refused a connection: ${ err }` ) ; resolve ( false ) ; } ) ; } ) ; }