TestHelper.js


/**
 * Test helper
 */
const _path_ = require("path");
const _process_ = require("process");
const _child_process_ = require("child_process");
const _http_ = require("http");
const _util_ = require('util');
const _exec_ = _util_.promisify(_child_process_.exec);


const Configuration = require("./Configuration.js");
const DexcaliburWorkspace = require('./DexcaliburWorkspace');
const DexcaliburEngine = require('./DexcaliburEngine');
const DexcaliburProject = require('./DexcaliburProject');


/**
 * Unit test utility class
 * 
 * Help to:
 * - generate a valid Configuration instance into test/* folder
 * - allow to send request to test web server front controller
 * 
 * Test Helper configuration 
 * 
 * @class
 */
class TestHelper
{
    constructor(){
        this.app = null;
        this.testCfg = require( _path_.join( __dirname, "../test/test_configuration.js") );
        this.config = null;
        this.engine = null;
        this.interceptors = {
            exec: []
        };
    }

    /**
     * To verify if a NodeJS module is loaded or not by its name
     * 
     * @param {String} pModuleName Module name
     * @returns {Boolean} TRUE is the module is loaded, else FALSE
     * @method
     */
    checkIfModuleIsLoaded( pModuleName){
        let loaded= Object.keys(require('module')._cache);
        let pattern = '/node_modules/'+pModuleName+'/';

        for(let i=0; i<loaded.length; i++){
            if(loaded[i].indexOf(pattern)>-1)
                return true;
        }

        return false;
    }
    /**
     * To set the web server instance
     * @param {require('express').Application} pInstance Web server instance  
     * @method
     */
    setWebServerInstance( pInstance){
        this.app = pInstance;
    }


    newConfiguration(){
        this.config = new Configuration();
        this.config.import(require(_path_.join( __dirname, this.testCfg.configuration)));
        this.config.workspacePath = _path_.join( __dirname, '../test/workspace/');
        return this.config;
    } 

    getConfiguration(){
        return this.config;
    }

    getConfigurationPath(){
        // return this.testCfg.configuration;
        return _path_.join( __dirname, this.testCfg.configuration);
    }

    interceptExec( pInterceptor, pReturn){
        if( this.interceptors.exec == null) this.interceptors.exec = [];
        this.interceptors.exec.push({ test:pInterceptor, ret:pReturn });
    }

    filterInterceptor( pType, pInput){
        for(let i=0; i<this.interceptors[pType].length; i++){
            if(this.interceptors[pType][i].test(pInput)){
                return {success:true, ret: this.interceptors[pType][i].ret};
            }
        }

        return {success:false };
    }

    clearInterceptors(){
        this.interceptors = {};
    }

    /**
     * To mock conditionnaly Process.execSync()
     * 
     * @param {*} pCmd 
     */
    execSync( pCmd){
        let res = this.filterInterceptor( "exec", pCmd);
        if(res.success){
            return res.ret;
        }else{
            return _process_.execSync( pCmd);
        }
    }

    /**
     * To mock conditionnaly Process.execAsync()
     *
     * @param {*} pCmd
     */
    async execAsync( pCmd){
        let res = this.filterInterceptor( "exec", pCmd);
        if(res.success){
            return res.ret;
        }else{
            return await _exec_(pCmd);;
        }
    }

    /**
     * 
     * @param {String} pMethod The HTTP method : GET | POST | PUT | DELETE
     * @param {*} pURL  
     * @param {*} pData 
     * @param {*} pContentType 
     */
    sendHTTPRequest( pMethod, pURL, pData=null, pContentType = null){
        let req = null;
        switch(pMethod){
            case 'GET':
                req = _http_.get(pURL);
                break;
            case 'POST':
                req = _http_.post(pURL)
                    .set('Content-Type', pContentType)
                    .send(pData);
                break;
        }

        return req;
    }
    /**
     * To send serialized data in JSON format through 
     * an HTTP POST request to a given URL.
     * 
     * @param {String} pURL 
     * @param {Object} pData 
     */
    sendRequest_POST_JSON( pURL, pData){
        return this.sendHTTPRequest( 'POST', pURL, pData, 'application/json'); 
    }

    /**
     * To send an HTTP GET request to a given URL.
     * 
     * @param {String} pURL 
     * @param {Object} pData 
     */
    sendRequest_GET( pURL){
        return this.sendHTTPRequest( 'GET', pURL); 
    }

    /**
     * 
     * @param {*} pPath 
     * @method
     */
    resetDexcaliburWorkspace( pPath=null){
        let dxc = DexcaliburWorkspace.getInstance(
            _path_.join(__dirname,'..','test','ws'), true
        );
        dxc.init();
    }

    /**
     * @method
     */
    newDexcaliburEngine(){
        
        DexcaliburWorkspace.clearInstance();

        let engine = DexcaliburEngine.getInstance();

        engine.loadWorkspaceFromConfig( 
            _path_.join( __dirname, '..', 'test', '.dexcalibur'),
            {
                workspace: _path_.join( __dirname, '..', 'test', 'ws')
            });

        engine.boot();
        
        return engine;
    }

    /**
     * 
     * @param {*} pForce 
     * @method
     */
    getDexcaliburEngine(pForce = false){
        if(this.engine == null || pForce){
            this.engine = this.newDexcaliburEngine();
        }

        return this.engine;
    }

    /**
     *
     * @returns {DexcaliburProject}
     */
    newDexcaliburProject(){
        this.project = new DexcaliburProject(
            DexcaliburEngine.getInstance(),
            'owasp.mstg.uncrackable1'
        );

        return this.project;
    }

    /**
     *
     * @param pForce
     * @returns {DexcaliburProject}
     */
    getDexcaliburProject(pForce = false){
        if(this.project == null || pForce){
            this.project = this.newDexcaliburProject();
        }

        return this.project;
    }


    /**
     *
     * @param pForce
     * @returns {DexcaliburProject}
     */
    getInitializedDexcaliburProject(pForce = false){
        if(this.project_ready == null || pForce){
            this.project_ready = new DexcaliburProject(
                this.newDexcaliburEngine(),
                'owasp.mstg.uncrackable1'
            );
            this.project_ready.init();
        }

        return this.project_ready;
    }

}

module.exports =  new TestHelper();