<commit_before>/*
 * Copyright 2014 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of fiware-iotagent-lib
 *
 * fiware-iotagent-lib is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * fiware-iotagent-lib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with fiware-iotagent-lib.
 * If not, seehttp://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License
 * please contact with::daniel.moranjimenez@telefonica.com
 */

'use strict';

var request = require('request'),
    async = require('async'),
    apply = async.apply,
    errors = require('../errors'),
    logger = require('fiware-node-logger'),
    security = require('./securityService'),
    _ = require('underscore'),
    context = {
        op: 'IoTAgentNGSI.NGSIService'
    },
    registry,
    config;

/**
 * Given a NGSI Body, determines whether it contains any NGSI error.
 *
 * @param {String} body             String representing a NGSI body in JSON format.
 * @return {Number|*}
 */
function getErrorField(body) {
    var errorField = body.errorCode ||
        body.orionError;

    if (body && body.contextResponses &&
        body.contextResponses[0] && body.contextResponses[0] &&
        body.contextResponses[0].statusCode && body.contextResponses[0].statusCode.code !== '200') {
        errorField = body.contextResponses[0].statusCode.reasonPhrase +
        ': ' + body.contextResponses[0].statusCode.details;
    }

    return errorField;
}

/**
 * Sends a Context Provider registration or unregistration request to the Context Broker. As registrations cannot be
 * removed, an unregistration consists of an update of the existent registration to make reduce its duration to
 * 1 second.
 *
 * The entity type, entity name and lazy attributes list are needed in order to send the registration:
 *
 * @param {Boolen} unregister       Indicates whether this registration is an unregistration or register.
 * @param {Object} deviceData       Object containing all the deviceData needed to send the registration.
 */
function sendRegistrations(unregister, deviceData, callback) {
    var options = {
        url: 'http://' + config.contextBroker.host + ':' + config.contextBroker.port + '/NGSI9/registerContext',
        method: 'POST',
        json: {
            contextRegistrations: [
                {
                    entities: [
                        {
                            type: deviceData.type,
                            isPattern: 'false',
                            id: String(deviceData.name)
                        }
                    ],
                    attributes: [],
                    providingApplication: config.providerUrl
                }
            ],
            duration: (unregister) ? 'PT1S' : config.deviceRegistrationDuration
        },
        headers: {
            'fiware-service': deviceData.service,
            'fiware-servicepath': deviceData.subservice
        }
    };

    if (deviceData.registrationId) {
        options.json.registrationId = deviceData.registrationId;
    }

    for (var i = 0; i < deviceData.lazy.length; i++) {
        options.json.contextRegistrations[0].attributes.push({
            name: deviceData.lazy[i].name,
            type: deviceData.lazy[i].type,
            isDomain: 'false'
        });
    }

    logger.debug(context, 'Sending device registrations to Context Broker at [%s]', options.url);
    logger.debug(context, 'Using the following request:\n\n%s\n\n', JSON.stringify(options, null, 4));

    request(options, function(error, response, body) {
        if (error) {
            logger.error(context, 'Connection error sending registrations to the Context Broker: %s', error);
            callback(error);
        } else if (response && body && response.statusCode === 200) {
            var errorField = getErrorField(body);

            if (errorField) {
                logger.error(context, 'Registration error connecting to the Context Broker: %j', errorField);
                callback(new errors.BadRequest(JSON.stringify(errorField)));
            } else {
                logger.debug(context, 'Registration success.');
                callback(null, body);
            }
        } else {
            var errorObj;

            logger.error(context, 'Protocol error connecting to the Context Broker: %j', errorObj);

            if (unregister) {
                errorObj = new errors.UnregistrationError(deviceData.id, deviceData.type);
            } else {
                errorObj = new errors.RegistrationError(deviceData.id, deviceData.type);
            }

            callback(errorObj);
        }
    });
}

/**
 * Process the response from a Register Context request for a device, extracting the 'registrationId' and creating the
 * device object that will be stored in the registry.
 *
 * @param {Object} deviceData       Object containing all the deviceData needed to send the registration.
 *
 */
function processContextRegistration(deviceData, body, callback) {
    var newDevice = _.clone(deviceData);

    newDevice.registrationId = body.registrationId;

    callback(null, newDevice);
}

/**
 * Register a new device identified by the Id and Type in the Context Broker, and the internal registry.
 *
 * The device id and type are required fields for any registration. The rest of the parameters are optional, but, if
 * they are not present in the function call arguments, the type must be registered in the configuration, so the
 * service can infer their default values from the configured type. If an optional attribute is not given in the
 * parameter list and there isn't a default configuration for the given type, a TypeNotFound error is raised.
 *
 * When an optional parameter is not included in the call, a null value must be given in its place.
 *
 * @param {Object} deviceObj                    Object with all the device information (mandatory).
 */
function registerDevice(deviceObj, callback) {
    var deviceData = _.clone(deviceObj);

    logger.debug(context, 'Registering device into NGSI Service:\n%s', JSON.stringify(deviceData, null, 4));

    if (!deviceData.name) {
        logger.debug(context, 'Device name not found, falling back to device id [%s]', deviceData.id);
        deviceData.name = deviceData.id;
    }

    if (!deviceObj.service || !deviceObj.subservice || !deviceObj.lazy) {
        if (config.types[deviceObj.type]) {
            logger.debug(context, 'Device type [%s] found', deviceObj.type);

            var fields = ['service', 'subservice', 'lazy', 'internalAttributes', 'active'];

            for (var i = 0; i < fields.length; i++) {
                deviceData[fields[i]] =
                    (deviceObj[fields[i]]) ? deviceData[fields[i]] : config.types[deviceObj.type][fields[i]];
            }
        } else {
            logger.debug(context, 'Device type not found [%s] for device [%s]', deviceObj.type, deviceData.name);
            callback(new errors.TypeNotFound(deviceObj.id, deviceObj.type));
            return;
        }
    }

    async.waterfall([
        async.apply(sendRegistrations, false, deviceData),
        async.apply(processContextRegistration, deviceData),
        registry.store
    ], callback);
}

/**
 * Makes an update in the Device's entity in the context broker, with the values given in the 'attributes' array. This
 * array should comply to the NGSI's attribute format.
 *
 * @param {String} deviceId     Device ID of the device to register.
 * @param {String} deviceType   Type of device to register.
 * @param {Array} attributes    Attribute array containing the values to update.
 * @param {String} token        User token to identify against the PEP Proxies (optional).
 */
function sendUpdateValue(deviceId, deviceType, attributes, token, callback) {
    var brokerHost = config.contextBroker.host,
        brokerPort = config.contextBroker.port,
        options,
        headers = {
            'fiware-service': config.service,
            'fiware-servicepath': config.subservice,
            'X-Auth-Token': token
        };

    if (config.types[deviceType]) {
        if (config.types[deviceType].service) {
            headers['fiware-service'] = config.types[deviceType].service;
        }

        if (config.types[deviceType].subservice) {
            headers['fiware-servicepath'] = config.types[deviceType].subservice;
        }

        if (config.types[deviceType].contextBroker) {
            brokerHost = config.types[deviceType].contextBroker.host;
            brokerPort = config.types[deviceType].contextBroker.port;
        }
    }

    options = {
        url: 'http://' + brokerHost + ':' + brokerPort + '/v1/updateContext',
        method: 'POST',
        json: {
            contextElements: [
                {
                    type: deviceType,
                    isPattern: 'false',
                    id: deviceId,
                    attributes: attributes
                }
            ],
            updateAction: 'APPEND'
        },
        headers: headers
    };

    logger.debug(context, 'Updating device value in the Context Broker at [%s]', options.url);
    logger.debug(context, 'Using the following request:\n\n%s\n\n', JSON.stringify(options, null, 4));

    request(options, function(error, response, body) {
        if (error) {
            logger.debug(context, 'Error found updating value in Context Broker: %s', error);
            callback(error);
        } else if (body.orionError) {
            logger.debug(context, 'Orion error found updating value in Context Broker: %j', body.orionError);
            callback(new errors.BadRequest(body.orionError.details));
        } else if (response && body && response.statusCode === 200) {
            var errorField = getErrorField(body);

            if (errorField) {
                logger.error(context, 'Update value error connecting to the Context Broker: %j', errorField);
                callback(new errors.BadRequest(JSON.stringify(errorField)));
            } else {
                logger.debug(context, 'Value updated successfully');
                callback(null, body);
            }
        } else if (response && response.statusCode === 403) {
            logger.debug(context, 'Access forbidden updating value');
            callback(new errors.AccessForbidden(
                token,
                options.headers['fiware-service'],
                options.headers['fiware-servicepath']));
        } else {
            logger.debug(context, 'Unknown error updating value');
            callback(new errors.EntityUpdateError(deviceId, deviceType));
        }
    });
}

/**
 * Launches the updating process, getting the security token in case the authorization sequence is enabled.
 *
 * @param {String} deviceId     Device ID of the device to register.
 * @param {String} deviceType   Type of device to register.
 * @param {Array} attributes    Attribute array containing the values to update.
 */
function updateValue(deviceId, deviceType, attributes, callback) {
    if (config.authentication && config.authentication.enabled) {
        if (config.types[deviceType] && config.types[deviceType].trust) {
            async.waterfall([
                apply(security.getToken, config.types[deviceType].trust),
                apply(sendUpdateValue, deviceId, deviceType, attributes)
            ], callback);
        } else {
            callback(new errors.SecurityInformationMissing(deviceType));
        }
    } else {
        sendUpdateValue(deviceId, deviceType, attributes, null, callback);
    }
}

/**
 * Unregister a device from the Context broker and the internal registry.
 *
 * @param {String} id           Device ID of the device to register.
 * @param {String} type         Type of device to register.
 */
function unregisterDevice(id, type, callback) {
    function processContextUnregister(body, innerCallback) {
        innerCallback(null);
    }

    logger.debug(context, 'Unregistering device from NGSI Service');

    async.waterfall([
        async.apply(registry.get, id),
        async.apply(sendRegistrations, true),
        processContextUnregister,
        async.apply(registry.remove, id)
    ], function(error) {
        callback(error);
    });
}

/**
 * Updates the register of an existing device identified by the Id and Type in the Context Broker, and the internal
 * registry.
 *
 * The device id and type are required fields for a registration updated. Only the following attributes will be
 * updated: lazy, active and internalId. Any other change will be ignored. The registration for the active attributes
 * of the updated entity will be updated if existing, and created if not.
 *
 * @param {Object} deviceObj                    Object with all the device information (mandatory).
 */
function updateRegisterDevice(deviceObj, callback) {
    if (!deviceObj.id || !deviceObj.type) {
        callback(new errors.MissingAttributes('Id or device missing'));
        return;
    }

    logger.debug(context, 'Unregistering device from NGSI Service');

    function combineWithNewDevice(newDevice, oldDevice, callback) {
        if (oldDevice) {
            oldDevice.internalId = newDevice.internalId;
            oldDevice.lazy = newDevice.lazy;
            oldDevice.active = newDevice.active;

            callback(null, oldDevice);
        } else {
            callback(new errors.DeviceNotFound(newDevice.id));
        }

    }

    async.waterfall([
        async.apply(registry.get, deviceObj.id),
        async.apply(combineWithNewDevice, deviceObj),
        async.apply(sendRegistrations, false),
        async.apply(processContextRegistration, deviceObj),
        registry.update
    ], function(error) {
        callback(error);
    });
}

/**
 * Return a list of all the devices registered in the system.
 */
function listDevices(callback) {
    if (registry) {
        registry.list(callback);
    } else {
        logger.error(context, 'Tried to list devices before a registry was available');
        callback(new errors.RegistryNotAvailable());
    }
}

/**
 * Retrieve a device from the device registry.
 *
 * @param {String} deviceId         ID of the device to be found.
 */
function getDevice(deviceId, callback) {
    if (registry) {
        registry.get(deviceId, callback);
    } else {
        logger.error(context, 'Tried to list devices before a registry was available');
        callback(new errors.RegistryNotAvailable());
    }
}

/**
 * Initializes the NGSI service. The initialization requires a configuration object and a reference to a device
 * registry.
 *
 * @param {Object} newRegistry      Reference to a device registry, where the devices information will be stored.
 * @param {Object} newConfig        Configuration object.
 */
function init(newRegistry, newConfig, callback) {
    registry = newRegistry;
    config = newConfig;

    callback(null);
}

exports.init = init;
exports.register = registerDevice;
exports.updateRegister = updateRegisterDevice;
exports.unregister = unregisterDevice;
exports.update = updateValue;
exports.listDevices = listDevices;
exports.getDevice = getDevice;
<commit_msg>FIX Pass data object as the callback in device register update<commit_after>/*
 * Copyright 2014 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of fiware-iotagent-lib
 *
 * fiware-iotagent-lib is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * fiware-iotagent-lib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with fiware-iotagent-lib.
 * If not, seehttp://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License
 * please contact with::daniel.moranjimenez@telefonica.com
 */

'use strict';

var request = require('request'),
    async = require('async'),
    apply = async.apply,
    errors = require('../errors'),
    logger = require('fiware-node-logger'),
    security = require('./securityService'),
    _ = require('underscore'),
    context = {
        op: 'IoTAgentNGSI.NGSIService'
    },
    registry,
    config;

/**
 * Given a NGSI Body, determines whether it contains any NGSI error.
 *
 * @param {String} body             String representing a NGSI body in JSON format.
 * @return {Number|*}
 */
function getErrorField(body) {
    var errorField = body.errorCode ||
        body.orionError;

    if (body && body.contextResponses &&
        body.contextResponses[0] && body.contextResponses[0] &&
        body.contextResponses[0].statusCode && body.contextResponses[0].statusCode.code !== '200') {
        errorField = body.contextResponses[0].statusCode.reasonPhrase +
        ': ' + body.contextResponses[0].statusCode.details;
    }

    return errorField;
}

/**
 * Sends a Context Provider registration or unregistration request to the Context Broker. As registrations cannot be
 * removed, an unregistration consists of an update of the existent registration to make reduce its duration to
 * 1 second.
 *
 * The entity type, entity name and lazy attributes list are needed in order to send the registration:
 *
 * @param {Boolen} unregister       Indicates whether this registration is an unregistration or register.
 * @param {Object} deviceData       Object containing all the deviceData needed to send the registration.
 */
function sendRegistrations(unregister, deviceData, callback) {
    var options = {
        url: 'http://' + config.contextBroker.host + ':' + config.contextBroker.port + '/NGSI9/registerContext',
        method: 'POST',
        json: {
            contextRegistrations: [
                {
                    entities: [
                        {
                            type: deviceData.type,
                            isPattern: 'false',
                            id: String(deviceData.name)
                        }
                    ],
                    attributes: [],
                    providingApplication: config.providerUrl
                }
            ],
            duration: (unregister) ? 'PT1S' : config.deviceRegistrationDuration
        },
        headers: {
            'fiware-service': deviceData.service,
            'fiware-servicepath': deviceData.subservice
        }
    };

    if (deviceData.registrationId) {
        options.json.registrationId = deviceData.registrationId;
    }

    for (var i = 0; i < deviceData.lazy.length; i++) {
        options.json.contextRegistrations[0].attributes.push({
            name: deviceData.lazy[i].name,
            type: deviceData.lazy[i].type,
            isDomain: 'false'
        });
    }

    logger.debug(context, 'Sending device registrations to Context Broker at [%s]', options.url);
    logger.debug(context, 'Using the following request:\n\n%s\n\n', JSON.stringify(options, null, 4));

    request(options, function(error, response, body) {
        if (error) {
            logger.error(context, 'Connection error sending registrations to the Context Broker: %s', error);
            callback(error);
        } else if (response && body && response.statusCode === 200) {
            var errorField = getErrorField(body);

            if (errorField) {
                logger.error(context, 'Registration error connecting to the Context Broker: %j', errorField);
                callback(new errors.BadRequest(JSON.stringify(errorField)));
            } else {
                logger.debug(context, 'Registration success.');
                callback(null, body);
            }
        } else {
            var errorObj;

            logger.error(context, 'Protocol error connecting to the Context Broker: %j', errorObj);

            if (unregister) {
                errorObj = new errors.UnregistrationError(deviceData.id, deviceData.type);
            } else {
                errorObj = new errors.RegistrationError(deviceData.id, deviceData.type);
            }

            callback(errorObj);
        }
    });
}

/**
 * Process the response from a Register Context request for a device, extracting the 'registrationId' and creating the
 * device object that will be stored in the registry.
 *
 * @param {Object} deviceData       Object containing all the deviceData needed to send the registration.
 *
 */
function processContextRegistration(deviceData, body, callback) {
    var newDevice = _.clone(deviceData);

    newDevice.registrationId = body.registrationId;

    callback(null, newDevice);
}

/**
 * Register a new device identified by the Id and Type in the Context Broker, and the internal registry.
 *
 * The device id and type are required fields for any registration. The rest of the parameters are optional, but, if
 * they are not present in the function call arguments, the type must be registered in the configuration, so the
 * service can infer their default values from the configured type. If an optional attribute is not given in the
 * parameter list and there isn't a default configuration for the given type, a TypeNotFound error is raised.
 *
 * When an optional parameter is not included in the call, a null value must be given in its place.
 *
 * @param {Object} deviceObj                    Object with all the device information (mandatory).
 */
function registerDevice(deviceObj, callback) {
    var deviceData = _.clone(deviceObj);

    logger.debug(context, 'Registering device into NGSI Service:\n%s', JSON.stringify(deviceData, null, 4));

    if (!deviceData.name) {
        logger.debug(context, 'Device name not found, falling back to device id [%s]', deviceData.id);
        deviceData.name = deviceData.id;
    }

    if (!deviceObj.service || !deviceObj.subservice || !deviceObj.lazy) {
        if (config.types[deviceObj.type]) {
            logger.debug(context, 'Device type [%s] found', deviceObj.type);

            var fields = ['service', 'subservice', 'lazy', 'internalAttributes', 'active'];

            for (var i = 0; i < fields.length; i++) {
                deviceData[fields[i]] =
                    (deviceObj[fields[i]]) ? deviceData[fields[i]] : config.types[deviceObj.type][fields[i]];
            }
        } else {
            logger.debug(context, 'Device type not found [%s] for device [%s]', deviceObj.type, deviceData.name);
            callback(new errors.TypeNotFound(deviceObj.id, deviceObj.type));
            return;
        }
    }

    async.waterfall([
        async.apply(sendRegistrations, false, deviceData),
        async.apply(processContextRegistration, deviceData),
        registry.store
    ], callback);
}

/**
 * Makes an update in the Device's entity in the context broker, with the values given in the 'attributes' array. This
 * array should comply to the NGSI's attribute format.
 *
 * @param {String} deviceId     Device ID of the device to register.
 * @param {String} deviceType   Type of device to register.
 * @param {Array} attributes    Attribute array containing the values to update.
 * @param {String} token        User token to identify against the PEP Proxies (optional).
 */
function sendUpdateValue(deviceId, deviceType, attributes, token, callback) {
    var brokerHost = config.contextBroker.host,
        brokerPort = config.contextBroker.port,
        options,
        headers = {
            'fiware-service': config.service,
            'fiware-servicepath': config.subservice,
            'X-Auth-Token': token
        };

    if (config.types[deviceType]) {
        if (config.types[deviceType].service) {
            headers['fiware-service'] = config.types[deviceType].service;
        }

        if (config.types[deviceType].subservice) {
            headers['fiware-servicepath'] = config.types[deviceType].subservice;
        }

        if (config.types[deviceType].contextBroker) {
            brokerHost = config.types[deviceType].contextBroker.host;
            brokerPort = config.types[deviceType].contextBroker.port;
        }
    }

    options = {
        url: 'http://' + brokerHost + ':' + brokerPort + '/v1/updateContext',
        method: 'POST',
        json: {
            contextElements: [
                {
                    type: deviceType,
                    isPattern: 'false',
                    id: deviceId,
                    attributes: attributes
                }
            ],
            updateAction: 'APPEND'
        },
        headers: headers
    };

    logger.debug(context, 'Updating device value in the Context Broker at [%s]', options.url);
    logger.debug(context, 'Using the following request:\n\n%s\n\n', JSON.stringify(options, null, 4));

    request(options, function(error, response, body) {
        if (error) {
            logger.debug(context, 'Error found updating value in Context Broker: %s', error);
            callback(error);
        } else if (body.orionError) {
            logger.debug(context, 'Orion error found updating value in Context Broker: %j', body.orionError);
            callback(new errors.BadRequest(body.orionError.details));
        } else if (response && body && response.statusCode === 200) {
            var errorField = getErrorField(body);

            if (errorField) {
                logger.error(context, 'Update value error connecting to the Context Broker: %j', errorField);
                callback(new errors.BadRequest(JSON.stringify(errorField)));
            } else {
                logger.debug(context, 'Value updated successfully');
                callback(null, body);
            }
        } else if (response && response.statusCode === 403) {
            logger.debug(context, 'Access forbidden updating value');
            callback(new errors.AccessForbidden(
                token,
                options.headers['fiware-service'],
                options.headers['fiware-servicepath']));
        } else {
            logger.debug(context, 'Unknown error updating value');
            callback(new errors.EntityUpdateError(deviceId, deviceType));
        }
    });
}

/**
 * Launches the updating process, getting the security token in case the authorization sequence is enabled.
 *
 * @param {String} deviceId     Device ID of the device to register.
 * @param {String} deviceType   Type of device to register.
 * @param {Array} attributes    Attribute array containing the values to update.
 */
function updateValue(deviceId, deviceType, attributes, callback) {
    if (config.authentication && config.authentication.enabled) {
        if (config.types[deviceType] && config.types[deviceType].trust) {
            async.waterfall([
                apply(security.getToken, config.types[deviceType].trust),
                apply(sendUpdateValue, deviceId, deviceType, attributes)
            ], callback);
        } else {
            callback(new errors.SecurityInformationMissing(deviceType));
        }
    } else {
        sendUpdateValue(deviceId, deviceType, attributes, null, callback);
    }
}

/**
 * Unregister a device from the Context broker and the internal registry.
 *
 * @param {String} id           Device ID of the device to register.
 * @param {String} type         Type of device to register.
 */
function unregisterDevice(id, type, callback) {
    function processContextUnregister(body, innerCallback) {
        innerCallback(null);
    }

    logger.debug(context, 'Unregistering device from NGSI Service');

    async.waterfall([
        async.apply(registry.get, id),
        async.apply(sendRegistrations, true),
        processContextUnregister,
        async.apply(registry.remove, id)
    ], function(error) {
        callback(error);
    });
}

/**
 * Updates the register of an existing device identified by the Id and Type in the Context Broker, and the internal
 * registry.
 *
 * The device id and type are required fields for a registration updated. Only the following attributes will be
 * updated: lazy, active and internalId. Any other change will be ignored. The registration for the active attributes
 * of the updated entity will be updated if existing, and created if not.
 *
 * @param {Object} deviceObj                    Object with all the device information (mandatory).
 */
function updateRegisterDevice(deviceObj, callback) {
    if (!deviceObj.id || !deviceObj.type) {
        callback(new errors.MissingAttributes('Id or device missing'));
        return;
    }

    logger.debug(context, 'Unregistering device from NGSI Service');

    function combineWithNewDevice(newDevice, oldDevice, callback) {
        if (oldDevice) {
            oldDevice.internalId = newDevice.internalId;
            oldDevice.lazy = newDevice.lazy;
            oldDevice.active = newDevice.active;

            callback(null, oldDevice);
        } else {
            callback(new errors.DeviceNotFound(newDevice.id));
        }

    }

    async.waterfall([
        async.apply(registry.get, deviceObj.id),
        async.apply(combineWithNewDevice, deviceObj),
        async.apply(sendRegistrations, false),
        async.apply(processContextRegistration, deviceObj),
        registry.update
    ], callback);
}

/**
 * Return a list of all the devices registered in the system.
 */
function listDevices(callback) {
    if (registry) {
        registry.list(callback);
    } else {
        logger.error(context, 'Tried to list devices before a registry was available');
        callback(new errors.RegistryNotAvailable());
    }
}

/**
 * Retrieve a device from the device registry.
 *
 * @param {String} deviceId         ID of the device to be found.
 */
function getDevice(deviceId, callback) {
    if (registry) {
        registry.get(deviceId, callback);
    } else {
        logger.error(context, 'Tried to list devices before a registry was available');
        callback(new errors.RegistryNotAvailable());
    }
}

/**
 * Initializes the NGSI service. The initialization requires a configuration object and a reference to a device
 * registry.
 *
 * @param {Object} newRegistry      Reference to a device registry, where the devices information will be stored.
 * @param {Object} newConfig        Configuration object.
 */
function init(newRegistry, newConfig, callback) {
    registry = newRegistry;
    config = newConfig;

    callback(null);
}

exports.init = init;
exports.register = registerDevice;
exports.updateRegister = updateRegisterDevice;
exports.unregister = unregisterDevice;
exports.update = updateValue;
exports.listDevices = listDevices;
exports.getDevice = getDevice;
<|endoftext|>


<commit_before>'use strict';

const assert = require('assert');
const randomName = require('..');

function assertLength(name, length) {
  console.log(name);
  const ok = !length ? (name.length > 0) : name.length === length;
  assert.ok(ok, 'Invalid length. ' + name + ' - ' + length);
}

function run() {
  assertLength(randomName.generate());
  assertLength(randomName.generate(2), 2);
  assertLength(randomName.generate(3), 3);
  assertLength(randomName.generate(4), 4);
  assertLength(randomName.surnames.getOne());
  assertLength(randomName.names.get());
  assertLength(randomName.names.get1(), 1);
  assertLength(randomName.names.get2(), 2);
  assertLength(randomName.names.get3(), 3);
  assertLength(randomName.names.get1('火'), 1);
  assertLength(randomName.names.get2('火火'), 2);
  assertLength(randomName.names.get3('火火火'), 3);
}

for (let i = 0; i < 10000; i++) run();
<commit_msg>test: reduce test times<commit_after>'use strict';

const assert = require('assert');
const randomName = require('..');

function assertLength(name, length) {
  console.log(name);
  const ok = !length ? (name.length > 0) : name.length === length;
  assert.ok(ok, 'Invalid length. ' + name + ' - ' + length);
}

function run() {
  assertLength(randomName.generate());
  assertLength(randomName.generate(2), 2);
  assertLength(randomName.generate(3), 3);
  assertLength(randomName.generate(4), 4);
  assertLength(randomName.surnames.getOne());
  assertLength(randomName.names.get());
  assertLength(randomName.names.get1(), 1);
  assertLength(randomName.names.get2(), 2);
  assertLength(randomName.names.get3(), 3);
  assertLength(randomName.names.get1('火'), 1);
  assertLength(randomName.names.get2('火火'), 2);
  assertLength(randomName.names.get3('火火火'), 3);
}

for (let i = 0; i < 1000; i++) run();
<|endoftext|>


<commit_before>/*!
 * Bootstrap's Gruntfile
 * http://getbootstrap.com
 * Copyright 2013-2017 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 */

module.exports = function (grunt) {
  'use strict';

  // Project configuration.
  grunt.initConfig({
  })
<commit_msg>add missing bracket<commit_after>/*!
 * Bootstrap's Gruntfile
 * http://getbootstrap.com
 * Copyright 2013-2017 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 */

module.exports = function (grunt) {
  'use strict';

  // Project configuration.
  grunt.initConfig({
  })
}
<|endoftext|>


<commit_before>const _ = require('highland'),
    chai = require('chai'),
    parser = require('../lib/parser'),
    vfs = require('vinyl-fs');

let should = chai.should();

const kushner = __dirname + '/data/Kushner, Jared.pdf';

describe('lib/parser.js', () => {
    it('should find 10 tables in Jared Kushner\'s filing', (done) => {
       parser(kushner)
        .then((filing) => {
            filing.tables.length.should.equal(10);

            done();
       });
    });
});
<commit_msg>Fix Kushner test timing out<commit_after>const _ = require('highland'),
    chai = require('chai'),
    parser = require('../lib/parser'),
    vfs = require('vinyl-fs');

let should = chai.should();

const kushner = __dirname + '/data/Kushner, Jared.pdf';

describe('lib/parser.js', () => {
    it('should find 10 tables in Jared Kushner\'s filing', (done) => {
        parser(kushner)
            .then((filing) => {
                filing.tables.length.should.equal(10);

                done();
            });
    }).timeout(15000);
});
<|endoftext|>


<commit_before>module.exports = function (grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    qunit: { all: ['http://localhost:19999/js/tests/all.html'] },
    connect: { server: { options: { port: 19999, base: './public' } } },
    jshint: {
      all: [
        'public/js/lib/**/*.js',
        'Gruntfile.js'
      ],
      options: {
        indent: 2,
        expr: true,
        bitwise: true,
        camelcase: true,
        curly: true,
        immed: true,
        noarg: true,
        nonew: true,
        plusplus: true,
        quotmark: 'single',
        trailing: true,
        maxparams: 3,
        maxlen: 150,
        browser: true,
        nomen: true,
        jquery: true,
        globals: {
          '$': true,
          'console': true,
          'module': true,
          'require': true,
          'define': true,
          'Line': true,
          '$V': true,
          '_': true
        },
        undef: true
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-qunit');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-jshint');

  grunt.registerTask('test', ['connect', 'qunit']);
  grunt.registerTask('default', ['jshint', 'test']);
};
<commit_msg>disabling option temporarily<commit_after>module.exports = function (grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    qunit: { all: ['http://localhost:19999/js/tests/all.html'] },
    connect: { server: { options: { port: 19999, base: './public' } } },
    jshint: {
      all: [
        'public/js/lib/**/*.js',
        'Gruntfile.js'
      ],
      options: {
        //indent: 2,
        expr: true,
        bitwise: true,
        camelcase: true,
        curly: true,
        immed: true,
        noarg: true,
        nonew: true,
        plusplus: true,
        quotmark: 'single',
        trailing: true,
        maxparams: 3,
        maxlen: 150,
        browser: true,
        nomen: true,
        jquery: true,
        globals: {
          '$': true,
          'console': true,
          'module': true,
          'require': true,
          'define': true,
          'Line': true,
          '$V': true,
          '_': true
        },
        undef: true
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-qunit');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-jshint');

  grunt.registerTask('test', ['connect', 'qunit']);
  grunt.registerTask('default', ['jshint', 'test']);
};
<|endoftext|>


<commit_before>//Power is connected to pin4 (5V), ground is pin6, tx (output) is pin 8,
// rx (input) is pin10

var SerialPort = require('serialport').SerialPort;
var serialPort = new SerialPort('/dev/ttyAMA0', {
	baudRate: 9600
});
var EMIC = (function() {
var isOpen = false;
var isReady = true;

var emic = {};
emic.init = function () {

	console.log('Successfully loaded SerialPort module');

	console.log('Successfully initialised /dev/ttyAMA0');

	serialPort.on('open', function () {
		console.log('Port is open')
		isOpen = true;
		serialPort.on('data', function(msg) {
			msg = msg.toString('ascii');
			console.log(msg);
			serialPort.flush();
			if (msg == ':') {
				isReady = true
				console.log('Emic is ready for an instruction')
			} else { console.log('errorcheck')}
		});
		serialPort.write(':P0\r');
		serialPort.drain();

		serialPort.write(':S[:PHONE ON] [:nv] [:dv gn 75] [wiy<400,20>wih<300,25>sh<100>yu<200>ax<200,27>meh<200,25>riy<200,24>krih<300,22>s<100>mah<300>s<100>wih<400>wih<300,27>sh<100>yu<200>ax<200,29>meh<200,27>riy<200,25>krih<300,24>s<100>mah<300,20>s<100>wih<400>wih<300,29>sh<100>yu<200>ax<200,30>meh<200,29>riy<200,27>KRIH<300,25>S<100>MAH<300,22>S<100>AE<100,20>N<50>D<50>AX<200>HXAE<400,22>PIY<400,27>NUW<400,24>YXIR<600,25>_<100>]. [GUH<300,20>D<100>TAY<400,25>DIH<200>NX<100>Z<100>TUW<400>YU<800,24>WER<400>EH<400,25>VRR<400,24>YU<400,22>AR<800,20>GUH<300,27>D<100>TAY<400,29>DIH<200,27>NX<100>Z<100>FOR<400,25>KRIH<300,32>S<100>MAH<300,20>S<100>AE<100>N<50>D<50>AX<200>HXAE<400,22>PIY<400,27>NUW<400,24>YXIR<600,25>_<100>]. [WIY<400,20>WIH<300,25>SH<100>YU<200>AX<200,27>MER<200,25>RIY<200,24>KRIH<300,22>S<100>MAH<300>S<100>WIY<400>WIH<300,27>SH<100>YU<200>AX<200,29>MEH<200,27>RIY<200,25>KRIH<300,24>S<100>MAH<300,20>S<100>WIY<400>WIH<300,29>SH<100>YU<200>AX<200,30>MEH<200,29>RIY<200,27>KRIH<300,25>S<100>MAH<300,22>S<100>AE<100,20>N<50>D<50>AX<200>HXAE<400,22>PIY<400,27>NUW<400,24>YXIR<800,25>].\r');
	});
};
emic.speak = function (data) {
	data = data.toString('ascii');
	while (isOpen == false) {};
	if (data.length > 1000) {
		console.log('Error: Message exceeds the character limit');
	} else {
		//serialPort.write(':SHello World to all\r');
		serialPort.write(':S' + data + '\r');
		console.log(':S' + data + '\r');
		isReady = false
		console.log('Emic is busy')
	};
};

emic.demo = function (id) {
	id = id.toString('ascii');
	if (id == '0' || id == '1' || id == '2') {
		serialPort.write(':D' + id + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.stopNow = function () {
	serialPort.write(':X\r');
}

emic.pause = function () {
	serialPort.write(':Z\r');
};

emic.voice = function (id) {
	var idN = id.parseInt();
	if (idN >= 0 && idN <= 8) {
		id.toString('ascii');
		serialPort.write(':N' + id + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.volume = function (level) {
	var levelN = id.parseInt();
	if (levelN >= -48 && levelN <= 18) {
		level = level.toString('ascii');
		serialPort.write(':V' + level + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.rate = function (wpm) {
	var wpmN = wpm.parseInt();
	if (wpmN >= 75 && wpmN <= 600) {
		wpm = wpm.toString('ascii');
		serialPort.write(':W' + wpm + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.parser = function (id) {
	id = id.toString('ascii');
	if (parser == '0' || parser == '1' || parser == '2') {
		serialPort.write(':P' + id + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.revert = function () {
	serialPort.write(':R\r');
};

emic.callCurrentSettings = function () {
	serialPort.write(':C\r');
};

emic.callVersionInfo = function () {
	serialPort.write(':I\r');
};

emic.callCommands = function () {
	serialPort.write(':I\r');
};
return emic
}());

/*function writeLog(logFile, output){
	var logf = new File(logFile);
	logf.writeln(output);
	logf.close()*/

module.exports = EMIC;

<commit_msg>commented out parser changer<commit_after>//Power is connected to pin4 (5V), ground is pin6, tx (output) is pin 8,
// rx (input) is pin10

var SerialPort = require('serialport').SerialPort;
var serialPort = new SerialPort('/dev/ttyAMA0', {
	baudRate: 9600
});
var EMIC = (function() {
var isOpen = false;
var isReady = true;
var emic = {};

emic.init = function () {

	console.log('Successfully loaded SerialPort module');

	console.log('Successfully initialised /dev/ttyAMA0');

	serialPort.on('open', function () {
		console.log('Port is open')
		isOpen = true;
		serialPort.on('data', function(msg) {
			msg = msg.toString('ascii');
			console.log(msg);
			serialPort.flush();
			if (msg == ':') {
				isReady = true
				console.log('Emic is ready for an instruction')
			} else { console.log('errorcheck')}
		});
		//serialPort.write(':P0\r');
		//serialPort.drain();

		serialPort.write(':S[:PHONE ON] [:nv] [:dv gn 75] [wiy<400,20>wih<300,25>sh<100>yu<200>ax<200,27>meh<200,25>riy<200,24>krih<300,22>s<100>mah<300>s<100>wih<400>wih<300,27>sh<100>yu<200>ax<200,29>meh<200,27>riy<200,25>krih<300,24>s<100>mah<300,20>s<100>wih<400>wih<300,29>sh<100>yu<200>ax<200,30>meh<200,29>riy<200,27>KRIH<300,25>S<100>MAH<300,22>S<100>AE<100,20>N<50>D<50>AX<200>HXAE<400,22>PIY<400,27>NUW<400,24>YXIR<600,25>_<100>]. [GUH<300,20>D<100>TAY<400,25>DIH<200>NX<100>Z<100>TUW<400>YU<800,24>WER<400>EH<400,25>VRR<400,24>YU<400,22>AR<800,20>GUH<300,27>D<100>TAY<400,29>DIH<200,27>NX<100>Z<100>FOR<400,25>KRIH<300,32>S<100>MAH<300,20>S<100>AE<100>N<50>D<50>AX<200>HXAE<400,22>PIY<400,27>NUW<400,24>YXIR<600,25>_<100>]. [WIY<400,20>WIH<300,25>SH<100>YU<200>AX<200,27>MER<200,25>RIY<200,24>KRIH<300,22>S<100>MAH<300>S<100>WIY<400>WIH<300,27>SH<100>YU<200>AX<200,29>MEH<200,27>RIY<200,25>KRIH<300,24>S<100>MAH<300,20>S<100>WIY<400>WIH<300,29>SH<100>YU<200>AX<200,30>MEH<200,29>RIY<200,27>KRIH<300,25>S<100>MAH<300,22>S<100>AE<100,20>N<50>D<50>AX<200>HXAE<400,22>PIY<400,27>NUW<400,24>YXIR<800,25>].\r');
	});
};
emic.speak = function (data) {
	data = data.toString('ascii');
	while (isOpen == false) {};
	if (data.length > 1000) {
		console.log('Error: Message exceeds the character limit');
	} else {
		//serialPort.write(':SHello World to all\r');
		serialPort.write(':S' + data + '\r');
		console.log(':S' + data + '\r');
		isReady = false
		console.log('Emic is busy')
	};
};

emic.demo = function (id) {
	id = id.toString('ascii');
	if (id == '0' || id == '1' || id == '2') {
		serialPort.write(':D' + id + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.stopNow = function () {
	serialPort.write(':X\r');
}

emic.pause = function () {
	serialPort.write(':Z\r');
};

emic.voice = function (id) {
	var idN = id.parseInt();
	if (idN >= 0 && idN <= 8) {
		id.toString('ascii');
		serialPort.write(':N' + id + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.volume = function (level) {
	var levelN = id.parseInt();
	if (levelN >= -48 && levelN <= 18) {
		level = level.toString('ascii');
		serialPort.write(':V' + level + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.rate = function (wpm) {
	var wpmN = wpm.parseInt();
	if (wpmN >= 75 && wpmN <= 600) {
		wpm = wpm.toString('ascii');
		serialPort.write(':W' + wpm + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.parser = function (id) {
	id = id.toString('ascii');
	if (parser == '0' || parser == '1' || parser == '2') {
		serialPort.write(':P' + id + '\r');
	} else {
		console.log('Error: Invalid Command');
	};
};

emic.revert = function () {
	serialPort.write(':R\r');
};

emic.callCurrentSettings = function () {
	serialPort.write(':C\r');
};

emic.callVersionInfo = function () {
	serialPort.write(':I\r');
};

emic.callCommands = function () {
	serialPort.write(':I\r');
};
return emic
}());

/*function writeLog(logFile, output){
	var logf = new File(logFile);
	logf.writeln(output);
	logf.close()*/

module.exports = EMIC;

<|endoftext|>


<commit_before>/**
 * EventEmitter tests
 */

(function() {
	test('Adding and retrieving listeners', function() {
		var ee = new EventEmitter();

		equal(ee.listeners('testEvent'), false, 'Checking for any listeners');

		ee.addListener('testEvent', function() {
			// Listener
		});
		equal(ee.listeners('testEvent')[0].type, 'testEvent', 'Retrieving the first listener');

		ee.addListener('testEvent', function() {
			// Another listener for the same event
		});
		equal(ee.listeners('testEvent')[1].type, 'testEvent', 'Retrieving the second listener');

		ee.addListener('anotherTestEvent', function() {
			// Listener for new event
		});
		equal(ee.listeners('anotherTestEvent')[0].type, 'anotherTestEvent', 'Retrieving the first listener for a different event');

		ee.addListener('anotherTestEvent', function() {
			// Another listener for new event
		});
		equal(ee.listeners('anotherTestEvent')[1].type, 'anotherTestEvent', 'Retrieving the second listener for a different event');

		ee.addListener('onTest', function() {
			// Listener via the alias
		});
		equal(ee.listeners('onTest')[0].type, 'onTest', 'Retrieving the first listener for a different event added via the on alias');
	});

	test('Removing listeners', function() {
		var ee = new EventEmitter();

		function testListener() {
			// Listener
		}

		function testListener2() {
			// Listener 2
		}

		ee.addListener('testEvent', testListener);
		equal(ee.listeners('testEvent')[0].type, 'testEvent', 'Retrieving the first listener');

		ee.addListener('testEvent', testListener2);
		equal(ee.listeners('testEvent')[1].type, 'testEvent', 'Retrieving the second listener');

		ee.removeListener('testEvent', testListener);
		equal(ee.listeners('testEvent')[1], undefined, 'Retrieving the second listener (should be gone)');
		equal(ee.listeners('testEvent')[0].listener, testListener2, 'First should now be the second');

		ee.removeListener('testEvent', testListener2);
		equal(ee.listeners('testEvent'), false, 'Retrieving any listeners (should be gone)');

		ee.addListener('removeAllTest', function() {
			// Listener
		});
		ee.addListener('removeAllTest', function() {
			// Another listener for the same event
		});
		equal(ee.listeners('removeAllTest')[1].type, 'removeAllTest', 'Check for a second removeAllTest listener');
		ee.removeAllListeners('removeAllTest');
		equal(ee.listeners('removeAllTest'), false, 'Retrieving any listeners from removeAllTest (should be gone)');
	});

	test('Emitting events', function() {
		var ee = new EventEmitter();

		ee.addListener('emittingTest', function() {
			// Listener
			ok(true, 'First called');
		});
		ee.addListener('emittingTest', function() {
			// Another listener for the same event
			ok(true, 'Second called');
		});
		ee.addListener('differentEvent', function() {
			// Another listener for the same event
			ok(false, 'Wrong event called');
		});
		ee.emit('emittingTest');
	});

	test('Adding and calling a once event', function() {
		var ee = new EventEmitter();

		function normalFunction() {
			// Another listener for the same event but not a once event
		}

		ee.once('onceTest', function() {
			// Listener
		});
		ee.once('onceTest', function() {
			// Another listener for the same event
		});
		ee.addListener('onceTest', normalFunction);
		equal(ee.listeners('onceTest')[2].type, 'onceTest', 'Check for a third onceTest listener');

		// Emit the once test event
		ee.emit('onceTest');
		equal(ee.listeners('onceTest')[0].listener, normalFunction, 'There should only be one survivor, the normalFunction one');
		equal(ee.listeners('onceTest')[2], undefined, 'And a second should be undefined');
	});

	test('Passing arguments to listeners', function() {
		var ee = new EventEmitter();

		ee.addListener('argTest', function(aBool) {
			equal(aBool, true, 'Passing of a boolean that equals true');
		});

		ee.addListener('argTest2', function(aString, aBool) {
			equal(aString, 'foo', 'Passing of a string');
			equal(aBool, true, 'Passing of a boolean that equals true as the second argument');
		});

		ee.emit('argTest', [true]);
		ee.emit('argTest2', ['foo', true]);
	});
}());<commit_msg>Added a test for removing ALL of the listeners<commit_after>/**
 * EventEmitter tests
 */

(function() {
	test('Adding and retrieving listeners', function() {
		var ee = new EventEmitter();

		equal(ee.listeners('testEvent'), false, 'Checking for any listeners');

		ee.addListener('testEvent', function() {
			// Listener
		});
		equal(ee.listeners('testEvent')[0].type, 'testEvent', 'Retrieving the first listener');

		ee.addListener('testEvent', function() {
			// Another listener for the same event
		});
		equal(ee.listeners('testEvent')[1].type, 'testEvent', 'Retrieving the second listener');

		ee.addListener('anotherTestEvent', function() {
			// Listener for new event
		});
		equal(ee.listeners('anotherTestEvent')[0].type, 'anotherTestEvent', 'Retrieving the first listener for a different event');

		ee.addListener('anotherTestEvent', function() {
			// Another listener for new event
		});
		equal(ee.listeners('anotherTestEvent')[1].type, 'anotherTestEvent', 'Retrieving the second listener for a different event');

		ee.addListener('onTest', function() {
			// Listener via the alias
		});
		equal(ee.listeners('onTest')[0].type, 'onTest', 'Retrieving the first listener for a different event added via the on alias');
	});

	test('Removing listeners', function() {
		var ee = new EventEmitter();

		function testListener() {
			// Listener
		}

		function testListener2() {
			// Listener 2
		}

		ee.addListener('testEvent', testListener);
		equal(ee.listeners('testEvent')[0].type, 'testEvent', 'Retrieving the first listener');

		ee.addListener('testEvent', testListener2);
		equal(ee.listeners('testEvent')[1].type, 'testEvent', 'Retrieving the second listener');

		ee.removeListener('testEvent', testListener);
		equal(ee.listeners('testEvent')[1], undefined, 'Retrieving the second listener (should be gone)');
		equal(ee.listeners('testEvent')[0].listener, testListener2, 'First should now be the second');

		ee.removeListener('testEvent', testListener2);
		equal(ee.listeners('testEvent'), false, 'Retrieving any listeners (should be gone)');

		ee.addListener('removeAllTest', function() {
			// Listener
		});
		ee.addListener('removeAllTest', function() {
			// Another listener for the same event
		});
		equal(ee.listeners('removeAllTest')[1].type, 'removeAllTest', 'Check for a second removeAllTest listener');
		ee.removeAllListeners('removeAllTest');
		equal(ee.listeners('removeAllTest'), false, 'Retrieving any listeners from removeAllTest (should be gone)');
	});

	test('Removing all listeners', function() {
		var ee = new EventEmitter();

		ee.on('foo', function() {
			console.log('bar');
		});

		equal(ee.listeners('foo').length, 1, 'Check that it was added');

		ee.removeAllListeners();

		equal(ee.listeners('foo'), false, 'Check that it was removed');
	});

	test('Emitting events', function() {
		var ee = new EventEmitter();

		ee.addListener('emittingTest', function() {
			// Listener
			ok(true, 'First called');
		});
		ee.addListener('emittingTest', function() {
			// Another listener for the same event
			ok(true, 'Second called');
		});
		ee.addListener('differentEvent', function() {
			// Another listener for the same event
			ok(false, 'Wrong event called');
		});
		ee.emit('emittingTest');
	});

	test('Adding and calling a once event', function() {
		var ee = new EventEmitter();

		function normalFunction() {
			// Another listener for the same event but not a once event
		}

		ee.once('onceTest', function() {
			// Listener
		});
		ee.once('onceTest', function() {
			// Another listener for the same event
		});
		ee.addListener('onceTest', normalFunction);
		equal(ee.listeners('onceTest')[2].type, 'onceTest', 'Check for a third onceTest listener');

		// Emit the once test event
		ee.emit('onceTest');
		equal(ee.listeners('onceTest')[0].listener, normalFunction, 'There should only be one survivor, the normalFunction one');
		equal(ee.listeners('onceTest')[2], undefined, 'And a second should be undefined');
	});

	test('Passing arguments to listeners', function() {
		var ee = new EventEmitter();

		ee.addListener('argTest', function(aBool) {
			equal(aBool, true, 'Passing of a boolean that equals true');
		});

		ee.addListener('argTest2', function(aString, aBool) {
			equal(aString, 'foo', 'Passing of a string');
			equal(aBool, true, 'Passing of a boolean that equals true as the second argument');
		});

		ee.emit('argTest', [true]);
		ee.emit('argTest2', ['foo', true]);
	});
}());<|endoftext|>


<commit_before>/*
        Leaflet.OpacityControls, a plugin for adjusting the opacity of a Leaflet map.
        (c) 2013, Jared Dominguez
        (c) 2013, LizardTech

        https://github.com/lizardtechblog/Leaflet.OpacityControls
*/

//Declare global variables
var opacity_layer;

//Create a control to increase the opacity value. This makes the image more opaque.
L.Control.higherOpacity = L.Control.extend({
    options: {
        position: 'topright'
    },
    setOpacityLayer: function (layer) {
            opacity_layer = layer;
    },
    onAdd: function () {

        var higher_opacity_div = L.DomUtil.create('div', 'higher_opacity_control');

        L.DomEvent.addListener(higher_opacity_div, 'click', L.DomEvent.stopPropagation)
            .addListener(higher_opacity_div, 'click', L.DomEvent.preventDefault)
            .addListener(higher_opacity_div, 'click', function () { onClickHigherOpacity() });

        return higher_opacity_div;
    }
});

//Create a control to decrease the opacity value. This makes the image more transparent.
L.Control.lowerOpacity = L.Control.extend({
    options: {
        position: 'topright'
    },
    setOpacityLayer: function (layer) {
            opacity_layer = layer;
    },
    onAdd: function (map) {

        var lower_opacity_div = L.DomUtil.create('div', 'lower_opacity_control');

        L.DomEvent.addListener(lower_opacity_div, 'click', L.DomEvent.stopPropagation)
            .addListener(lower_opacity_div, 'click', L.DomEvent.preventDefault)
            .addListener(lower_opacity_div, 'click', function () { onClickLowerOpacity() });

        return lower_opacity_div;
    }
});

//Create a jquery-ui slider with values from 0 to 100. Match the opacity value to the slider value divided by 100.
L.Control.opacitySlider = L.Control.extend({
    options: {
        position: 'topright'
    },
    setOpacityLayer: function (layer) {
            opacity_layer = layer;
    },
    onAdd: function (map) {

        var opacity_slider_div = L.DomUtil.create('div', 'opacity_slider_control');

        $(function() {
            $( ".opacity_slider_control" ).slider({
              orientation: "vertical",
              range: "min",
              min: 0,
              max: 100,
              value: 60,
              step: 10,
              start: function ( event, ui) {
                //When moving the slider, disable panning.
                map.dragging.disable();
                map.once('mousedown', function (e) {
                    map.dragging.enable();
                });
              },
              slide: function ( event, ui ) {

                var slider_value = ui.value / 100;
                opacity_layer.setOpacity(slider_value);

              }
            });

        });

        return opacity_slider_div;
    }
});

function onClickHigherOpacity() {
    var opacity_value = opacity_layer.options.opacity;

    if (opacity_value > 1) {
        return;
    } else {
        opacity_layer.setOpacity(opacity_value + 0.2);
        //When you double-click on the control, do not zoom.
        map.doubleClickZoom.disable();
        map.once('click', function (e) {
            map.doubleClickZoom.enable();
        });
    }

}

function onClickLowerOpacity() {
    var opacity_value = opacity_layer.options.opacity;

    if (opacity_value < 0) {
        return;
    } else {
        opacity_layer.setOpacity(opacity_value - 0.2);
        //When you double-click on the control, do not zoom.
        map.doubleClickZoom.disable();
        map.once('click', function (e) {
            map.doubleClickZoom.enable();
        });
    }

}

<commit_msg>Bug fix: Not working if control added after doc ready.<commit_after>/*
        Leaflet.OpacityControls, a plugin for adjusting the opacity of a Leaflet map.
        (c) 2013, Jared Dominguez
        (c) 2013, LizardTech

        https://github.com/lizardtechblog/Leaflet.OpacityControls
*/

//Declare global variables
var opacity_layer;

//Create a control to increase the opacity value. This makes the image more opaque.
L.Control.higherOpacity = L.Control.extend({
    options: {
        position: 'topright'
    },
    setOpacityLayer: function (layer) {
            opacity_layer = layer;
    },
    onAdd: function () {

        var higher_opacity_div = L.DomUtil.create('div', 'higher_opacity_control');

        L.DomEvent.addListener(higher_opacity_div, 'click', L.DomEvent.stopPropagation)
            .addListener(higher_opacity_div, 'click', L.DomEvent.preventDefault)
            .addListener(higher_opacity_div, 'click', function () { onClickHigherOpacity() });

        return higher_opacity_div;
    }
});

//Create a control to decrease the opacity value. This makes the image more transparent.
L.Control.lowerOpacity = L.Control.extend({
    options: {
        position: 'topright'
    },
    setOpacityLayer: function (layer) {
            opacity_layer = layer;
    },
    onAdd: function (map) {

        var lower_opacity_div = L.DomUtil.create('div', 'lower_opacity_control');

        L.DomEvent.addListener(lower_opacity_div, 'click', L.DomEvent.stopPropagation)
            .addListener(lower_opacity_div, 'click', L.DomEvent.preventDefault)
            .addListener(lower_opacity_div, 'click', function () { onClickLowerOpacity() });

        return lower_opacity_div;
    }
});

//Create a jquery-ui slider with values from 0 to 100. Match the opacity value to the slider value divided by 100.
L.Control.opacitySlider = L.Control.extend({
    options: {
        position: 'topright'
    },
    setOpacityLayer: function (layer) {
            opacity_layer = layer;
    },
    onAdd: function (map) {
        var opacity_slider_div = L.DomUtil.create('div', 'opacity_slider_control');

        $(opacity_slider_div).slider({
          orientation: "vertical",
          range: "min",
          min: 0,
          max: 100,
          value: 60,
          step: 10,
          start: function ( event, ui) {
            //When moving the slider, disable panning.
            map.dragging.disable();
            map.once('mousedown', function (e) {
              map.dragging.enable();
            });
          },
          slide: function ( event, ui ) {
            var slider_value = ui.value / 100;
            opacity_layer.setOpacity(slider_value);
          }
        });

        return opacity_slider_div;
    }
});

function onClickHigherOpacity() {
    var opacity_value = opacity_layer.options.opacity;

    if (opacity_value > 1) {
        return;
    } else {
        opacity_layer.setOpacity(opacity_value + 0.2);
        //When you double-click on the control, do not zoom.
        map.doubleClickZoom.disable();
        map.once('click', function (e) {
            map.doubleClickZoom.enable();
        });
    }

}

function onClickLowerOpacity() {
    var opacity_value = opacity_layer.options.opacity;

    if (opacity_value < 0) {
        return;
    } else {
        opacity_layer.setOpacity(opacity_value - 0.2);
        //When you double-click on the control, do not zoom.
        map.doubleClickZoom.disable();
        map.once('click', function (e) {
            map.doubleClickZoom.enable();
        });
    }

}

<|endoftext|>


<commit_before>var BaseOverviewsWidget = require('./base');
var BaseDataview = require('../histogram');

function Histogram(query, options, queryRewriter, queryRewriteData, params) {
    BaseOverviewsWidget.call(this, query, options, BaseDataview, queryRewriter, queryRewriteData, params);
}

Histogram.prototype = Object.create(BaseOverviewsWidget.prototype);
Histogram.prototype.constructor = Histogram;

module.exports = Histogram;
<commit_msg>Implement overviews histogram dataviews<commit_after>var _ = require('underscore');
var BaseOverviewsWidget = require('./base');
var BaseDataview = require('../histogram');

var debug = require('debug')('windshaft:dataview:ovhistogram');

var dot = require('dot');
dot.templateSettings.strip = false;

var columnTypeQueryTpl = dot.template(
    'SELECT pg_typeof({{=it.column}})::oid FROM ({{=it.query}}) _cdb_histogram_column_type limit 1'
);
var columnCastTpl = dot.template("date_part('epoch', {{=it.column}})");

var BIN_MIN_NUMBER = 6;
var BIN_MAX_NUMBER = 48;

var basicsQueryTpl = dot.template([
    'basics AS (',
    '  SELECT',
    '    max({{=it._column}}) AS max_val, min({{=it._column}}) AS min_val,',
    '    sum({{=it._column}}*_feature_count)/sum(_feature_count) AS avg_val, sum(_feature_count) AS total_rows',
    '  FROM ({{=it._query}}) _cdb_basics',
    ')'
].join(' \n'));

var overrideBasicsQueryTpl = dot.template([
    'basics AS (',
    '  SELECT',
    '    max({{=it._end}}) AS max_val, min({{=it._start}}) AS min_val,',
    '    sum({{=it._column}}*_feature_count)/sum(_feature_count) AS avg_val, sum(_feature_count) AS total_rows',
    '  FROM ({{=it._query}}) _cdb_basics',
    ')'
].join('\n'));

var iqrQueryTpl = dot.template([
    'iqrange AS (',
    '  SELECT max(quartile_max) - min(quartile_max) AS iqr',
    '  FROM (',
    '    SELECT quartile, max(_cdb_iqr_column) AS quartile_max from (',
    '      SELECT {{=it._column}} AS _cdb_iqr_column, ntile(4) over (order by {{=it._column}}',
    '    ) AS quartile',
    '    FROM ({{=it._query}}) _cdb_rank) _cdb_quartiles',
    '    WHERE quartile = 1 or quartile = 3',
    '    GROUP BY quartile',
    '  ) _cdb_iqr',
    ')'
].join('\n'));

var binsQueryTpl = dot.template([
    'bins AS (',
    '  SELECT CASE WHEN total_rows = 0 OR iqr = 0',
    '      THEN 1',
    '      ELSE GREATEST(',
    '        LEAST({{=it._minBins}}, CAST(total_rows AS INT)),',
    '        LEAST(',
    '          CAST(((max_val - min_val) / (2 * iqr * power(total_rows, 1/3))) AS INT),',
    '          {{=it._maxBins}}',
    '        )',
    '      )',
    '    END AS bins_number',
    '  FROM basics, iqrange, ({{=it._query}}) _cdb_bins',
    '  LIMIT 1',
    ')'
].join('\n'));

var overrideBinsQueryTpl = dot.template([
    'bins AS (',
    '  SELECT {{=it._bins}} AS bins_number',
    ')'
].join('\n'));

var nullsQueryTpl = dot.template([
    'nulls AS (',
    '  SELECT',
    '  count(*) AS nulls_count',
    '  FROM ({{=it._query}}) _cdb_histogram_nulls',
    '  WHERE {{=it._column}} IS NULL',
    ')'
].join('\n'));

var histogramQueryTpl = dot.template([
    'SELECT',
    '    (max_val - min_val) / cast(bins_number as float) AS bin_width,',
    '    bins_number,',
    '    nulls_count,',
    '    avg_val,',
    '    CASE WHEN min_val = max_val',
    '      THEN 0',
    '      ELSE GREATEST(1, LEAST(WIDTH_BUCKET({{=it._column}}, min_val, max_val, bins_number), bins_number)) - 1',
    '    END AS bin,',
    '    min({{=it._column}})::numeric AS min,',
    '    max({{=it._column}})::numeric AS max,',
    '    sum({{=it._column}}*_feature_count)/sum(_feature_count)::numeric AS avg,',
    '    sum(_feature_count) AS freq',
    'FROM ({{=it._query}}) _cdb_histogram, basics, nulls, bins',
    'WHERE {{=it._column}} IS NOT NULL',
    'GROUP BY bin, bins_number, bin_width, nulls_count, avg_val',
    'ORDER BY bin'
].join('\n'));

function Histogram(query, options, queryRewriter, queryRewriteData, params) {
    BaseOverviewsWidget.call(this, query, options, BaseDataview, queryRewriter, queryRewriteData, params);

    this.query = query;
    this.column = options.column;
    this.bins = options.bins;

    this._columnType = null;
}

Histogram.prototype = Object.create(BaseOverviewsWidget.prototype);
Histogram.prototype.constructor = Histogram;

module.exports = Histogram;

var DATE_OIDS = {
    1082: true,
    1114: true,
    1184: true
};

Histogram.prototype.sql = function(psql, override, callback) {
    if (!callback) {
        callback = override;
        override = {};
    }

    var self = this;

    var _column = this.column;

    var columnTypeQuery = columnTypeQueryTpl({
        column: _column, query: this.rewrittenQuery(this.query)
    });

    if (this._columnType === null) {
        psql.query(columnTypeQuery, function(err, result) {
            // assume numeric, will fail later
            self._columnType = 'numeric';
            if (!err && !!result.rows[0]) {
                var pgType = result.rows[0].pg_typeof;
                if (DATE_OIDS.hasOwnProperty(pgType)) {
                    self._columnType = 'date';
                }
            }
            self.sql(psql, override, callback);
        }, true); // use read-only transaction
        return null;
    }

    if (this._columnType === 'date') {
        _column = columnCastTpl({column: _column});
    }

    var _query = this.rewrittenQuery(this.query);

    var basicsQuery, binsQuery;

    if (override && _.has(override, 'start') && _.has(override, 'end') && _.has(override, 'bins')) {
        debug('overriding with %j', override);
        basicsQuery = overrideBasicsQueryTpl({
            _query: _query,
            _column: _column,
            _start: override.start,
            _end: override.end
        });

        binsQuery = [
            overrideBinsQueryTpl({
                _bins: override.bins
            })
        ].join(',\n');
    } else {
        basicsQuery = basicsQueryTpl({
            _query: _query,
            _column: _column
        });

        if (override && _.has(override, 'bins')) {
            binsQuery = [
                overrideBinsQueryTpl({
                    _bins: override.bins
                })
            ].join(',\n');
        } else {
            binsQuery = [
                iqrQueryTpl({
                    _query: _query,
                    _column: _column
                }),
                binsQueryTpl({
                    _query: _query,
                    _minBins: BIN_MIN_NUMBER,
                    _maxBins: BIN_MAX_NUMBER
                })
            ].join(',\n');
        }
    }

    var histogramSql = [
        "WITH",
        [
            basicsQuery,
            binsQuery,
            nullsQueryTpl({
                _query: _query,
                _column: _column
            })
        ].join(',\n'),
        histogramQueryTpl({
            _query: _query,
            _column: _column
        })
    ].join('\n');

    debug(histogramSql);

    return callback(null, histogramSql);
};
<|endoftext|>


<commit_before>/*jslint forin:true sub:true anon:true, sloppy:true, stupid:true nomen:true, node:true continue:true*/

/*
 * Copyright (c) 2012, Yahoo! Inc. All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */
var log4js = require("log4js");
var SessionFactory = require("./sessionfactory");
var ReportManager = require("../util/reportmanager");
var FileUtil = require("../util/fileutil");
var WdSession = require("../session/wdsession");
var TestSession = require("../session/testsession");
var ProxyManager = require("../proxy/proxymanager");
var clone = require('clone');
var path = require("path");
var os = require("os");
var fs = require("fs");
var async = require("async");

var sf;
var testExecutor;
var curSessionCount;
var totalSessionCount;
var wdSessions;
var parallelCount;
var tests;
var testQueues;

function TestExecutor(sessionFactory) {

    sf = sessionFactory;

    this.logger = log4js.getLogger("TestExecutor");
    testExecutor = this;
    tests = [];
    wdSessions = [];
    testQueues = [];
    curSessionCount = 0;
    totalSessionCount = 0;
    parallelCount = 0;

}

TestExecutor.prototype.writeReportForDescriptor = function(testSession, callback) {

    var descriptor,
        testSessionsArr,
        currTime,
        reportObj,
        reportManager;

    for (descriptor in sf.descriptorObj) {
        if (descriptor === testSession.descriptorPath) {
            // Store testSessions array for each descriptor in testSessionMap
            if (sf.testSessionMap[descriptor]) {
                testSessionsArr = sf.testSessionMap[descriptor];
            } else {
                testSessionsArr = [];
            }
            testSessionsArr.push(testSession);

            sf.testSessionMap[descriptor] = testSessionsArr;

            sf.descriptorObj[descriptor].testSessionCount -= 1;
            if (sf.descriptorObj[descriptor].testSessionCount === 0) {

                sf.timeReportObj[testSession.descriptorPath].endTime = Date.now(); // TODO Is endTime required ???
                sf.timeReportObj[testSession.descriptorPath].timeTaken =
                    ((sf.timeReportObj[testSession.descriptorPath].endTime - sf.timeReportObj[testSession.descriptorPath].startTime) / 1000).toFixed(2);

                testExecutor.logger.info('Time taken to run descriptor-' + testSession.descriptorPath + ' = ' + sf.timeReportObj[testSession.descriptorPath].timeTaken);

                testExecutor.logger.info('All tests over for descriptor:' + testSession.descriptorPath);
                reportObj = {
                    "reportFolder" : global.reportFolder,
                    "arrTestSessions" : sf.testSessionMap[descriptor],
                    "descriptor" : testSession.descriptorPath,
                    "reuseSession" : sf.reuseSession,
                    "testSuiteName" : sf.descriptorObj[descriptor].testSuiteName,
                    "driver" : sf.driver,
                    "browser" : sf.browser,
                    "group" : sf.args.group,
                    "testName" : sf.args.testName

                };
                reportManager = new ReportManager(reportObj);
                reportManager.totalTimeTaken = sf.timeReportObj[testSession.descriptorPath].timeTaken;
                reportManager.writeReports();

            }

        }
    }
    callback();
};

TestExecutor.prototype.startProxy = function(proxyConfigPath, callback) {

    //TODO - move this to index.js
    if (os.type() === "Darwin") {
        global.hostname = "localhost";
    } else {
        global.hostname = os.hostname();
    }

    testExecutor.logger.info('Starting proxy server : ' + proxyConfigPath);

    var proxyManager = new ProxyManager(path.resolve(global.workingDirectory, proxyConfigPath),sf.config);

    proxyManager.runRouterProxy(sf.config.minPort, sf.config.maxPort, global.hostname, function(proxyHost) {

        if (proxyHost) {
            if (proxyHost.indexOf("Error") === -1) {
                testExecutor.logger.info("Running Proxy Server at " + proxyHost + ' for :::' + proxyConfigPath);
                global.routerMap[proxyConfigPath] = proxyHost;
            } else {
                testExecutor.logger.info("Unable to Start Proxy, " + proxyHost);
                testExecutor.logger.info("Running Tests Without Proxy! ");
            }
        } else {
            testExecutor.logger.info("Some error while starting proxy");
            //TODO - What message to show here??
        }

    });

    setTimeout(callback, 500);

};

TestExecutor.prototype.runNextTest = function(testQueue) {

    var testSession,
        testSessionTimeArr = [];

    if (testQueue.curIndex === testQueue.sessions.length) {
        return; // all done with this queue
    }
    testSession = testQueue.sessions[testQueue.curIndex];

//    var thisSession = testQueue.sessions[testQueue.curIndex];

    testQueue.curIndex += 1;
    // If first test session is starting for the descriptor, note start time
    if (!sf.timeReportObj[testSession.descriptorPath]) {
        sf.timeReportObj[testSession.descriptorPath] = [];
        sf.timeReportObj[testSession.descriptorPath].startTime = Date.now();
    }

    console.log('\n*****Running test :' + testSession.descriptorPath + ' - ' + testSession.args.testName);

    testSession.runTest(function (error) {

        if (error) {
            var obj = {};
            obj.error = error;
            console.log('\n*****Adding error for test :' + testSession.descriptorPath + ' - ' + testSession.args.testName);
            testSession.driver.reports.addReport(obj);
//            testExecutor.logger.debug("Error - Callback of runTest : " + error);
            testExecutor.logger.debug("Obj - Callback of runTest : " + JSON.stringify(obj));
        }

        testExecutor.logger.trace("Run Test :" + curSessionCount + "==" + totalSessionCount);
        testSession.endTime = Date.now();

        // Write report per descriptor ( if all testsessions for the descriptor ( to which the current test session belongs ) are run )

        if (sf.timeReportObj[this.descriptorPath].testSessionTimeArr) {
            testSessionTimeArr = sf.timeReportObj[this.descriptorPath].testSessionTimeArr;
        } else {
            testSessionTimeArr = {};
        }

        testSessionTimeArr[testSession.args.testName] = {};

        testSessionTimeArr[testSession.args.testName].timeTaken = ((testSession.endTime - this.startTime) / 1000).toFixed(2);
        sf.timeReportObj[testSession.descriptorPath].testSessionTimeArr = testSessionTimeArr;

        testExecutor.logger.info('Time taken to run - ' + testSession.descriptorPath + '-' + testSession.args.testName + ' is::' +
            testSessionTimeArr[testSession.args.testName].timeTaken);

        testExecutor.writeReportForDescriptor(testSession, function() {
            curSessionCount += 1;
            if (curSessionCount === totalSessionCount) {
                testExecutor.logger.trace("Done with all the sessions");
                sf.tearDown(testQueue, wdSessions);
            } else {
                testExecutor.logger.trace("Calling Next Test : " + curSessionCount);
                console.log('\n\n');
                testExecutor.runNextTest(testQueue);
            }
        });

    });
};

TestExecutor.prototype.runTests = function(testQueues, parallelCount) {
    var i, j;
    for (i = 0; i < testQueues.length; i += 1) {
        // start running as many sessions as we can in parallel as specified
        for (j = 0; j < parallelCount; j += 1) {
            testExecutor.runNextTest(testQueues[i]);
        }
    }

};

TestExecutor.prototype.setupTestQueues = function(callback) {

    var test,
        browsers,
        i,
        j;

    // there may be more than one independent queue that can always run in parallel
    if (wdSessions.length > 0) {

        parallelCount = 1; // when reusing sessions, items in a single queue cannot run in parallel
        // every wd session gets its own queue
        for (i = 0; i < wdSessions.length; i += 1) {
            testQueues[i] = {curIndex: 0, sessions: []};
            for (j = 0; j < tests.length; j += 1) {
                test = clone(tests[j]);

                // If proxy set to true or reuseSession set to false , ignore reuseSession
                if (test.startProxyServer === true || test.reuseSession === false) {
                    testQueues[i].sessions.push(new TestSession(sf.config, test));
                } else {
                    testQueues[i].sessions.push(new TestSession(sf.config, test, wdSessions[i]));
                }

            }
            totalSessionCount += tests.length;
        }
    } else {
        // when not reusing sessions, a single queue contains all the items
        // parallelism is controlled by the "parallel" argument passed by the user
        testQueues[0] = {curIndex: 0, sessions: []};
        for (i = 0; i < tests.length; i += 1) {
            browsers = sf.getBrowsers(tests[i]);
            for (j = 0; j < browsers.length; j += 1) {
                test = clone(tests[i]);
                test.browser = browsers[j];
                testQueues[0].sessions.push(new TestSession(sf.config, test));
            }
            totalSessionCount += browsers.length;
            // If more than one browsers, double the length
            if (browsers.length > 1) {

                if (sf.descriptorObj[test.descriptorPath]) {
                    sf.descriptorObj[test.descriptorPath].testSessionCount = sf.descriptorObj[test.descriptorPath].testSessionCount * browsers.length;
                }
            }

        }
    }
    testExecutor.logger.info("Total test sessions: " + totalSessionCount);
    callback();

};

TestExecutor.prototype.getTests = function(callback) {

    var testParams,
        test,
        i;

    if (sf.arrDescriptor) {

        tests = sf.getFactoryTests();
        if (tests.length === 0) {
            sf.tearDown({}, null);
        }
    } else if (sf.tests) {
        for (i = 0; i < sf.tests.length; i += 1) {
            testParams = clone(sf.args);
            testParams.test = sf.tests[i];
            // convert the cmd line test to look like a descriptor test
            test = {
                config : {},
                params : testParams,
                testName : "Default",
                driver : sf.args.driver,
                controller : sf.args.controller,
                browser : sf.browser
            };
            tests.push(test);
        }
    } else {
        // convert the cmd line test to look like a descriptor test
        test = {
            config: {},
            params : sf.args,
            testName : "Default",
            driver : sf.args.driver,
            controller : sf.args.controller,
            browser : sf.browser
        };
        test.params.lib = sf.args.lib;
        tests.push(test);
    }

    callback();

};

TestExecutor.prototype.populateProxyConfigList = function(callback) {

    var i,
        proxyConfig;

    // Get how many unique proxy servers we need to start
    for (i = 0; i < tests.length; i += 1) {

        proxyConfig = undefined;

        if (tests[i].startProxyServer === false) {
            continue;
        }

        // If test has routerProxyConfig
        if (tests[i].proxyConfig) {

            proxyConfig = tests[i].proxyConfig;

            if (tests[i].relativePath) {
                proxyConfig = path.resolve(global.workingDirectory, tests[i].relativePath, proxyConfig);
            } else {
                proxyConfig = path.resolve(global.workingDirectory, proxyConfig);
            }

        } else if (sf.args.routerProxyConfig) { // If proxyConfig is passed as an argument
            proxyConfig = path.resolve(global.workingDirectory, sf.args.routerProxyConfig);
        }

        if (proxyConfig) {

            tests[i].resolvedProxyConfigPath = proxyConfig;
            // Add routerConfig to the list ,if not already added
            if (sf.proxyConfigList.indexOf(proxyConfig) === -1) {
                sf.proxyConfigList.push(proxyConfig);
            }
        }
    }
    callback();

};

TestExecutor.prototype.setupProxy = function(callback) {

    // If set from command line
    if (sf.args.startProxyServer === true || sf.args.startProxyServer === undefined) {

        testExecutor.populateProxyConfigList(function () {

            if (sf.proxyConfigList && sf.proxyConfigList.length > 0) {

                testExecutor.logger.info('Number of Proxy servers needed to start:' + sf.proxyConfigList.length);

                async.eachSeries(sf.proxyConfigList, testExecutor.startProxy, function(err) {

                    if (err) {
                        testExecutor.logger.info('ERROR !! Failed to start proxy servers..');
                    } else {
                        testExecutor.logger.info('Started all proxy servers..Now running tests\n\n');
                    }
                    callback();

                });

            } else {
                callback();
            }
        });

    } else {
        callback();
    }

};

TestExecutor.prototype.startTest = function() {

    testExecutor.getTests(function() {
        parallelCount = parseInt(sf.parallel, 10);
        if (isNaN(parallelCount) || (parallelCount <= 0)) {
            parallelCount = 1;
        }
        testExecutor.setupProxy(function() {
            testExecutor.setupTestQueues(function() {
                testExecutor.runTests(testQueues, parallelCount);
            });
        });

    });

};

TestExecutor.prototype.executeTests = function () {
    var hub;

    // get all wd sessions if applicable (based on reuseSession flag)
    if (sf.reuseSession) {
        hub = new WdSession(sf.config);
        hub.getSessions(sf, function (error, sf, arrSessions) {
            if (error) {
                // logger.error('No sessions found..'); TODO  search for this msg
                process.exit(1);
            }
            wdSessions = arrSessions;
            testExecutor.startTest();
        });
    } else {
        testExecutor.startTest();
    }

};

module.exports = TestExecutor;<commit_msg>Fixing console statements<commit_after>/*jslint forin:true sub:true anon:true, sloppy:true, stupid:true nomen:true, node:true continue:true*/

/*
 * Copyright (c) 2012, Yahoo! Inc. All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */
var log4js = require("log4js");
var SessionFactory = require("./sessionfactory");
var ReportManager = require("../util/reportmanager");
var FileUtil = require("../util/fileutil");
var WdSession = require("../session/wdsession");
var TestSession = require("../session/testsession");
var ProxyManager = require("../proxy/proxymanager");
var clone = require('clone');
var path = require("path");
var os = require("os");
var fs = require("fs");
var async = require("async");

var sf;
var testExecutor;
var curSessionCount;
var totalSessionCount;
var wdSessions;
var parallelCount;
var tests;
var testQueues;

function TestExecutor(sessionFactory) {

    sf = sessionFactory;

    this.logger = log4js.getLogger("TestExecutor");
    testExecutor = this;
    tests = [];
    wdSessions = [];
    testQueues = [];
    curSessionCount = 0;
    totalSessionCount = 0;
    parallelCount = 0;

}

TestExecutor.prototype.writeReportForDescriptor = function(testSession, callback) {

    var descriptor,
        testSessionsArr,
        currTime,
        reportObj,
        reportManager;

    for (descriptor in sf.descriptorObj) {
        if (descriptor === testSession.descriptorPath) {
            // Store testSessions array for each descriptor in testSessionMap
            if (sf.testSessionMap[descriptor]) {
                testSessionsArr = sf.testSessionMap[descriptor];
            } else {
                testSessionsArr = [];
            }
            testSessionsArr.push(testSession);

            sf.testSessionMap[descriptor] = testSessionsArr;

            sf.descriptorObj[descriptor].testSessionCount -= 1;
            if (sf.descriptorObj[descriptor].testSessionCount === 0) {

                sf.timeReportObj[testSession.descriptorPath].endTime = Date.now(); // TODO Is endTime required ???
                sf.timeReportObj[testSession.descriptorPath].timeTaken =
                    ((sf.timeReportObj[testSession.descriptorPath].endTime - sf.timeReportObj[testSession.descriptorPath].startTime) / 1000).toFixed(2);

                testExecutor.logger.info('Time taken to run descriptor-' + testSession.descriptorPath + ' = ' + sf.timeReportObj[testSession.descriptorPath].timeTaken);

                testExecutor.logger.info('All tests over for descriptor:' + testSession.descriptorPath);
                reportObj = {
                    "reportFolder" : global.reportFolder,
                    "arrTestSessions" : sf.testSessionMap[descriptor],
                    "descriptor" : testSession.descriptorPath,
                    "reuseSession" : sf.reuseSession,
                    "testSuiteName" : sf.descriptorObj[descriptor].testSuiteName,
                    "driver" : sf.driver,
                    "browser" : sf.browser,
                    "group" : sf.args.group,
                    "testName" : sf.args.testName

                };
                reportManager = new ReportManager(reportObj);
                reportManager.totalTimeTaken = sf.timeReportObj[testSession.descriptorPath].timeTaken;
                reportManager.writeReports();

            }

        }
    }
    callback();
};

TestExecutor.prototype.startProxy = function(proxyConfigPath, callback) {

    //TODO - move this to index.js
    if (os.type() === "Darwin") {
        global.hostname = "localhost";
    } else {
        global.hostname = os.hostname();
    }

    testExecutor.logger.info('Starting proxy server : ' + proxyConfigPath);

    var proxyManager = new ProxyManager(path.resolve(global.workingDirectory, proxyConfigPath),sf.config);

    proxyManager.runRouterProxy(sf.config.minPort, sf.config.maxPort, global.hostname, function(proxyHost) {

        if (proxyHost) {
            if (proxyHost.indexOf("Error") === -1) {
                testExecutor.logger.info("Running Proxy Server at " + proxyHost + ' for :::' + proxyConfigPath);
                global.routerMap[proxyConfigPath] = proxyHost;
            } else {
                testExecutor.logger.info("Unable to Start Proxy, " + proxyHost);
                testExecutor.logger.info("Running Tests Without Proxy! ");
            }
        } else {
            testExecutor.logger.info("Some error while starting proxy");
            //TODO - What message to show here??
        }

    });

    setTimeout(callback, 500);

};

TestExecutor.prototype.runNextTest = function(testQueue) {

    var testSession,
        testSessionTimeArr = [];

    if (testQueue.curIndex === testQueue.sessions.length) {
        return; // all done with this queue
    }
    testSession = testQueue.sessions[testQueue.curIndex];

//    var thisSession = testQueue.sessions[testQueue.curIndex];

    testQueue.curIndex += 1;
    // If first test session is starting for the descriptor, note start time
    if (!sf.timeReportObj[testSession.descriptorPath]) {
        sf.timeReportObj[testSession.descriptorPath] = [];
        sf.timeReportObj[testSession.descriptorPath].startTime = Date.now();
    }

    console.log('\n*****Running test :' + testSession.descriptorPath + ' - ' + testSession.args.testName);

    var self = testSession;
    testSession.runTest(function (error) {

        if (error) {
            var obj = {};
            obj.error = error;
            console.log('\n*****Adding error for test :' + self.descriptorPath + ' - ' + self.args.testName);
            self.driver.reports.addReport(obj);
//            testExecutor.logger.debug("Error - Callback of runTest : " + error);
            testExecutor.logger.debug("Obj - Callback of runTest : " + JSON.stringify(obj));
        }

        testExecutor.logger.trace("Run Test :" + curSessionCount + "==" + totalSessionCount);
        testSession.endTime = Date.now();

        // Write report per descriptor ( if all testsessions for the descriptor ( to which the current test session belongs ) are run )

        if (sf.timeReportObj[self.descriptorPath].testSessionTimeArr) {
            testSessionTimeArr = sf.timeReportObj[self.descriptorPath].testSessionTimeArr;
        } else {
            testSessionTimeArr = {};
        }

        testSessionTimeArr[self.args.testName] = {};

        testSessionTimeArr[self.args.testName].timeTaken = ((self.endTime - self.startTime) / 1000).toFixed(2);
        sf.timeReportObj[self.descriptorPath].testSessionTimeArr = testSessionTimeArr;

        testExecutor.logger.info('Time taken to run - ' + self.descriptorPath + '-' + self.args.testName + ' is::' +
            testSessionTimeArr[self.args.testName].timeTaken);

        testExecutor.writeReportForDescriptor(self, function() {
            curSessionCount += 1;
            if (curSessionCount === totalSessionCount) {
                testExecutor.logger.trace("Done with all the sessions");
                sf.tearDown(testQueue, wdSessions);
            } else {
                testExecutor.logger.trace("Calling Next Test : " + curSessionCount);
                console.log('\n\n');
                testExecutor.runNextTest(testQueue);
            }
        });

    });
};

TestExecutor.prototype.runTests = function(testQueues, parallelCount) {
    var i, j;
    for (i = 0; i < testQueues.length; i += 1) {
        // start running as many sessions as we can in parallel as specified
        for (j = 0; j < parallelCount; j += 1) {
            testExecutor.runNextTest(testQueues[i]);
        }
    }

};

TestExecutor.prototype.setupTestQueues = function(callback) {

    var test,
        browsers,
        i,
        j;

    // there may be more than one independent queue that can always run in parallel
    if (wdSessions.length > 0) {

        parallelCount = 1; // when reusing sessions, items in a single queue cannot run in parallel
        // every wd session gets its own queue
        for (i = 0; i < wdSessions.length; i += 1) {
            testQueues[i] = {curIndex: 0, sessions: []};
            for (j = 0; j < tests.length; j += 1) {
                test = clone(tests[j]);

                // If proxy set to true or reuseSession set to false , ignore reuseSession
                if (test.startProxyServer === true || test.reuseSession === false) {
                    testQueues[i].sessions.push(new TestSession(sf.config, test));
                } else {
                    testQueues[i].sessions.push(new TestSession(sf.config, test, wdSessions[i]));
                }

            }
            totalSessionCount += tests.length;
        }
    } else {
        // when not reusing sessions, a single queue contains all the items
        // parallelism is controlled by the "parallel" argument passed by the user
        testQueues[0] = {curIndex: 0, sessions: []};
        for (i = 0; i < tests.length; i += 1) {
            browsers = sf.getBrowsers(tests[i]);
            for (j = 0; j < browsers.length; j += 1) {
                test = clone(tests[i]);
                test.browser = browsers[j];
                testQueues[0].sessions.push(new TestSession(sf.config, test));
            }
            totalSessionCount += browsers.length;
            // If more than one browsers, double the length
            if (browsers.length > 1) {

                if (sf.descriptorObj[test.descriptorPath]) {
                    sf.descriptorObj[test.descriptorPath].testSessionCount = sf.descriptorObj[test.descriptorPath].testSessionCount * browsers.length;
                }
            }

        }
    }
    testExecutor.logger.info("Total test sessions: " + totalSessionCount);
    callback();

};

TestExecutor.prototype.getTests = function(callback) {

    var testParams,
        test,
        i;

    if (sf.arrDescriptor) {

        tests = sf.getFactoryTests();
        if (tests.length === 0) {
            sf.tearDown({}, null);
        }
    } else if (sf.tests) {
        for (i = 0; i < sf.tests.length; i += 1) {
            testParams = clone(sf.args);
            testParams.test = sf.tests[i];
            // convert the cmd line test to look like a descriptor test
            test = {
                config : {},
                params : testParams,
                testName : "Default",
                driver : sf.args.driver,
                controller : sf.args.controller,
                browser : sf.browser
            };
            tests.push(test);
        }
    } else {
        // convert the cmd line test to look like a descriptor test
        test = {
            config: {},
            params : sf.args,
            testName : "Default",
            driver : sf.args.driver,
            controller : sf.args.controller,
            browser : sf.browser
        };
        test.params.lib = sf.args.lib;
        tests.push(test);
    }

    callback();

};

TestExecutor.prototype.populateProxyConfigList = function(callback) {

    var i,
        proxyConfig;

    // Get how many unique proxy servers we need to start
    for (i = 0; i < tests.length; i += 1) {

        proxyConfig = undefined;

        if (tests[i].startProxyServer === false) {
            continue;
        }

        // If test has routerProxyConfig
        if (tests[i].proxyConfig) {

            proxyConfig = tests[i].proxyConfig;

            if (tests[i].relativePath) {
                proxyConfig = path.resolve(global.workingDirectory, tests[i].relativePath, proxyConfig);
            } else {
                proxyConfig = path.resolve(global.workingDirectory, proxyConfig);
            }

        } else if (sf.args.routerProxyConfig) { // If proxyConfig is passed as an argument
            proxyConfig = path.resolve(global.workingDirectory, sf.args.routerProxyConfig);
        }

        if (proxyConfig) {

            tests[i].resolvedProxyConfigPath = proxyConfig;
            // Add routerConfig to the list ,if not already added
            if (sf.proxyConfigList.indexOf(proxyConfig) === -1) {
                sf.proxyConfigList.push(proxyConfig);
            }
        }
    }
    callback();

};

TestExecutor.prototype.setupProxy = function(callback) {

    // If set from command line
    if (sf.args.startProxyServer === true || sf.args.startProxyServer === undefined) {

        testExecutor.populateProxyConfigList(function () {

            if (sf.proxyConfigList && sf.proxyConfigList.length > 0) {

                testExecutor.logger.info('Number of Proxy servers needed to start:' + sf.proxyConfigList.length);

                async.eachSeries(sf.proxyConfigList, testExecutor.startProxy, function(err) {

                    if (err) {
                        testExecutor.logger.info('ERROR !! Failed to start proxy servers..');
                    } else {
                        testExecutor.logger.info('Started all proxy servers..Now running tests\n\n');
                    }
                    callback();

                });

            } else {
                callback();
            }
        });

    } else {
        callback();
    }

};

TestExecutor.prototype.startTest = function() {

    testExecutor.getTests(function() {
        parallelCount = parseInt(sf.parallel, 10);
        if (isNaN(parallelCount) || (parallelCount <= 0)) {
            parallelCount = 1;
        }
        testExecutor.setupProxy(function() {
            testExecutor.setupTestQueues(function() {
                testExecutor.runTests(testQueues, parallelCount);
            });
        });

    });

};

TestExecutor.prototype.executeTests = function () {
    var hub;

    // get all wd sessions if applicable (based on reuseSession flag)
    if (sf.reuseSession) {
        hub = new WdSession(sf.config);
        hub.getSessions(sf, function (error, sf, arrSessions) {
            if (error) {
                // logger.error('No sessions found..'); TODO  search for this msg
                process.exit(1);
            }
            wdSessions = arrSessions;
            testExecutor.startTest();
        });
    } else {
        testExecutor.startTest();
    }

};

module.exports = TestExecutor;<|endoftext|>