<commit_before>'use strict';
var K8Api = require('kubernetes-client');
var async = require('async');

var path = require('path');
var fs = require('fs');
var exec = require('child_process').exec;
var soajs = require('soajs');
var request = require('request');

var config = require('./config.js');
var folder = config.folder;
delete require.cache[config.profile];
var profile = require(config.profile);
var mongo = new soajs.mongo(profile);

var utilLog = require('util');
var lib = {

    "loadCustomData": function (cb) {
        var dataDir = process.env.SOAJS_DATA_FOLDER;

        fs.exists(path.normalize(dataDir + "/../custom.js"), function (exists) {
            if (!exists) {
                return cb(null);
            }
            else {
                delete require.cache[require.resolve(path.normalize(dataDir + "/../custom.js"))];
                var customData = require(path.normalize(dataDir + "/../custom.js"));
                return cb(customData);
            }
        });
    },

    printProgress: function (message, counter) {
        process.stdout.clearLine();
        process.stdout.write(showTimestamp() + ' - ' + message + ' ' + showDots() + '\r');

        function showDots() {
            var output = '';
            var numOfDots = counter % 5;
            for (var i = 0; i < numOfDots; i++) { output += '.'; }
            return output;
        }

        function showTimestamp() {
            var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
            var now = new Date();
            return '' + now.getDate() + ' ' + months[now.getMonth()] + ' ' + now.getHours() + ':' +
                ((now.getMinutes().toString().length === 2) ? now.getMinutes() : '0' + now.getMinutes()) + ':' +
                ((now.getSeconds().toString().length === 2) ? now.getSeconds() : '0' + now.getSeconds());
        }
    },

    getDeployer: function (deployerConfig, cb) {
        if(!config.kubernetes.certsPath){
	        return cb(new Error('No certificates found for remote machine.'));
        }
        var deployer = {};

        var certsName = {
            "ca": '/ca.pem',
            "cert": '/apiserver.pem',
            "key": '/apiserver-key.pem'
        };
        lib.loadCustomData(function(body){
            if(body.deployment.deployDriver === 'container.kubernetes.local' && process.platform === 'darwin'){
                certsName = {
                    "ca": '/ca.crt',
                    "cert": '/apiserver.crt',
                    "key": '/apiserver.key'
                };
            }

            deployerConfig.ca = fs.readFileSync(config.kubernetes.certsPath + certsName.ca);
            deployerConfig.cert = fs.readFileSync(config.kubernetes.certsPath + certsName.cert);
            deployerConfig.key = fs.readFileSync(config.kubernetes.certsPath + certsName.key);

            deployerConfig.version = 'v1beta1';
            deployer.extensions = new K8Api.Extensions(deployerConfig);

            deployerConfig.version = 'v1';
            deployer.core = new K8Api.Core(deployerConfig);
            return cb(null, deployer);
        });
    },

    getContent: function (type, group, cb) {
        var path = config.services.path.dir + group + '/';
        fs.exists(path, function (exists) {
            if (!exists) {
                utilLog.log('Folder [' + path + '] does not exist, skipping ...');
                return cb(null, true);
            }

            fs.readdir(path, function (error, content) {
                if (error) return cb(error);

                var regex = new RegExp('[a-zA-Z0-9]*\.' + config.services.path.fileType, 'g');
                var loadContent, allContent = [];
                content.forEach(function (oneContent) {
                    if (oneContent.match(regex)) {
                        try {
                            loadContent = require(path + oneContent);
                        }
                        catch (e) {
                            return cb(e);
                        }
                        allContent.push(loadContent);
                    }
                });
                return cb(null, allContent);
            });
        });
    },

    deployGroup: function (type, services, deployer, cb) {
        if (services.length === 0) {
            utilLog.log('No services of type [' + type + '] found, skipping ...');
            return cb(null, true);
        }

        if (type === 'db' && config.mongo.external) {
            utilLog.log('External Mongo deployment detected, data containers will not be deployed ...');
            return cb(null, true);
        }

        async.eachSeries(services, function (oneService, callback) {
            lib.deployService(deployer, oneService, callback);
        }, cb);
    },

    importData: function (mongoInfo, cb) {
        utilLog.log('Importing provision data to:', profile.servers[0].host + ":" + profile.servers[0].port);
        var dataImportFile = __dirname + "/../dataImport/index.js";
        var execString = process.env.NODE_PATH + " " + dataImportFile;
        exec(execString, cb);
    },

    deployService: function (deployer, options, cb) {
        if (options.service) {
            deployer.core.namespaces.services.post({body: options.service}, function (error) {
                if (error) return cb(error);
                return createDeployment();
            });
        }
        else {
            return createDeployment();
        }

        function createDeployment() {
            deployer.extensions.namespaces.deployments.post({body: options.deployment}, function (error, result) {
                if (error) return cb(error);
                lib.registerContainers(deployer, options, cb);
            });
        }
    },

    deleteDeployments: function (deployer, options, cb) {
        deployer.extensions.namespaces.deployments.delete({}, cb);
    },

    deleteKubeServices: function (deployer, options, cb) {
        var filter = { labelSelector: 'soajs.content=true' };
        deployer.core.namespaces.services.get({qs: filter}, function (error, serviceList) {
            if (error) return cb(error);

            async.each(serviceList.items, function (oneService, callback) {
                deployer.core.namespaces.services.delete({ name: oneService.metadata.name }, callback);
            }, cb);
        });
    },

    deletePods: function (deployer, options, cb) {
        //force delete all pods for a better cleanup
        deployer.core.namespaces.pods.delete({}, cb);
    },

    deletePreviousServices: function (deployer, cb) {
    	//todo: need to provide --grace-period=0 using the javascript syntax
        lib.deleteDeployments(deployer, {}, function (error) {
            if (error) return cb(error);

            lib.deleteKubeServices(deployer, {}, function (error) {
                if (error) return cb(error);

                lib.deletePods(deployer, {}, cb);
            });
        });
    },

    getServiceIPs: function (serviceName, deployer, replicaCount, counter, cb) {
        if (typeof (counter) === 'function') {
            cb = counter; //counter wasn't passed as param
            counter = 0;
        }

        deployer.core.namespaces.pods.get({}, function (error, podList) {
            if (error) return cb(error);
            var onePod, ips = [];
            podList.items.forEach(function (onePod) {
                if (onePod.metadata.labels['soajs.service.label'] === serviceName && onePod.status.phase === 'Running') {
                    ips.push({
                        name: onePod.metadata.name,
                        ip: onePod.status.podIP
                    });
                }
            });

            if (ips.length !== replicaCount) {
                //pod containers may not be ready yet
                lib.printProgress('Waiting for ' + serviceName + ' containers to become available', counter++);
                setTimeout(function () {
                    return lib.getServiceIPs(serviceName, deployer, replicaCount, counter, cb);
                }, 1000);
            }
            else {
                utilLog.log(""); //intentional, to force writting a new line.
                return cb(null, ips);
            }
        });
    },

    addMongoInfo: function (services, mongoInfo, cb) {
        var mongoEnv = [];

	    if(config.mongo.prefix && config.mongo.prefix !== ""){
		    mongoEnv.push({name: 'SOAJS_MONGO_PREFIX', value: config.mongo.prefix});
	    }

        if (config.mongo.external) {
            // if (!config.dataLayer.mongo.url || !config.dataLayer.mongo.port) {
            if (!profile.servers[0].host || !profile.servers[0].port) {
                utilLog.log('ERROR: External Mongo information is missing URL or port, make sure SOAJS_MONGO_EXTERNAL_URL and SOAJS_MONGO_EXTERNAL_PORT are set ...');
                return cb('ERROR: missing mongo information');
            }

            mongoEnv.push({ name: 'SOAJS_MONGO_NB', value: '' + profile.servers.length });
	        for(var i = 0; i < profile.servers.length; i++){
		        mongoEnv.push({name: 'SOAJS_MONGO_IP_' + (i + 1), value: profile.servers[i].host});
		        mongoEnv.push({name: 'SOAJS_MONGO_PORT_' + (i + 1), value: '' + profile.servers[i].port});
	        }

            if (profile.credentials && profile.credentials.username && profile.credentials.password) {
                mongoEnv.push({ name: 'SOAJS_MONGO_USERNAME', value: profile.credentials.username });
                mongoEnv.push({ name: 'SOAJS_MONGO_PASSWORD', value: profile.credentials.password });
	            mongoEnv.push({ name: 'SOAJS_MONGO_AUTH_DB', value: profile.URLParam.authSource });
            }

            if(profile.URLParam.ssl){
	            mongoEnv.push({ name: 'SOAJS_MONGO_SSL', value: profile.URLParam.ssl });
            }
        }
        else {
            mongoEnv.push({ name: 'SOAJS_MONGO_NB', value: '1' });
	        mongoEnv.push({ name: 'SOAJS_MONGO_IP_1', value: profile.servers[0].host});
	        mongoEnv.push({ name: 'SOAJS_MONGO_PORT_1', value: '27017'});
        }

        services.forEach(function (oneService) {
            oneService.deployment.spec.template.spec.containers[0].env = oneService.deployment.spec.template.spec.containers[0].env.concat(mongoEnv);
        });

        return cb(null, services);
    },

    registerNode: function (deployer, swarmConfig, cb) {
        deployer.core.nodes.get({}, function (error, nodeList) {
            if (error) return cb(error);

            async.map(nodeList.items, function (oneNode, callback) {
                var record = {
                    recordType: 'node',
                    id: oneNode.metadata.uid,
                    name: oneNode.metadata.name,
                    ip: getIP(oneNode.status.addresses),
                    kubePort: config.kubernetes.machinePort,
                    availability: ((!oneNode.spec.unschedulable) ? 'active' : 'drained'),
                    role: 'manager',
                    resources: {
                        cpuCount: oneNode.status.capacity.cpu,
                        memory: calcMemory(oneNode.status.capacity.memory)
                    },
                    tokens: {}
                };

                return callback(null, record);
            }, function (error, nodeRecords) {
                if (error) return cb(error);

                for (var i = nodeRecords.length; i >= 0; i--) {
                    if (!nodeRecords[i]) {
                        nodeRecords.splice(i, 1);
                    }
                }

                mongo.insert(config.kubernetes.mongoCollection, nodeRecords, cb);
            });
        });

        function calcMemory (memory) {
			var value = memory.substring(0, memory.length - 2);
			var unit = memory.substring(memory.length - 2);

			if (unit === 'Ki') value += '000';
			else if (unit === 'Mi') value += '000000';

			return parseInt(value);
		}

        function getIP (addresses) {
			var ip = '';
			for (var i = 0; i < addresses.length; i++) {
				if (addresses[i].type === 'LegacyHostIP') {
					ip = addresses[i].address;
				}
			}

			return ip;
		}
    },

    configureEnvDeployer: function (cb) {
        var criteria = {role: 'manager'};
        mongo.find('docker', criteria, function (error, managerNodes) {
            if (error) return cb(error);

            async.map(managerNodes, function (oneNode, callback) {
                return callback(null, oneNode.name);
            }, function (error, nodeHostnames) {
                //get environments records
                mongo.find('environment', {}, function (error, envs) {
                    if (error) return cb(error);

                    async.each(envs, function (oneEnv, callback) {
                        var target = oneEnv.deployer.selected.split('.')[2];

                        oneEnv.deployer.container.kubernetes[target].nodes = nodeHostnames;
                        mongo.save('environment', oneEnv, callback);
                    }, cb);
                });
            });
        });
    },

    registerContainers: function (deployer, serviceOptions, cb) {
        var info = {};
        var kubeServiceName = serviceOptions.deployment.metadata.name;
        var serviceGroup, serviceName, serviceEnv;

        if (serviceOptions.deployment.metadata.labels) {
            serviceGroup = serviceOptions.deployment.metadata.labels['soajs.service.group'];
            serviceName = serviceOptions.deployment.metadata.labels['soajs.service'];
            serviceEnv = serviceOptions.deployment.metadata.labels['soajs.env'];
        }

        if (serviceGroup === 'core') {
            info.type = (serviceName === 'controller') ? 'controller' : 'service';
        }
        else if (serviceGroup === 'nginx') {
            info.type = 'nginx';
        }
        else {
            return cb(null, true);
        }

        var replicaCount = serviceOptions.deployment.spec.replicas;

        utilLog.log ('Registering ' + serviceName + ' containers in docker collection ...');

        info.env = serviceEnv;
        info.running = true;
        info.recordType = 'container';

        lib.getServiceIPs(kubeServiceName, deployer, replicaCount, function (error, serviceIPs) {
            if (error) return cb(error);

            async.map(serviceIPs, function (oneServiceInfo, callback) {
                deployer.core.namespaces.pods.get({name: oneServiceInfo.name}, function (error, pod) {
                    if (error) return callback(error);
                    var record = JSON.parse(JSON.stringify(info));
                    record.taskName = oneServiceInfo.name;
                    record.serviceName = kubeServiceName;
                    delete pod.metadata.annotations;
                    record.info = pod;
                    return callback(null, record);
                });
            }, function (error, records) {
                if (error) return cb(error);
                mongo.insert(config.kubernetes.mongoCollection, records, cb);
            });
        });
    },

    closeDbCon: function (cb) {
        mongo.closeDb();
        return cb();
    }
};

module.exports = lib;
<commit_msg>Added extra filter for backward compatibility, kubernetes deployer<commit_after>'use strict';
var K8Api = require('kubernetes-client');
var async = require('async');

var path = require('path');
var fs = require('fs');
var exec = require('child_process').exec;
var soajs = require('soajs');
var request = require('request');

var config = require('./config.js');
var folder = config.folder;
delete require.cache[config.profile];
var profile = require(config.profile);
var mongo = new soajs.mongo(profile);

var utilLog = require('util');
var lib = {

    "loadCustomData": function (cb) {
        var dataDir = process.env.SOAJS_DATA_FOLDER;

        fs.exists(path.normalize(dataDir + "/../custom.js"), function (exists) {
            if (!exists) {
                return cb(null);
            }
            else {
                delete require.cache[require.resolve(path.normalize(dataDir + "/../custom.js"))];
                var customData = require(path.normalize(dataDir + "/../custom.js"));
                return cb(customData);
            }
        });
    },

    printProgress: function (message, counter) {
        process.stdout.clearLine();
        process.stdout.write(showTimestamp() + ' - ' + message + ' ' + showDots() + '\r');

        function showDots() {
            var output = '';
            var numOfDots = counter % 5;
            for (var i = 0; i < numOfDots; i++) { output += '.'; }
            return output;
        }

        function showTimestamp() {
            var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
            var now = new Date();
            return '' + now.getDate() + ' ' + months[now.getMonth()] + ' ' + now.getHours() + ':' +
                ((now.getMinutes().toString().length === 2) ? now.getMinutes() : '0' + now.getMinutes()) + ':' +
                ((now.getSeconds().toString().length === 2) ? now.getSeconds() : '0' + now.getSeconds());
        }
    },

    getDeployer: function (deployerConfig, cb) {
        if(!config.kubernetes.certsPath){
	        return cb(new Error('No certificates found for remote machine.'));
        }
        var deployer = {};

        var certsName = {
            "ca": '/ca.pem',
            "cert": '/apiserver.pem',
            "key": '/apiserver-key.pem'
        };
        lib.loadCustomData(function(body){
            if(body.deployment.deployDriver === 'container.kubernetes.local' && process.platform === 'darwin'){
                certsName = {
                    "ca": '/ca.crt',
                    "cert": '/apiserver.crt',
                    "key": '/apiserver.key'
                };
            }

            deployerConfig.ca = fs.readFileSync(config.kubernetes.certsPath + certsName.ca);
            deployerConfig.cert = fs.readFileSync(config.kubernetes.certsPath + certsName.cert);
            deployerConfig.key = fs.readFileSync(config.kubernetes.certsPath + certsName.key);

            deployerConfig.version = 'v1beta1';
            deployer.extensions = new K8Api.Extensions(deployerConfig);

            deployerConfig.version = 'v1';
            deployer.core = new K8Api.Core(deployerConfig);
            return cb(null, deployer);
        });
    },

    getContent: function (type, group, cb) {
        var path = config.services.path.dir + group + '/';
        fs.exists(path, function (exists) {
            if (!exists) {
                utilLog.log('Folder [' + path + '] does not exist, skipping ...');
                return cb(null, true);
            }

            fs.readdir(path, function (error, content) {
                if (error) return cb(error);

                var regex = new RegExp('[a-zA-Z0-9]*\.' + config.services.path.fileType, 'g');
                var loadContent, allContent = [];
                content.forEach(function (oneContent) {
                    if (oneContent.match(regex)) {
                        try {
                            loadContent = require(path + oneContent);
                        }
                        catch (e) {
                            return cb(e);
                        }
                        allContent.push(loadContent);
                    }
                });
                return cb(null, allContent);
            });
        });
    },

    deployGroup: function (type, services, deployer, cb) {
        if (services.length === 0) {
            utilLog.log('No services of type [' + type + '] found, skipping ...');
            return cb(null, true);
        }

        if (type === 'db' && config.mongo.external) {
            utilLog.log('External Mongo deployment detected, data containers will not be deployed ...');
            return cb(null, true);
        }

        async.eachSeries(services, function (oneService, callback) {
            lib.deployService(deployer, oneService, callback);
        }, cb);
    },

    importData: function (mongoInfo, cb) {
        utilLog.log('Importing provision data to:', profile.servers[0].host + ":" + profile.servers[0].port);
        var dataImportFile = __dirname + "/../dataImport/index.js";
        var execString = process.env.NODE_PATH + " " + dataImportFile;
        exec(execString, cb);
    },

    deployService: function (deployer, options, cb) {
        if (options.service) {
            deployer.core.namespaces.services.post({body: options.service}, function (error) {
                if (error) return cb(error);
                return createDeployment();
            });
        }
        else {
            return createDeployment();
        }

        function createDeployment() {
            deployer.extensions.namespaces.deployments.post({body: options.deployment}, function (error, result) {
                if (error) return cb(error);
                lib.registerContainers(deployer, options, cb);
            });
        }
    },

    deleteDeployments: function (deployer, options, cb) {
        deployer.extensions.namespaces.deployments.delete({}, cb);
    },

    deleteKubeServices: function (deployer, options, cb) {
        var filter = { labelSelector: 'soajs.content=true, type=soajs-service' }; //type=soajs-service is kept for backward compatibility
        deployer.core.namespaces.services.get({qs: filter}, function (error, serviceList) {
            if (error) return cb(error);

            async.each(serviceList.items, function (oneService, callback) {
                deployer.core.namespaces.services.delete({ name: oneService.metadata.name }, callback);
            }, cb);
        });
    },

    deletePods: function (deployer, options, cb) {
        //force delete all pods for a better cleanup
        deployer.core.namespaces.pods.delete({}, cb);
    },

    deletePreviousServices: function (deployer, cb) {
    	//todo: need to provide --grace-period=0 using the javascript syntax
        lib.deleteDeployments(deployer, {}, function (error) {
            if (error) return cb(error);

            lib.deleteKubeServices(deployer, {}, function (error) {
                if (error) return cb(error);

                lib.deletePods(deployer, {}, cb);
            });
        });
    },

    getServiceIPs: function (serviceName, deployer, replicaCount, counter, cb) {
        if (typeof (counter) === 'function') {
            cb = counter; //counter wasn't passed as param
            counter = 0;
        }

        deployer.core.namespaces.pods.get({}, function (error, podList) {
            if (error) return cb(error);
            var onePod, ips = [];
            podList.items.forEach(function (onePod) {
                if (onePod.metadata.labels['soajs.service.label'] === serviceName && onePod.status.phase === 'Running') {
                    ips.push({
                        name: onePod.metadata.name,
                        ip: onePod.status.podIP
                    });
                }
            });

            if (ips.length !== replicaCount) {
                //pod containers may not be ready yet
                lib.printProgress('Waiting for ' + serviceName + ' containers to become available', counter++);
                setTimeout(function () {
                    return lib.getServiceIPs(serviceName, deployer, replicaCount, counter, cb);
                }, 1000);
            }
            else {
                utilLog.log(""); //intentional, to force writting a new line.
                return cb(null, ips);
            }
        });
    },

    addMongoInfo: function (services, mongoInfo, cb) {
        var mongoEnv = [];

	    if(config.mongo.prefix && config.mongo.prefix !== ""){
		    mongoEnv.push({name: 'SOAJS_MONGO_PREFIX', value: config.mongo.prefix});
	    }

        if (config.mongo.external) {
            // if (!config.dataLayer.mongo.url || !config.dataLayer.mongo.port) {
            if (!profile.servers[0].host || !profile.servers[0].port) {
                utilLog.log('ERROR: External Mongo information is missing URL or port, make sure SOAJS_MONGO_EXTERNAL_URL and SOAJS_MONGO_EXTERNAL_PORT are set ...');
                return cb('ERROR: missing mongo information');
            }

            mongoEnv.push({ name: 'SOAJS_MONGO_NB', value: '' + profile.servers.length });
	        for(var i = 0; i < profile.servers.length; i++){
		        mongoEnv.push({name: 'SOAJS_MONGO_IP_' + (i + 1), value: profile.servers[i].host});
		        mongoEnv.push({name: 'SOAJS_MONGO_PORT_' + (i + 1), value: '' + profile.servers[i].port});
	        }

            if (profile.credentials && profile.credentials.username && profile.credentials.password) {
                mongoEnv.push({ name: 'SOAJS_MONGO_USERNAME', value: profile.credentials.username });
                mongoEnv.push({ name: 'SOAJS_MONGO_PASSWORD', value: profile.credentials.password });
	            mongoEnv.push({ name: 'SOAJS_MONGO_AUTH_DB', value: profile.URLParam.authSource });
            }

            if(profile.URLParam.ssl){
	            mongoEnv.push({ name: 'SOAJS_MONGO_SSL', value: profile.URLParam.ssl });
            }
        }
        else {
            mongoEnv.push({ name: 'SOAJS_MONGO_NB', value: '1' });
	        mongoEnv.push({ name: 'SOAJS_MONGO_IP_1', value: profile.servers[0].host});
	        mongoEnv.push({ name: 'SOAJS_MONGO_PORT_1', value: '27017'});
        }

        services.forEach(function (oneService) {
            oneService.deployment.spec.template.spec.containers[0].env = oneService.deployment.spec.template.spec.containers[0].env.concat(mongoEnv);
        });

        return cb(null, services);
    },

    registerNode: function (deployer, swarmConfig, cb) {
        deployer.core.nodes.get({}, function (error, nodeList) {
            if (error) return cb(error);

            async.map(nodeList.items, function (oneNode, callback) {
                var record = {
                    recordType: 'node',
                    id: oneNode.metadata.uid,
                    name: oneNode.metadata.name,
                    ip: getIP(oneNode.status.addresses),
                    kubePort: config.kubernetes.machinePort,
                    availability: ((!oneNode.spec.unschedulable) ? 'active' : 'drained'),
                    role: 'manager',
                    resources: {
                        cpuCount: oneNode.status.capacity.cpu,
                        memory: calcMemory(oneNode.status.capacity.memory)
                    },
                    tokens: {}
                };

                return callback(null, record);
            }, function (error, nodeRecords) {
                if (error) return cb(error);

                for (var i = nodeRecords.length; i >= 0; i--) {
                    if (!nodeRecords[i]) {
                        nodeRecords.splice(i, 1);
                    }
                }

                mongo.insert(config.kubernetes.mongoCollection, nodeRecords, cb);
            });
        });

        function calcMemory (memory) {
			var value = memory.substring(0, memory.length - 2);
			var unit = memory.substring(memory.length - 2);

			if (unit === 'Ki') value += '000';
			else if (unit === 'Mi') value += '000000';

			return parseInt(value);
		}

        function getIP (addresses) {
			var ip = '';
			for (var i = 0; i < addresses.length; i++) {
				if (addresses[i].type === 'LegacyHostIP') {
					ip = addresses[i].address;
				}
			}

			return ip;
		}
    },

    configureEnvDeployer: function (cb) {
        var criteria = {role: 'manager'};
        mongo.find('docker', criteria, function (error, managerNodes) {
            if (error) return cb(error);

            async.map(managerNodes, function (oneNode, callback) {
                return callback(null, oneNode.name);
            }, function (error, nodeHostnames) {
                //get environments records
                mongo.find('environment', {}, function (error, envs) {
                    if (error) return cb(error);

                    async.each(envs, function (oneEnv, callback) {
                        var target = oneEnv.deployer.selected.split('.')[2];

                        oneEnv.deployer.container.kubernetes[target].nodes = nodeHostnames;
                        mongo.save('environment', oneEnv, callback);
                    }, cb);
                });
            });
        });
    },

    registerContainers: function (deployer, serviceOptions, cb) {
        var info = {};
        var kubeServiceName = serviceOptions.deployment.metadata.name;
        var serviceGroup, serviceName, serviceEnv;

        if (serviceOptions.deployment.metadata.labels) {
            serviceGroup = serviceOptions.deployment.metadata.labels['soajs.service.group'];
            serviceName = serviceOptions.deployment.metadata.labels['soajs.service'];
            serviceEnv = serviceOptions.deployment.metadata.labels['soajs.env'];
        }

        if (serviceGroup === 'core') {
            info.type = (serviceName === 'controller') ? 'controller' : 'service';
        }
        else if (serviceGroup === 'nginx') {
            info.type = 'nginx';
        }
        else {
            return cb(null, true);
        }

        var replicaCount = serviceOptions.deployment.spec.replicas;

        utilLog.log ('Registering ' + serviceName + ' containers in docker collection ...');

        info.env = serviceEnv;
        info.running = true;
        info.recordType = 'container';

        lib.getServiceIPs(kubeServiceName, deployer, replicaCount, function (error, serviceIPs) {
            if (error) return cb(error);

            async.map(serviceIPs, function (oneServiceInfo, callback) {
                deployer.core.namespaces.pods.get({name: oneServiceInfo.name}, function (error, pod) {
                    if (error) return callback(error);
                    var record = JSON.parse(JSON.stringify(info));
                    record.taskName = oneServiceInfo.name;
                    record.serviceName = kubeServiceName;
                    delete pod.metadata.annotations;
                    record.info = pod;
                    return callback(null, record);
                });
            }, function (error, records) {
                if (error) return cb(error);
                mongo.insert(config.kubernetes.mongoCollection, records, cb);
            });
        });
    },

    closeDbCon: function (cb) {
        mongo.closeDb();
        return cb();
    }
};

module.exports = lib;
<|endoftext|>


<commit_before>// TODO: update to VIE 2.0
// var VIE = new VIE();

jQuery(document).ready(function($) {

    VIE.EntityManager.initializeCollection();

    VIE.EntityManager.entities.bind('add', function(model) {
        model.url = vie_phpcr_path + model.id;
        model.toJSON = model.toJSONLD;
    });

    // Load all RDFa entities into VIE
    VIE.RDFaEntities.getInstances();

    // Make all RDFa entities editable

    jQuery('[typeof][about]').each(function() {
        jQuery(this).vieSemanticHallo({
            plugins: {
                'dcterms:title': {
                    'halloformat': {},
                    'hallooverlay': {},
                    'hallotoolbarlinebreak': {}
                },
                'default': {
                    'halloimage': { 'searchUrl': 'liip/vie/assets/search/' },
                    'hallolink': {},
                    'halloheadings': {},
                    'halloformat': {},
                    'hallolists': {},
                    'hallojustify': {},
                    'hallotoolbarlinebreak': { 'breakAfter': ['hallolink'] },
                    'hallooverlay': {}
                }
            },
            floating: false,
            offset: {
                'x': 0,
                'y': "top"
            },
            showAlways: true
        });
    });

    $(this).bind('hallodeactivated', vieSaveContent);
    $(this).bind('startPreventSave', function() {
        preventSave = true;
    });
    $(this).bind('stopPreventSave', function() {
        preventSave = false;
    });

    $(window).resize(function(){
        if(!$('.inEditMode')[0] == undefined ){
            $('.halloToolbar').css('left', $('.inEditMode')[0].offsetLeft);
        }
    });

    $('[contenteditable]').not('.inEditMode').hover(function(){
        $(document).trigger('startPreventSave');
        if(!$(this).hasClass('inEditMode')){
            var editButton = $('
edit
').addClass('editButton');
            $(this).append(editButton);
        }
    }, function(){
        $(document).trigger('stopPreventSave');
        $('.editButton').remove();
    });

});

var preventSave = false;
function vieSaveContent() {
    if (preventSave) {
        setTimeout(vieSaveContent, 5000);
        return;
    }

    // Go through all Backbone model instances loaded for the page
    VIE.EntityManager.entities.each(function(objectInstance) {

        if (!VIE.HalloEditable.refreshFromEditables(objectInstance)) {
            // No changes to this object, skip
            return true;
        }
        $(document).trigger("vieSaveStart");

        // Set the modified properties to the model instance
        objectInstance.save(null, {
            success: function(savedModel, response) {
                $(document).trigger("vieSaveSuccess");
                console.log(savedModel.id + " was saved");
            },
            error: function(response) {
                console.log("Save failed");
                console.log(response);
            }
        });
    });
}
<commit_msg>Only select div in selector<commit_after>// TODO: update to VIE 2.0
// var VIE = new VIE();

jQuery(document).ready(function($) {

    VIE.EntityManager.initializeCollection();

    VIE.EntityManager.entities.bind('add', function(model) {
        model.url = vie_phpcr_path + model.id;
        model.toJSON = model.toJSONLD;
    });

    // Load all RDFa entities into VIE
    VIE.RDFaEntities.getInstances();

    // Make all RDFa entities editable

    jQuery('[typeof][about]').each(function() {
        jQuery(this).vieSemanticHallo({
            plugins: {
                'dcterms:title': {
                    'halloformat': {},
                    'hallooverlay': {},
                    'hallotoolbarlinebreak': {}
                },
                'default': {
                    'halloimage': { 'searchUrl': 'liip/vie/assets/search/' },
                    'hallolink': {},
                    'halloheadings': {},
                    'halloformat': {},
                    'hallolists': {},
                    'hallojustify': {},
                    'hallotoolbarlinebreak': { 'breakAfter': ['hallolink'] },
                    'hallooverlay': {}
                }
            },
            floating: false,
            offset: {
                'x': 0,
                'y': "top"
            },
            showAlways: true
        });
    });

    $(this).bind('hallodeactivated', vieSaveContent);
    $(this).bind('startPreventSave', function() {
        preventSave = true;
    });
    $(this).bind('stopPreventSave', function() {
        preventSave = false;
    });

    $(window).resize(function(){
        if(!$('.inEditMode')[0] == undefined ){
            $('.halloToolbar').css('left', $('.inEditMode')[0].offsetLeft);
        }
    });

    $('div[contenteditable]').not('.inEditMode').hover(function(){
        $(document).trigger('startPreventSave');
        if(!$(this).hasClass('inEditMode')){
            var editButton = $('
edit
').addClass('editButton');
            $(this).append(editButton);
        }
    }, function(){
        $(document).trigger('stopPreventSave');
        $('.editButton').remove();
    });

});

var preventSave = false;
function vieSaveContent() {
    if (preventSave) {
        setTimeout(vieSaveContent, 5000);
        return;
    }

    // Go through all Backbone model instances loaded for the page
    VIE.EntityManager.entities.each(function(objectInstance) {

        if (!VIE.HalloEditable.refreshFromEditables(objectInstance)) {
            // No changes to this object, skip
            return true;
        }
        $(document).trigger("vieSaveStart");

        // Set the modified properties to the model instance
        objectInstance.save(null, {
            success: function(savedModel, response) {
                $(document).trigger("vieSaveSuccess");
                console.log(savedModel.id + " was saved");
            },
            error: function(response) {
                console.log("Save failed");
                console.log(response);
            }
        });
    });
}
<|endoftext|>


<commit_before>const path = require('path');
const chai = require('chai');
const expect = chai.expect;

const MockerParser = require('../../../src/mocker/MockerParser');
const Mocker = require('../../../src/mocker/Mocker');
const MockModule = require('../../../src/mocker/MockModule');

describe.only('./mocker/MockerParser.js', () => {
    let mockerParser;

    before(() => {
        mockerParser = new MockerParser({
            basePath: path.resolve(__dirname, '../../data/fixtures/mock_service/mockers')
        });

        // console.log(mockerParser);
    });

    describe('check basic info', () => {
        it('should be instanceof MockerParser ', () => {
            expect(mockerParser).to.be.an.instanceof(MockerParser);
        });

        it('should contain some fields', () => {
            expect(mockerParser).to.have.all.keys('basePath', 'matmanMockers');
        });
    });

    describe('check demo_01', () => {
        it('mockerParser.getMockerByName(\'demo_01\') should return correct mocker', () => {
            let mocker = mockerParser.getMockerByName('demo_01');

            expect(mocker).to.be.an.instanceof(Mocker);
            expect(mocker.name).to.equal('demo_01');
            expect(mocker.mockModuleList).to.have.lengthOf(2);
        });

        it('mockerParser.getMockModuleByName(\'demo_01\', \'error\') should return correct mockModule', () => {
            let mockModule = mockerParser.getMockModuleByName('demo_01', 'error');

            expect(mockModule).to.be.an.instanceof(MockModule);
            expect(mockModule.name).to.equal('error');

            return mockModule.getResult()
                .then((data) => {
                    expect(data).to.eql({
                        errCode: 100000
                    });
                });
        });
    });

    describe('check demo_02', () => {
        it('mockerParser.getMockerByName(\'demo_02\') should return correct mocker', () => {
            let mocker = mockerParser.getMockerByName('demo_02');

            expect(mocker).to.be.undefined;
        });

        it('mockerParser.getMockerByName(\'demo_02_renamed\') should return correct mocker', () => {
            let mocker = mockerParser.getMockerByName('demo_02_renamed');

            expect(mocker).to.be.an.instanceof(Mocker);
            expect(mocker.name).to.equal('demo_02_renamed');
            expect(mocker.mockModuleList).to.have.lengthOf(5);
        });

        it('mockerParser.getMockModuleByName(\'demo_02_renamed\', \'error\') should return correct mockModule', () => {
            let mockModule = mockerParser.getMockModuleByName('demo_02_renamed', 'error');

            expect(mockModule).to.be.an.instanceof(MockModule);
            expect(mockModule.name).to.equal('error');

            return mockModule.getResult()
                .then((data) => {
                    expect(data).to.eql({
                        errCode: 100000
                    });
                });
        });

        it('mockerParser.getMockModuleByName(\'demo_02_renamed\', \'success_1\') should return correct mockModule', () => {
            let mockModule = mockerParser.getMockModuleByName('demo_02_renamed', 'success_1');

            expect(mockModule).to.be.an.instanceof(MockModule);
            expect(mockModule.name).to.equal('success_1');

            return mockModule.getResult()
                .then((data) => {
                    expect(data).to.eql({
                        'result': {
                            'other': 'other',
                            'result': 1
                        },
                        'retcode': 0
                    });
                });
        });

        it('mockerParser.getMockModuleByName(\'demo_02_renamed\', \'success_2\') should return correct mockModule', () => {
            let mockModule = mockerParser.getMockModuleByName('demo_02_renamed', 'success_2');

            expect(mockModule).to.be.an.instanceof(MockModule);
            expect(mockModule.name).to.equal('success_2');

            return mockModule.getResult()
                .then((data) => {
                    expect(data).to.eql({
                        'result': 2
                    });
                });
        });

        it('mockerParser.getMockModuleByName(\'demo_02_renamed\', \'success_3_renamed\') should return correct mockModule', () => {
            let mockModule = mockerParser.getMockModuleByName('demo_02_renamed', 'success_3_renamed');

            expect(mockModule).to.be.an.instanceof(MockModule);
            expect(mockModule.name).to.equal('success_3_renamed');

            return mockModule.getResult()
                .then((data) => {
                    expect(data).to.eql({
                        'result': 3
                    });
                });
        });

        it('mockerParser.getMockModuleByName(\'demo_02_renamed\', \'success_4\') should return correct mockModule', () => {
            let mockModule = mockerParser.getMockModuleByName('demo_02_renamed', 'success_4');

            expect(mockModule).to.be.an.instanceof(MockModule);
            expect(mockModule.name).to.equal('success_4');

            return mockModule.getResult()
                .then((data) => {
                    expect(data).to.equal(4);
                });
        });
        it('mockerParser.getMockModuleByName(\'demo_02_renamed\', \'success_4\') with param should return correct mockModule', () => {
            let mockModule = mockerParser.getMockModuleByName('demo_02_renamed', 'success_4');

            expect(mockModule).to.be.an.instanceof(MockModule);
            expect(mockModule.name).to.equal('success_4');

            return mockModule.getResult({ a: 110 })
                .then((data) => {
                    expect(data).to.equal('from_param_110');
                });
        });
    });

    describe('check getMockerByRoute', () => {
        it('should return demo_01', () => {
            let mocker = mockerParser.getMockerByRoute('/cgi-bin/a/b/demo_01');

            expect(mocker).to.be.an.instanceof(Mocker);
            expect(mocker.name).to.equal('demo_01');
        });

        it('should return demo_02', () => {
            let mocker = mockerParser.getMockerByRoute('/cgi-bin/a/b/demo_02');

            expect(mocker).to.be.an.instanceof(Mocker);
            expect(mocker.name).to.equal('demo_02_renamed');
        });

    });
});

<commit_msg>refactor: 新增 getMockerByRoute 测试<commit_after>const path = require('path');
const chai = require('chai');
const expect = chai.expect;

const MockerParser = require('../../../src/mocker/MockerParser');
const Mocker = require('../../../src/mocker/Mocker');
const MockModule = require('../../../src/mocker/MockModule');

describe.only('./mocker/MockerParser.js', () => {
    let mockerParser;

    before(() => {
        mockerParser = new MockerParser({
            basePath: path.resolve(__dirname, '../../data/fixtures/mock_service/mockers')
        });

        // console.log(mockerParser);
    });

    describe('check basic info', () => {
        it('should be instanceof MockerParser ', () => {
            expect(mockerParser).to.be.an.instanceof(MockerParser);
        });

        it('should contain some fields', () => {
            expect(mockerParser).to.have.all.keys('basePath', 'matmanMockers');
        });
    });

    describe('check demo_01', () => {
        it('mockerParser.getMockerByName(\'demo_01\') should return correct mocker', () => {
            let mocker = mockerParser.getMockerByName('demo_01');

            expect(mocker).to.be.an.instanceof(Mocker);
            expect(mocker.name).to.equal('demo_01');
            expect(mocker.mockModuleList).to.have.lengthOf(2);
        });

        it('mockerParser.getMockModuleByName(\'demo_01\', \'error\') should return correct mockModule', () => {
            let mockModule = mockerParser.getMockModuleByName('demo_01', 'error');

            expect(mockModule).to.be.an.instanceof(MockModule);
            expect(mockModule.name).to.equal('error');

            return mockModule.getResult()
                .then((data) => {
                    expect(data).to.eql({
                        errCode: 100000
                    });
                });
        });
    });

    describe('check demo_02', () => {
        it('mockerParser.getMockerByName(\'demo_02\') should return correct mocker', () => {
            let mocker = mockerParser.getMockerByName('demo_02');

            expect(mocker).to.be.undefined;
        });

        it('mockerParser.getMockerByName(\'demo_02_renamed\') should return correct mocker', () => {
            let mocker = mockerParser.getMockerByName('demo_02_renamed');

            expect(mocker).to.be.an.instanceof(Mocker);
            expect(mocker.name).to.equal('demo_02_renamed');
            expect(mocker.mockModuleList).to.have.lengthOf(5);
        });

        it('mockerParser.getMockModuleByName(\'demo_02_renamed\', \'error\') should return correct mockModule', () => {
            let mockModule = mockerParser.getMockModuleByName('demo_02_renamed', 'error');

            expect(mockModule).to.be.an.instanceof(MockModule);
            expect(mockModule.name).to.equal('error');

            return mockModule.getResult()
                .then((data) => {
                    expect(data).to.eql({
                        errCode: 100000
                    });
                });
        });

        it('mockerParser.getMockModuleByName(\'demo_02_renamed\', \'success_1\') should return correct mockModule', () => {
            let mockModule = mockerParser.getMockModuleByName('demo_02_renamed', 'success_1');

            expect(mockModule).to.be.an.instanceof(MockModule);
            expect(mockModule.name).to.equal('success_1');

            return mockModule.getResult()
                .then((data) => {
                    expect(data).to.eql({
                        'result': {
                            'other': 'other',
                            'result': 1
                        },
                        'retcode': 0
                    });
                });
        });

        it('mockerParser.getMockModuleByName(\'demo_02_renamed\', \'success_2\') should return correct mockModule', () => {
            let mockModule = mockerParser.getMockModuleByName('demo_02_renamed', 'success_2');

            expect(mockModule).to.be.an.instanceof(MockModule);
            expect(mockModule.name).to.equal('success_2');

            return mockModule.getResult()
                .then((data) => {
                    expect(data).to.eql({
                        'result': 2
                    });
                });
        });

        it('mockerParser.getMockModuleByName(\'demo_02_renamed\', \'success_3_renamed\') should return correct mockModule', () => {
            let mockModule = mockerParser.getMockModuleByName('demo_02_renamed', 'success_3_renamed');

            expect(mockModule).to.be.an.instanceof(MockModule);
            expect(mockModule.name).to.equal('success_3_renamed');

            return mockModule.getResult()
                .then((data) => {
                    expect(data).to.eql({
                        'result': 3
                    });
                });
        });

        it('mockerParser.getMockModuleByName(\'demo_02_renamed\', \'success_4\') should return correct mockModule', () => {
            let mockModule = mockerParser.getMockModuleByName('demo_02_renamed', 'success_4');

            expect(mockModule).to.be.an.instanceof(MockModule);
            expect(mockModule.name).to.equal('success_4');

            return mockModule.getResult()
                .then((data) => {
                    expect(data).to.equal(4);
                });
        });
        it('mockerParser.getMockModuleByName(\'demo_02_renamed\', \'success_4\') with param should return correct mockModule', () => {
            let mockModule = mockerParser.getMockModuleByName('demo_02_renamed', 'success_4');

            expect(mockModule).to.be.an.instanceof(MockModule);
            expect(mockModule.name).to.equal('success_4');

            return mockModule.getResult({ a: 110 })
                .then((data) => {
                    expect(data).to.equal('from_param_110');
                });
        });
    });

    describe('check getMockerByRoute', () => {
        it('should return demo_01', () => {
            let mocker = mockerParser.getMockerByRoute('/cgi-bin/a/b/demo_01');

            expect(mocker).to.be.an.instanceof(Mocker);
            expect(mocker.name).to.equal('demo_01');
        });

        it('should return null', () => {
            let mocker = mockerParser.getMockerByRoute('/cgi-bin/a/b/demo_not_exist');

            expect(mocker).to.be.null;
        });

        it('should return demo_02', () => {
            let mocker = mockerParser.getMockerByRoute('/cgi-bin/a/b/demo_02');

            expect(mocker).to.be.an.instanceof(Mocker);
            expect(mocker.name).to.equal('demo_02_renamed');
        });

    });
});

<|endoftext|>


<commit_before>var Backbone = require('backbone');
var Map = require('../../../src/geo/map');
var VisModel = require('../../../src/vis/vis');
var CartoDBLayer = require('../../../src/geo/map/cartodb-layer');
var CartoDBLayerGroup = require('../../../src/geo/cartodb-layer-group');

var TooltipModel = require('../../../src/geo/ui/tooltip-model');
var InfowindowModel = require('../../../src/geo/ui/infowindow-model');

var InfowindowManager = require('../../../src/vis/infowindow-manager');

var createCartoDBLayer = function (vis, infowindowAttrs) {
  infowindowAttrs = infowindowAttrs || {
    fields: [{
      'name': 'name',
      'title': true,
      'position': 1
    }],
    template: '
{{ name }}
'
  };
  return new CartoDBLayer({
    infowindow: infowindowAttrs
  }, { vis: vis });
};

var simulateFeatureClickEvent = function (layerView, data) {
  layerView.trigger('featureClick', {
    layer: layerView.model.getLayerInLayerGroupAt(data.layerIndex),
    layerIndex: data.layerIndex,
    latlng: [100, 200],
    position: { x: 20, y: 30 },
    feature: data.data
  });
};

describe('src/vis/infowindow-manager.js', function () {
  beforeEach(function () {
    this.map = new Map({}, {
      layersFactory: {}
    });

    this.infowindowModel = new InfowindowModel();
    this.tooltipModel = new TooltipModel();

    this.cartoDBLayerGroup = new CartoDBLayerGroup({}, {
      layersCollection: this.map.layers
    });

    this.layerView = new Backbone.View({
      model: this.cartoDBLayerGroup
    });

    spyOn(this.cartoDBLayerGroup, 'fetchAttributes').and.callFake(function (layerIndex, featureId, callback) {
      var data = { name: 'juan' };
      callback(data);
    });

    this.vis = new VisModel();
    spyOn(this.vis, 'reload');

    this.infowindowManager = new InfowindowManager({ // eslint-disable-line
      visModel: this.vis,
      mapModel: this.map,
      infowindowModel: this.infowindowModel,
      tooltipModel: this.tooltipModel
    });
  });

  it('should correctly bind the featureClick event to the corresponding layerView', function () {
    var layer1 = createCartoDBLayer(this.vis, {
      template: 'template1',
      template_type: 'underscore',
      fields: [{
        'name': 'name',
        'title': true,
        'position': 1
      }],
      alternative_names: 'alternative_names1'
    });

    var layer2 = createCartoDBLayer(this.vis, {
      template: 'template2',
      template_type: 'underscore',
      fields: [{
        'name': 'description',
        'title': true,
        'position': 1
      }],
      alternative_names: 'alternative_names2'
    });

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer1, layer2 ]);

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    // A request to fetch the attributes for the right cartodb_id and layerIndex has been triggered
    expect(this.layerView.model.fetchAttributes.calls.count()).toEqual(1);
    expect(this.layerView.model.fetchAttributes).toHaveBeenCalledWith(0, 10, jasmine.any(Function));
    this.layerView.model.fetchAttributes.calls.reset();

    // InfowindowModel has been updated
    expect(this.infowindowModel.attributes).toEqual({
      'template': 'template1',
      'alternative_names': 'alternative_names1',
      'template_type': 'underscore',
      'offset': [
        28,
        0
      ],
      'maxHeight': 180,
      'autoPan': true,
      'content': {
        'fields': [
          {
            'name': 'name',
            'title': 'name',
            'value': 'juan',
            'index': 0
          }
        ],
        'data': {
          'name': 'juan'
        }
      },
      'latlng': [
        100,
        200
      ],
      'visibility': true,
      'currentFeatureId': 10
    });

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 1,
      data: { cartodb_id: 100 }
    });

    // A request to fetch the attributes for the right cartodb_id and layerIndex has been triggered
    expect(this.layerView.model.fetchAttributes.calls.count()).toEqual(1);
    expect(this.layerView.model.fetchAttributes).toHaveBeenCalledWith(1, 100, jasmine.any(Function));
    this.layerView.model.fetchAttributes.calls.reset();

    // InfowindowModel has been updated
    expect(this.infowindowModel.attributes).toEqual({
      'template': 'template2',
      'alternative_names': 'alternative_names2',
      'template_type': 'underscore',
      'offset': [
        28,
        0
      ],
      'maxHeight': 180,
      'autoPan': true,
      'content': {
        'fields': [
          {
            'title': null,
            'value': 'No data available',
            'index': 0,
            'type': 'empty'
          }
        ],
        'data': {
          'name': 'juan'
        }
      },
      'latlng': [
        100,
        200
      ],
      'visibility': true,
      'currentFeatureId': 100
    });
  });

  it('should not fetch attributes and show the infowindow if template is empty', function () {
    var layer1 = createCartoDBLayer(this.vis, {
      template: '',
      template_type: 'underscore',
      fields: [{
        'name': 'name',
        'title': true,
        'position': 1
      }],
      alternative_names: 'alternative_names1'
    });

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer1 ]);

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    expect(this.layerView.model.fetchAttributes).not.toHaveBeenCalled();
    expect(this.infowindowModel.get('visibility')).toEqual(false);
  });

  it('should not fetch attributes and show the infowindow if popups are disabled', function () {
    var layer1 = createCartoDBLayer(this.vis, {
      template: 'template1',
      template_type: 'underscore',
      fields: [{
        'name': 'name',
        'title': true,
        'position': 1
      }],
      alternative_names: 'alternative_names1'
    });

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer1 ]);
    this.map.disablePopups();

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    expect(this.layerView.model.fetchAttributes).not.toHaveBeenCalled();
    expect(this.infowindowModel.get('visibility')).toEqual(false);
  });

  it('should hide the infowindow if map popups are disabled', function () {
    var layer1 = createCartoDBLayer(this.vis, {
      template: 'template1',
      template_type: 'underscore',
      fields: [{
        'name': 'name',
        'title': true,
        'position': 1
      }],
      alternative_names: 'alternative_names1'
    });

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer1 ]);

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    expect(this.infowindowModel.get('visibility')).toEqual(true);

    // Disable Map Popups
    this.map.disablePopups();

    expect(this.infowindowModel.get('visibility')).toEqual(false);
  });

  it('should set loading content while loading', function () {
    var layer1 = createCartoDBLayer(this.vis);

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer1 ]);

    // Fetch attributes does NOT suceed inmediatily
    this.layerView.model.fetchAttributes.and.callFake(function () {});

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    // InfowindowModel has been updated
    expect(this.infowindowModel.get('content').fields).toEqual([
      {
        'type': 'loading',
        'title': 'loading',
        'value': '…'
      }
    ]);
    expect(this.infowindowModel.get('visibility')).toBe(true);
  });

  it('should set error content if no attributes are returned', function () {
    var layer1 = new CartoDBLayer({
      infowindow: {
        template: 'template1',
        template_type: 'underscore',
        fields: [{
          'name': 'name',
          'title': true,
          'position': 1
        }],
        alternative_names: 'alternative_names1'
      }
    }, { vis: this.vis });

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer1 ]);

    this.layerView.model.fetchAttributes.and.callFake(function (layerIndex, featureId, callback) {
      callback();
    });

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    // InfowindowModel has been updated
    expect(this.infowindowModel.get('content').fields).toEqual([
      {
        'title': null,
        'alternative_name': null,
        'value': 'There has been an error...',
        'index': null,
        'type': 'error'
      }
    ]);
    expect(this.infowindowModel.get('visibility')).toBe(true);
  });

  it('should set the currentFeatureId on the model when the infowindow is shown', function () {
    var layer = new CartoDBLayer({
      infowindow: {
        template: 'template',
        template_type: 'underscore',
        fields: [{
          'name': 'name',
          'title': true,
          'position': 1
        }],
        alternative_names: 'alternative_names'
      }
    }, { vis: this.vis });

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer ]);

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    expect(this.infowindowModel.getCurrentFeatureId()).toEqual(10);
  });

  it('should hide the tooltip', function () {
    var layer = new CartoDBLayer({
      infowindow: {
        template: 'template',
        template_type: 'underscore',
        fields: [{
          'name': 'name',
          'title': true,
          'position': 1
        }],
        alternative_names: 'alternative_names'
      }
    }, { vis: this.vis });

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer ]);

    this.tooltipModel.set('visible', true);

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    expect(this.tooltipModel.isVisible()).toBeFalsy();
  });

  it('should unset the currentFeatureId on the model when the infowindow is hidden', function () {
    var layer = createCartoDBLayer(this.vis);

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer ]);

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    // Layer is hidden and infowindow too
    layer.hide();

    expect(this.infowindowModel.getCurrentFeatureId()).toBeUndefined();
  });

  it('should update the infowindow model when the infowindow template gets new fields', function () {
    var layer = createCartoDBLayer(this.vis);

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer ]);

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    spyOn(this.infowindowModel, 'setInfowindowTemplate');

    layer.infowindow.update({
      fields: [
        {
          'name': 'name',
          'title': true,
          'position': 1
        },
        {
          'name': 'description',
          'title': true,
          'position': 2
        }
      ]
    });

    expect(this.infowindowModel.setInfowindowTemplate).toHaveBeenCalledWith(layer.infowindow);
  });

  it('should re-fetch attributes when the vis is reloaded', function () {
    var layer = createCartoDBLayer(this.vis);
    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer ]);

    this.cartoDBLayerGroup.fetchAttributes.and.callFake(function (layerIndex, featureId, callback) {
      var data = { name: 'juan' };
      callback(data);
    });

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    expect(this.infowindowModel.get('content')).toEqual({
      'fields': [
        {
          'name': 'name',
          'title': 'name',
          'value': 'juan',
          'index': 0
        }
      ],
      'data': {
        'name': 'juan'
      }
    });

    this.cartoDBLayerGroup.fetchAttributes.and.callFake(function (layerIndex, featureId, callback) {
      var data = { name: 'luis' };
      callback(data);
    });

    this.vis.trigger('reloaded');

    // InfowindowModel has been updated
    expect(this.infowindowModel.get('content')).toEqual({
      'fields': [
        {
          'name': 'name',
          'title': 'name',
          'value': 'luis',
          'index': 0
        }
      ],
      'data': {
        'name': 'luis'
      }
    });
  });

  it('should hide the infowindow when fields are cleared in the infowindow template', function () {
    // Simulate that the layerView has been added a tooltipView
    var tooltipView = jasmine.createSpyObj('tooltipView', ['setFilter', 'hide']);
    tooltipView.setFilter.and.returnValue(tooltipView);
    this.layerView.tooltipView = tooltipView;

    var layer1 = createCartoDBLayer(this.vis);
    var layer2 = createCartoDBLayer(this.vis);

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer1, layer2 ]);

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    expect(this.infowindowModel.get('visibility')).toBe(true);

    // Clear fields on layer #1
    layer2.infowindow.update({
      fields: []
    });

    // Nothing happened
    expect(this.infowindowModel.get('visibility')).toBe(true);
    expect(this.vis.reload).not.toHaveBeenCalledWith({});

    // Clear fields on layer #0 (the one that was opened)
    layer1.infowindow.update({
      fields: []
    });

    // Infowindow has been closed and map has NOT been reloaded
    expect(this.infowindowModel.get('visibility')).toBe(false);
    expect(this.vis.reload).not.toHaveBeenCalledWith({});
  });

  it('should hide the infowindow if the layer is hidden', function () {
    var layer1 = createCartoDBLayer(this.vis);
    var layer2 = createCartoDBLayer(this.vis);

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer1, layer2 ]);

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    expect(this.infowindowModel.get('visibility')).toBe(true);

    // hide layer2 -> nothing happens
    layer2.hide();

    expect(this.infowindowModel.get('visibility')).toBe(true);

    // hide layer1 -> infowindow is hidden
    layer1.hide();

    expect(this.infowindowModel.get('visibility')).toBe(false);
  });
});
<commit_msg>Add test<commit_after>var Backbone = require('backbone');
var Map = require('../../../src/geo/map');
var VisModel = require('../../../src/vis/vis');
var CartoDBLayer = require('../../../src/geo/map/cartodb-layer');
var CartoDBLayerGroup = require('../../../src/geo/cartodb-layer-group');

var TooltipModel = require('../../../src/geo/ui/tooltip-model');
var InfowindowModel = require('../../../src/geo/ui/infowindow-model');

var InfowindowManager = require('../../../src/vis/infowindow-manager');

var createCartoDBLayer = function (vis, infowindowAttrs) {
  infowindowAttrs = infowindowAttrs || {
    fields: [{
      'name': 'name',
      'title': true,
      'position': 1
    }],
    template: '
{{ name }}
'
  };
  return new CartoDBLayer({
    infowindow: infowindowAttrs
  }, { vis: vis });
};

var simulateFeatureClickEvent = function (layerView, data) {
  layerView.trigger('featureClick', {
    layer: layerView.model.getLayerInLayerGroupAt(data.layerIndex),
    layerIndex: data.layerIndex,
    latlng: [100, 200],
    position: { x: 20, y: 30 },
    feature: data.data
  });
};

describe('src/vis/infowindow-manager.js', function () {
  beforeEach(function () {
    this.map = new Map({}, {
      layersFactory: {}
    });

    this.infowindowModel = new InfowindowModel();
    this.tooltipModel = new TooltipModel();

    this.cartoDBLayerGroup = new CartoDBLayerGroup({}, {
      layersCollection: this.map.layers
    });

    this.layerView = new Backbone.View({
      model: this.cartoDBLayerGroup
    });

    spyOn(this.cartoDBLayerGroup, 'fetchAttributes').and.callFake(function (layerIndex, featureId, callback) {
      var data = { name: 'juan' };
      callback(data);
    });

    this.vis = new VisModel();
    spyOn(this.vis, 'reload');

    this.infowindowManager = new InfowindowManager({ // eslint-disable-line
      visModel: this.vis,
      mapModel: this.map,
      infowindowModel: this.infowindowModel,
      tooltipModel: this.tooltipModel
    });
  });

  it('should correctly bind the featureClick event to the corresponding layerView', function () {
    var layer1 = createCartoDBLayer(this.vis, {
      template: 'template1',
      template_type: 'underscore',
      fields: [{
        'name': 'name',
        'title': true,
        'position': 1
      }],
      alternative_names: 'alternative_names1'
    });

    var layer2 = createCartoDBLayer(this.vis, {
      template: 'template2',
      template_type: 'underscore',
      fields: [{
        'name': 'description',
        'title': true,
        'position': 1
      }],
      alternative_names: 'alternative_names2'
    });

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer1, layer2 ]);

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    // A request to fetch the attributes for the right cartodb_id and layerIndex has been triggered
    expect(this.layerView.model.fetchAttributes.calls.count()).toEqual(1);
    expect(this.layerView.model.fetchAttributes).toHaveBeenCalledWith(0, 10, jasmine.any(Function));
    this.layerView.model.fetchAttributes.calls.reset();

    // InfowindowModel has been updated
    expect(this.infowindowModel.attributes).toEqual({
      'template': 'template1',
      'alternative_names': 'alternative_names1',
      'template_type': 'underscore',
      'offset': [
        28,
        0
      ],
      'maxHeight': 180,
      'autoPan': true,
      'content': {
        'fields': [
          {
            'name': 'name',
            'title': 'name',
            'value': 'juan',
            'index': 0
          }
        ],
        'data': {
          'name': 'juan'
        }
      },
      'latlng': [
        100,
        200
      ],
      'visibility': true,
      'currentFeatureId': 10
    });

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 1,
      data: { cartodb_id: 100 }
    });

    // A request to fetch the attributes for the right cartodb_id and layerIndex has been triggered
    expect(this.layerView.model.fetchAttributes.calls.count()).toEqual(1);
    expect(this.layerView.model.fetchAttributes).toHaveBeenCalledWith(1, 100, jasmine.any(Function));
    this.layerView.model.fetchAttributes.calls.reset();

    // InfowindowModel has been updated
    expect(this.infowindowModel.attributes).toEqual({
      'template': 'template2',
      'alternative_names': 'alternative_names2',
      'template_type': 'underscore',
      'offset': [
        28,
        0
      ],
      'maxHeight': 180,
      'autoPan': true,
      'content': {
        'fields': [
          {
            'title': null,
            'value': 'No data available',
            'index': 0,
            'type': 'empty'
          }
        ],
        'data': {
          'name': 'juan'
        }
      },
      'latlng': [
        100,
        200
      ],
      'visibility': true,
      'currentFeatureId': 100
    });
  });

  it('should not fetch attributes and show the infowindow if template is empty', function () {
    var layer1 = createCartoDBLayer(this.vis, {
      template: '',
      template_type: 'underscore',
      fields: [{
        'name': 'name',
        'title': true,
        'position': 1
      }],
      alternative_names: 'alternative_names1'
    });

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer1 ]);

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    expect(this.layerView.model.fetchAttributes).not.toHaveBeenCalled();
    expect(this.infowindowModel.get('visibility')).toEqual(false);
  });

  it('should not fetch attributes and show the infowindow if popups are disabled', function () {
    var layer1 = createCartoDBLayer(this.vis, {
      template: 'template1',
      template_type: 'underscore',
      fields: [{
        'name': 'name',
        'title': true,
        'position': 1
      }],
      alternative_names: 'alternative_names1'
    });

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer1 ]);
    this.map.disablePopups();

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    expect(this.layerView.model.fetchAttributes).not.toHaveBeenCalled();
    expect(this.infowindowModel.get('visibility')).toEqual(false);
  });

  it('should hide the infowindow if map popups are disabled', function () {
    var layer1 = createCartoDBLayer(this.vis, {
      template: 'template1',
      template_type: 'underscore',
      fields: [{
        'name': 'name',
        'title': true,
        'position': 1
      }],
      alternative_names: 'alternative_names1'
    });

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer1 ]);

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    expect(this.infowindowModel.get('visibility')).toEqual(true);

    // Disable Map Popups
    this.map.disablePopups();

    expect(this.infowindowModel.get('visibility')).toEqual(false);
  });

  it('should set loading content while loading', function () {
    var layer1 = createCartoDBLayer(this.vis);

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer1 ]);

    // Fetch attributes does NOT suceed inmediatily
    this.layerView.model.fetchAttributes.and.callFake(function () {});

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    // InfowindowModel has been updated
    expect(this.infowindowModel.get('content').fields).toEqual([
      {
        'type': 'loading',
        'title': 'loading',
        'value': '…'
      }
    ]);
    expect(this.infowindowModel.get('visibility')).toBe(true);
  });

  it('should set error content if no attributes are returned', function () {
    var layer1 = new CartoDBLayer({
      infowindow: {
        template: 'template1',
        template_type: 'underscore',
        fields: [{
          'name': 'name',
          'title': true,
          'position': 1
        }],
        alternative_names: 'alternative_names1'
      }
    }, { vis: this.vis });

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer1 ]);

    this.layerView.model.fetchAttributes.and.callFake(function (layerIndex, featureId, callback) {
      callback();
    });

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    // InfowindowModel has been updated
    expect(this.infowindowModel.get('content').fields).toEqual([
      {
        'title': null,
        'alternative_name': null,
        'value': 'There has been an error...',
        'index': null,
        'type': 'error'
      }
    ]);
    expect(this.infowindowModel.get('visibility')).toBe(true);
  });

  it('should set the currentFeatureId on the model when the infowindow is shown', function () {
    var layer = new CartoDBLayer({
      infowindow: {
        template: 'template',
        template_type: 'underscore',
        fields: [{
          'name': 'name',
          'title': true,
          'position': 1
        }],
        alternative_names: 'alternative_names'
      }
    }, { vis: this.vis });

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer ]);

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    expect(this.infowindowModel.getCurrentFeatureId()).toEqual(10);
  });

  it('should hide the tooltip', function () {
    var layer = new CartoDBLayer({
      infowindow: {
        template: 'template',
        template_type: 'underscore',
        fields: [{
          'name': 'name',
          'title': true,
          'position': 1
        }],
        alternative_names: 'alternative_names'
      }
    }, { vis: this.vis });

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer ]);

    this.tooltipModel.set('visible', true);

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    expect(this.tooltipModel.isVisible()).toBeFalsy();
  });

  it('should unset the currentFeatureId on the model when the infowindow is hidden', function () {
    var layer = createCartoDBLayer(this.vis);

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer ]);

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    // Layer is hidden and infowindow too
    layer.hide();

    expect(this.infowindowModel.getCurrentFeatureId()).toBeUndefined();
  });

  it('should update the infowindow model when the infowindow template gets new fields', function () {
    var layer = createCartoDBLayer(this.vis);

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer ]);

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    spyOn(this.infowindowModel, 'setInfowindowTemplate');

    layer.infowindow.update({
      fields: [
        {
          'name': 'name',
          'title': true,
          'position': 1
        },
        {
          'name': 'description',
          'title': true,
          'position': 2
        }
      ]
    });

    expect(this.infowindowModel.setInfowindowTemplate).toHaveBeenCalledWith(layer.infowindow);
  });

  it('should re-fetch attributes when the vis is reloaded', function () {
    var layer = createCartoDBLayer(this.vis);
    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer ]);

    this.cartoDBLayerGroup.fetchAttributes.and.callFake(function (layerIndex, featureId, callback) {
      var data = { name: 'juan' };
      callback(data);
    });

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    expect(this.infowindowModel.get('content')).toEqual({
      'fields': [
        {
          'name': 'name',
          'title': 'name',
          'value': 'juan',
          'index': 0
        }
      ],
      'data': {
        'name': 'juan'
      }
    });

    this.cartoDBLayerGroup.fetchAttributes.and.callFake(function (layerIndex, featureId, callback) {
      var data = { name: 'luis' };
      callback(data);
    });

    this.vis.trigger('reloaded');

    // InfowindowModel has been updated
    expect(this.infowindowModel.get('content')).toEqual({
      'fields': [
        {
          'name': 'name',
          'title': 'name',
          'value': 'luis',
          'index': 0
        }
      ],
      'data': {
        'name': 'luis'
      }
    });
  });

  it('should hide the infowindow when fields are cleared in the infowindow template', function () {
    // Simulate that the layerView has been added a tooltipView
    var tooltipView = jasmine.createSpyObj('tooltipView', ['setFilter', 'hide']);
    tooltipView.setFilter.and.returnValue(tooltipView);
    this.layerView.tooltipView = tooltipView;

    var layer1 = createCartoDBLayer(this.vis);
    var layer2 = createCartoDBLayer(this.vis);

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer1, layer2 ]);

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    expect(this.infowindowModel.get('visibility')).toBe(true);

    // Clear fields on layer #1
    layer2.infowindow.update({
      fields: []
    });

    // Nothing happened
    expect(this.infowindowModel.get('visibility')).toBe(true);
    expect(this.vis.reload).not.toHaveBeenCalledWith({});

    // Clear fields on layer #0 (the one that was opened)
    layer1.infowindow.update({
      fields: []
    });

    // Infowindow has been closed and map has NOT been reloaded
    expect(this.infowindowModel.get('visibility')).toBe(false);
    expect(this.vis.reload).not.toHaveBeenCalledWith({});
  });

  it('should hide the infowindow if the layer is hidden', function () {
    var layer1 = createCartoDBLayer(this.vis);
    var layer2 = createCartoDBLayer(this.vis);

    this.infowindowManager.start(this.layerView);

    this.map.layers.reset([ layer1, layer2 ]);

    simulateFeatureClickEvent(this.layerView, {
      layerIndex: 0,
      data: { cartodb_id: 10 }
    });

    expect(this.infowindowModel.get('visibility')).toBe(true);

    // hide layer2 -> nothing happens
    layer2.hide();

    expect(this.infowindowModel.get('visibility')).toBe(true);

    // hide layer1 -> infowindow is hidden
    layer1.hide();

    expect(this.infowindowModel.get('visibility')).toBe(false);
  });

  describe('.fetchAttributes', function () {
    fit('should work as expected?', function () {
      jasmine.clock().install();
      var currentCall = 0;
      spyOn(this.infowindowModel, 'updateContent');
      this.infowindowManager._cartoDBLayerGroupView = this.layerView;
      this.currentFeatureId = 10;

      spyOn(this.cartoDBLayerGroup, 'getIndexOfLayerInLayerGroup').and.callFake(function () {
        return currentCall++;
      });

      this.cartoDBLayerGroup.fetchAttributes.and.callFake(function (layerIndex, featureId, callback) {
        var data = { name: 'test' };

        currentCall === 1
          ? setTimeout(function () { callback(data); }, 100)
          : callback(data);
      });

      this.infowindowManager._fetchAttributes(10);
      this.infowindowManager._fetchAttributes(4);

      jasmine.clock().tick(101);
      expect(this.infowindowModel.updateContent.calls.count()).toEqual(1);

      jasmine.clock().uninstall();
    });
  });
});
<|endoftext|>


<commit_before>describe("REPLConsole", function() {
  SpecHelper.prepareStageElement();

  describe("#install()", function() {
    beforeEach(function() {
      this.elm = document.createElement("div");
      this.stageElement.appendChild(this.elm);
    });

    context("install console", function() {
      beforeEach(function() {
        var replConsole = new REPLConsole;
        replConsole.install(this.elm);
      });
      it("should have .console", function() {
        assert.ok(hasClass(this.elm, "console"));
      });
      it("should have a inner", function() {
        assert.equal(this.elm.getElementsByClassName("console-inner").length, 1);
      });
      it("should have a resizer", function() {
        assert.equal(this.elm.getElementsByClassName("resizer").length, 1);
      });
      it("should have a close button", function() {
        assert.equal(this.elm.getElementsByClassName("close-button").length, 1);
      });
    });
  });

  describe("console actions", function() {
    describe("close action", function() {
      beforeEach(function() {
        this.elm = document.createElement("div");
        this.elmId = this.elm.id = SpecHelper.randomString();
        this.stageElement.appendChild(this.elm);
        var replConsole = new REPLConsole;
        replConsole.install(this.elm);
      });

      context("click close button", function() {
        beforeEach(function() {
          var closeButton = this.elm.getElementsByClassName("close-button")[0];
          SpecHelper.triggerEvent(closeButton, "click");
        });
        it("should be removed from the parent node", function() {
          assert.isNull(document.getElementById(this.elmId));
        });
      });
    });
  });
});
<commit_msg>Add tests for REPLConsole.installInto()<commit_after>describe("REPLConsole", function() {
  SpecHelper.prepareStageElement();

  describe(".installInto()", function() {
    beforeEach(function() {
      this.elm = document.createElement('div');
      this.elm.innerHTML = '

';
      this.stageElement.appendChild(this.elm);
    });

    context("install console without options", function() {
      beforeEach(function() {
        this.console = REPLConsole.installInto('console');
      });
      it("should have data-prompt-label", function() {
        assert.equal(this.console.prompt, 'data-prompt-label');
      });
      it("should have data-remote-path", function() {
        assert.equal(this.console.remotePath, 'data-remote-path');
      });
    });

    context("install console with {remotePath: 'opt-remote-path'}", function() {
      beforeEach(function() {
        this.console = REPLConsole.installInto('console', {remotePath: 'opt-remote-path'});
      });
      it("should have opt-remote-path", function() {
        assert.equal(this.console.remotePath, 'opt-remote-path');
      });
    });
  });

  describe("#install()", function() {
    beforeEach(function() {
      this.elm = document.createElement("div");
      this.stageElement.appendChild(this.elm);
    });

    context("install console", function() {
      beforeEach(function() {
        var replConsole = new REPLConsole;
        replConsole.install(this.elm);
      });
      it("should have .console", function() {
        assert.ok(hasClass(this.elm, "console"));
      });
      it("should have a inner", function() {
        assert.equal(this.elm.getElementsByClassName("console-inner").length, 1);
      });
      it("should have a resizer", function() {
        assert.equal(this.elm.getElementsByClassName("resizer").length, 1);
      });
      it("should have a close button", function() {
        assert.equal(this.elm.getElementsByClassName("close-button").length, 1);
      });
    });
  });

  describe("console actions", function() {
    describe("close action", function() {
      beforeEach(function() {
        this.elm = document.createElement("div");
        this.elmId = this.elm.id = SpecHelper.randomString();
        this.stageElement.appendChild(this.elm);
        var replConsole = new REPLConsole;
        replConsole.install(this.elm);
      });

      context("click close button", function() {
        beforeEach(function() {
          var closeButton = this.elm.getElementsByClassName("close-button")[0];
          SpecHelper.triggerEvent(closeButton, "click");
        });
        it("should be removed from the parent node", function() {
          assert.isNull(document.getElementById(this.elmId));
        });
      });
    });
  });
});
<|endoftext|>


<commit_before>const test = require( 'unit.js' );
let guest, admin, config, user1, user2, numUsers,
  testUserName = 'fancyUser123',
  testUserEmail = 'fancyUser123@fancy.com';

describe( '19. Testing fetching users', function() {

  before( function() {
    const header = require( '../header.js' );
    guest = header.users.guest;
    admin = header.users.admin;
    user1 = header.users.user1;
    user2 = header.users.user2;
    config = header.config;
  } )

  it( 'did get the number of users before the tests begin', async function() {
    const resp = await admin.get( `/api/users` );
    test.number( resp.status ).is( 200 );
    const json = await resp.json();
    test.number( json.data.length )
    numUsers = json.data.length;
  } )

  it( 'did not allow a regular user to access the admin user details', async function() {
    const resp = await user1.get( `/api/users/${admin.username}?verbose=true` );
    test.number( resp.status ).is( 403 );
    const json = await resp.json();
    test.object( json ).hasProperty( "message" )
    test.string( json.message ).is( "You don't have permission to make this request" )
  } )

  it( 'did not allow a regular user to access another user details', async function() {
    const resp = await user2.get( `/api/users/${admin.username}?verbose=true` )
    test.number( resp.status ).is( 403 );
    const json = await resp.json();
    test.object( json ).hasProperty( "message" )
    test.string( json.message ).is( "You don't have permission to make this request" )
  } )

  it( 'did get regular users own data', async function() {
    const resp = await user1.get( `/api/users/${user1.username}?verbose=true` );
    test.number( resp.status ).is( 200 );
    const json = await resp.json();
    test.string( json._id )
    test.string( json.email ).is( user1.email )
    test.number( json.lastLoggedIn ).isNotNaN()
    test.value( json.password )
    test.value( json.registerKey )
    test.value( json.sessionId )
    test.value( json.passwordTag )
    test.string( json.username ).is( user1.username )
    test.number( json.privileges ).is( 3 );
  } )

  it( 'did have the same number of users as before the tests started', async function() {
    const resp = await admin.get( `/api/users` );
    test.number( resp.status ).is( 200 );
    const json = await resp.json();
    test.bool( json.data.length === numUsers ).isTrue();
  } )
} )<commit_msg>Added user page test<commit_after>const test = require( 'unit.js' );
let guest, admin, config, user1, user2, numUsers,
  testUserName = 'fancyUser123',
  testUserEmail = 'fancyUser123@fancy.com';

describe( '19. Testing fetching users', function() {

  before( function() {
    const header = require( '../header.js' );
    guest = header.users.guest;
    admin = header.users.admin;
    user1 = header.users.user1;
    user2 = header.users.user2;
    config = header.config;
  } )

  it( 'did get the number of users before the tests begin', async function() {
    const resp = await admin.get( `/api/users` );
    test.number( resp.status ).is( 200 );
    const json = await resp.json();
    test.number( json.data.length )
    numUsers = json.data.length;
  } )

  it( 'did not allow a regular user to access the admin user details', async function() {
    const resp = await user1.get( `/api/users/${admin.username}?verbose=true` );
    test.number( resp.status ).is( 403 );
    const json = await resp.json();
    test.object( json ).hasProperty( "message" )
    test.string( json.message ).is( "You don't have permission to make this request" )
  } )

  it( 'did not allow a regular user to access another user details', async function() {
    const resp = await user2.get( `/api/users/${admin.username}?verbose=true` )
    test.number( resp.status ).is( 403 );
    const json = await resp.json();
    test.object( json ).hasProperty( "message" )
    test.string( json.message ).is( "You don't have permission to make this request" )
  } )

  it( 'did get regular users own data', async function() {
    const resp = await user1.get( `/api/users/${user1.username}?verbose=true` );
    test.number( resp.status ).is( 200 );
    const json = await resp.json();
    test.string( json._id )
    test.string( json.email ).is( user1.email )
    test.number( json.lastLoggedIn ).isNotNaN()
    test.value( json.password )
    test.value( json.registerKey )
    test.value( json.sessionId )
    test.value( json.passwordTag )
    test.string( json.username ).is( user1.username )
    test.number( json.privileges ).is( 3 );
  } )

  it( 'did get user page information', async function() {
    const resp = await admin.get( `/api/users` );
    test.number( resp.status ).is( 200 );
    const json = await resp.json();
    test.number( json.count ).isGreaterThan( 0 )
    test.number( json.index ).is( 0 )
    test.number( json.limit ).is( 10 )
  } )

  it( 'did get client driven page information from the URL', async function() {
    const resp = await admin.get( `/api/users?limit=20&index=1` );
    test.number( resp.status ).is( 200 );
    const json = await resp.json();
    test.number( json.index ).is( 1 );
    test.number( json.limit ).is( 20 );
  } )

  it( 'did have the same number of users as before the tests started', async function() {
    const resp = await admin.get( `/api/users` );
    test.number( resp.status ).is( 200 );
    const json = await resp.json();
    test.bool( json.data.length === numUsers ).isTrue();
  } )
} )<|endoftext|>


<commit_before>/* Copyright (c) 2018 e-soa Jacques Desodt, MIT License */
'use strict'

/* Prerequisites */
const processThen = require('../../process/then')
const testFunctions = require('../functions')

/* Test prerequisites */
const Code = require('code')
const Lab = require('lab', {timeout: testFunctions.timeout})
const lab = (exports.lab = Lab.script())
const describe = lab.describe
const it = lab.it
const expect = Code.expect

describe('then replaceValuesForString', function () {
  /* Bad arguments */
  it('no args', function (fin) {
    /* Fires the test */
    var newValue = processThen.replaceValuesForString(null, null)
    /* Checks the result */
    expect(newValue).to.not.exist()
    fin()
  })
  it('no string value', function (fin) {
    /* Fires the test */
    var newValue = processThen.replaceValuesForString(null, 12345)
    /* Checks the result */
    expect(newValue).to.not.exist()
    fin()
  })
  it('no entity object', function (fin) {
    /* Fires the test */
    var newValue = processThen.replaceValuesForString(null, getValue())
    /* Checks the result */
    expect(newValue).to.equal(getValue())
    fin()
  })
  /* Patterns don't match */
  it('no pattern', function (fin) {
    /* Initializes */
    var value = 'abc'
    /* Fires the test */
    var newValue = processThen.replaceValuesForString(getEntity(), value)
    /* Checks the result */
    expect(newValue).to.equal(value)
    fin()
  })
  it('others patterns', function (fin) {
    /* Initializes */
    var value = '%other% and %another%'
    /* Fires the test */
    var newValue = processThen.replaceValuesForString(getEntity(), value)
    /* Checks the result */
    expect(newValue).to.equal(value)
    fin()
  })
  /* Patterns match */
  it('patterns match', function (fin) {
    /* Fires the test */
    var newValue = processThen.replaceValuesForString(getEntity(), getValue())
    /* Checks the result */
    expect(newValue).to.equal('My kingdom for a bottle!')
    fin()
  })
})

/* ---------- FUNCTIONS ---------- */

function getEntity () {
  return {
    command: 'test',
    data: {
      id: '123'
    },
    product: 'bottle',
    role: 'kingdom'
  }
}

function getValue () {
  return 'My %role% for a %product%!'
}
<commit_msg>This project has been moved to GitLab<commit_after><|endoftext|>