import { existsSync , readdirSync , readFileSync } from 'fs' ; import { join , parse , resolve , sep } from 'path' ; import { createLogger } from '@sap-cloud-sdk/util' ; import { Destination } from '@sap-cloud-sdk/connectivity' ; const logger = createLogger ( { package : 'test-util' , messageContext : 'test-destination-provider' } ) ; const SYSTEMS_FILE = 'systems.json' ; const CREDENTIALS_FILE = 'credentials.json' ; export interface GetTestDestinationOptions { systemsFilePath ? : string ; credentialsFilePath ? : string ; } interface System { alias : string ; uri : string ; sapClient ? : string ; } interface SystemsFile { systems : System [ ] ; } interface Credentials { alias : string ; username : string ; password : string ; } interface CredentialsFile { credentials : Credentials [ ] ; } const formatSystemJson = `Format of systems.json is:
{
  systems:[
  {
    alias:     A unique identifier. Used for matching a system and credentials.
    uri:       A unique resource identifier like "http://mySystem.com"
    sapClient?: The sap client as string e.g. "001"
  },...
  ]
}` ; const formatCredentials = `Format of credentials.json is:
{
  credentials:[
  {
    alias:     A unique identifier. Used for matching a system and credentials.
    username:  The username used for basic authentication.
    password: The password used for basic autentication.
  },...
  ]
}` ; param alias param options returns export function getTestDestinationByAlias ( alias , options ? ) { const destinations = getTestDestinations ( options ) ; const matchingDestination = destinations . find ( d => d . name === alias ) ; if ( ! matchingDestination ) { throw new Error ( `Couldn't find destination that matches the provided name "${ alias }".
      The following destinations could be found: ${ destinations . map ( d => d . name ) . join ( ', ' ) }` ) ; } return matchingDestination ; } param options returns export function getTestDestinations ( options ? ) { const systems = readSystemsOrFail ( options ) ; const credentials = readCredentialsOrFail ( options ) ; return toDestinations ( mergeSystemsAndCredentials ( systems , credentials ) ) ; } function readSystemsOrFail ( options ? ) { if ( options && options . systemsFilePath ) { if ( ! existsSync ( options . systemsFilePath ) ) { throw new Error ( `The provided path (${ options . systemsFilePath }) to the systems file is invalid!` ) ; } return readSystems ( options . systemsFilePath ) . systems ; } const foundPath = findFileSearchingUpwards ( process . cwd ( ) , SYSTEMS_FILE ) ; if ( ! foundPath ) { throw new Error ( `No ${ SYSTEMS_FILE } could be found when searching in directory ${ process . cwd ( ) } and upwards and no paths have been provided directly. ${ formatSystemJson }` ) ; } return readSystems ( join ( foundPath , SYSTEMS_FILE ) ) . systems ; } function readCredentialsOrFail ( options ? ) { if ( options && options . credentialsFilePath ) { if ( existsSync ( options . credentialsFilePath ) ) { return readCredentials ( options . credentialsFilePath ) . credentials ; } throw new Error ( `The provided path (${ options . credentialsFilePath }) to the credentials file is invalid!` ) ; } const foundPath = findFileSearchingUpwards ( process . cwd ( ) , CREDENTIALS_FILE ) ; if ( foundPath && existsSync ( join ( foundPath , CREDENTIALS_FILE ) ) ) { return readCredentials ( join ( foundPath , CREDENTIALS_FILE ) ) . credentials ; } logger . warn ( `No path to a ${ CREDENTIALS_FILE } provided and none found next to ${ foundPath }${ sep }${ SYSTEMS_FILE }. Proceeding without credentials.` ) ; return [ ] ; } function mergeSystemsAndCredentials ( systems , credentials ) { return systems . map ( system => ( { ... system , ... credentials . find ( cred => cred . alias === system . alias ) } ) ) ; } function toDestinations ( systemsAndCredentials ) { return systemsAndCredentials . map ( sysAndCred => ( { name : sysAndCred . alias , url : sysAndCred . uri , username : sysAndCred . username , password : sysAndCred . password , sapClient : sysAndCred . sapClient , isTestDestination : true } ) ) ; } function findFileSearchingUpwards ( dir , fileName ) { const files = readdirSync ( dir ) ; const rootPath = parse ( process . cwd ( ) ) . root ; if ( files . includes ( fileName ) ) { return dir ; } if ( dir === rootPath ) { return null ; } const oneDirUp = resolve ( dir , '..' ) ; return findFileSearchingUpwards ( oneDirUp , fileName ) ; } function readSystems ( filePath ) { const systemfile = readJson ( filePath ) as SystemsFile ; if ( ! systemfile . systems || systemfile . systems . length === 0 ) { throw new Error ( `No systems provided in ${ filePath }.
                     If you do not want to define systems just remove the file. ${ formatSystemJson }` ) ; } systemfile . systems . forEach ( system => { if ( ! system . alias || ! system . uri ) { throw new Error ( `A system in ${ filePath } is not valid - Mandatory alias or url missing.
                       Broken entry is: ${ JSON . stringify ( system ) }. ${ formatSystemJson }` ) ; } } ) ; return systemfile ; } function readCredentials ( filePath ) { const credentialsFile = readJson ( filePath ) as CredentialsFile ; if ( ! credentialsFile . credentials || credentialsFile . credentials . length === 0 ) { throw new Error ( `No credentials provided in ${ filePath }.
                     If you do not want to define credentials just remove the file. ${ formatCredentials }` ) ; } credentialsFile . credentials . forEach ( cred => { if ( ! cred . alias || ! cred . username || ! cred . password ) { throw new Error ( `A credential in ${ filePath } is not valid - Mandatory alias, username or password missing.
                       Broken entry is: ${ JSON . stringify ( cred ) }. ${ formatCredentials }` ) ; } } ) ; return credentialsFile ; } function readJson ( filePath ) { let content ; try { content = readFileSync ( filePath , 'utf8' ) ; } catch ( error ) { throw new Error ( `Failed to read file at path: ${ filePath }.
      Original error: ${ error . message }` ) ; } try { return JSON . parse ( content ) ; } catch ( error ) { throw new Error ( `File read from path ${ filePath } is not valid JSON.
      Original error: ${ error . message }` ) ; } }