scc-integration-tests
Version:
Integration tests for SCC
260 lines (233 loc) • 9.01 kB
JavaScript
let childProcess = require('child_process');
let exec = childProcess.exec;
let fork = childProcess.fork;
let uuid = require('uuid');
let path = require('path');
function InstanceManager(config) {
this.config = config;
this.activeDockerInstanceList = [];
this.activeNodeInstanceMap = {};
this.absoluteControllerPath = path.join(__dirname, 'controllers');
this.count = 0;
}
InstanceManager.prototype.launchSCCInstance = function (instanceType, externalPort, instanceName, stateServerHost) {
stateServerHost = stateServerHost || '127.0.0.1';
let instanceTypeConfig = this.config[instanceType];
return new Promise((resolve, reject) => {
let volumeFlag = '';
let envFlag = '';
if (instanceType !== 'state') {
envFlag = ` -e "SCC_STATE_SERVER_HOST=${stateServerHost}"`;
if (instanceType === 'regular') {
envFlag += ` -e "SOCKETCLUSTER_MASTER_CONTROLLER=/usr/src/app/server.js"`;
envFlag += ` -e "SOCKETCLUSTER_WORKER_CONTROLLER=/usr/src/app/worker.js"`;
envFlag += ` -e "SOCKETCLUSTER_BROKER_CONTROLLER=/usr/src/app/broker.js"`;
volumeFlag = ` -v ${this.absoluteControllerPath}:/usr/src/app/`;
}
}
// console.log('Launching SCC instance:', `docker run -d -p ${externalPort}:${instanceTypeConfig.internalContainerPort}${volumeFlag}${envFlag} --name ${instanceName} ${instanceTypeConfig.imageName}:${instanceTypeConfig.versionTag}`);
let instanceProcess = exec(`docker run -d -p ${externalPort}:${instanceTypeConfig.internalContainerPort}${volumeFlag}${envFlag} --name ${instanceName} ${instanceTypeConfig.imageName}:${instanceTypeConfig.versionTag}`, (err) => {
if (err) {
reject(err);
} else {
this.activeDockerInstanceList.push(instanceName);
resolve(instanceProcess);
}
});
});
};
InstanceManager.prototype.stopSCCInstance = function (instanceName) {
return new Promise((resolve, reject) => {
// console.log('Stopping SCC instance:', `docker stop -t 0 ${instanceName}`);
exec(`docker stop -t 0 ${instanceName}`, (err) => {
if (err) {
reject(err);
} else {
this.activeDockerInstanceList = this.activeDockerInstanceList.filter((curInstanceName) => {
return curInstanceName !== instanceName;
});
resolve();
}
});
});
};
InstanceManager.prototype.getRunningInstanceNames = function () {
return new Promise((resolve, reject) => {
exec(`docker ps --format '{{.Names}}'`, (err, stdout) => {
if (err) {
reject(err);
} else {
resolve(stdout.split('\n'));
}
});
});
};
InstanceManager.prototype.isInstanceRunning = async function (instanceName) {
let instanceNameList = await this.getRunningInstanceNames();
return instanceNameList.indexOf(instanceName) !== -1;
};
function removeSCCInstance(instanceName) {
return new Promise((resolve, reject) => {
exec(`docker rm ${instanceName}`, (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
};
InstanceManager.prototype.destroySCCInstance = async function (instanceName) {
await this.stopSCCInstance(instanceName);
await this.removeSCCInstance(instanceName);
};
InstanceManager.prototype.destroyAllSCCInstances = function () {
let destroyInstanceListPromises = this.activeDockerInstanceList.map((instanceName) => {
return this.destroySCCInstance(instanceName);
});
return Promise.all(destroyInstanceListPromises);
};
InstanceManager.prototype.stopAllDockerInstances = function () {
return new Promise((resolve, reject) => {
exec(`docker stop -t 0 $(docker ps -a -q)`, (err) => {
resolve();
});
});
};
InstanceManager.prototype.removeAllDockerInstances = function () {
return new Promise((resolve, reject) => {
exec(`docker rm $(docker ps -a -q)`, (err) => {
resolve();
});
});
};
InstanceManager.prototype.destroyAllDockerInstances = async function () {
await this.stopAllDockerInstances();
await this.removeAllDockerInstances();
};
InstanceManager.prototype.getDockerInstanceIP = function (instanceName) {
return new Promise((resolve, reject) => {
exec(`docker inspect -f "{{.NetworkSettings.IPAddress}}" ${instanceName}`, (err, stdout) => {
if (err) {
reject(err);
} else {
resolve(stdout.split('\n')[0]);
}
});
});
};
InstanceManager.prototype.generateSCCInstanceName = function (instanceType) {
return `scc-${instanceType}-` + this.count++;
};
InstanceManager.prototype.generateSCCInstanceClusterDetailsList = function (options) {
let instanceDetailList = [];
let stateInstanceStartPort = options.stateInstanceStartPort || 7777;
let regularInstanceStartPort = options.regularInstanceStartPort || 8000;
let brokerInstanceStartPort = options.brokerInstanceStartPort || 8888;
instanceDetailList.push({
type: 'state',
name: this.generateSCCInstanceName('state'),
port: stateInstanceStartPort
});
for (let i = 0; i < options.regularInstanceCount; i++) {
instanceDetailList.push({
type: 'regular',
name: this.generateSCCInstanceName('regular'),
port: regularInstanceStartPort + i
});
}
for (let i = 0; i < options.brokerInstanceCount; i++) {
instanceDetailList.push({
type: 'broker',
name: this.generateSCCInstanceName('broker'),
port: brokerInstanceStartPort + i
});
}
return instanceDetailList;
};
InstanceManager.prototype.waitForTimeout = function (delay) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, delay);
});
};
InstanceManager.prototype.launchSCCInstanceCluster = async function (clusterDetailsList, readyDelay) {
let stateInstanceDetails = clusterDetailsList.filter((instanceDetails) => {
return instanceDetails.type === 'state';
})[0];
await this.launchSCCInstance(stateInstanceDetails.type, stateInstanceDetails.port, stateInstanceDetails.name);
let stateInstanceIP = await this.getDockerInstanceIP(stateInstanceDetails.name);
let otherInstanceDetailsList = clusterDetailsList.filter((instanceDetails) => {
return instanceDetails.type !== 'state';
});
let launchInstancePromises = otherInstanceDetailsList.map((instanceDetails) => {
return this.launchSCCInstance(instanceDetails.type, instanceDetails.port, instanceDetails.name, stateInstanceIP);
});
await Promise.all(launchInstancePromises);
if (readyDelay) {
await this.waitForTimeout(readyDelay);
}
return {
stateInstanceIP: stateInstanceIP
};
};
InstanceManager.prototype.launchSubscriberNodeInstance = function (instanceName, options) {
let optionsString = JSON.stringify(options || {});
let args = ['--options', optionsString];
return new Promise((resolve, reject) => {
let instanceProcess = fork(this.config.subscriberInstancePath, args);
instanceProcess.on('error', (err) => {
instanceProcess.removeAllListeners('error');
instanceProcess.removeAllListeners('message');
reject(err);
});
instanceProcess.receivedMessages = [];
instanceProcess.on('message', (message) => {
if (message.type === 'ready') {
instanceProcess.removeAllListeners('error');
resolve(instanceProcess);
} else if (message.type === 'received') {
instanceProcess.receivedMessages.push(message);
}
});
instanceProcess.instanceName = instanceName;
this.activeNodeInstanceMap[instanceName] = instanceProcess;
});
};
InstanceManager.prototype.launchPublisherNodeInstance = function (instanceName, options) {
let optionsString = JSON.stringify(options || {});
let args = ['--options', optionsString];
return new Promise((resolve, reject) => {
let instanceProcess = fork(this.config.publisherInstancePath, args);
instanceProcess.on('error', (err) => {
instanceProcess.removeAllListeners('error');
instanceProcess.removeAllListeners('message');
reject(err);
});
instanceProcess.sentMessages = [];
instanceProcess.failedToSendMessages = [];
instanceProcess.on('message', (message) => {
if (message.type === 'ready') {
instanceProcess.removeAllListeners('error');
resolve(instanceProcess);
} else if (message.type === 'sent') {
instanceProcess.sentMessages.push(message);
} else if (message.type === 'failedToSend') {
instanceProcess.failedToSendMessages.push(message);
}
});
instanceProcess.instanceName = instanceName;
this.activeNodeInstanceMap[instanceName] = instanceProcess;
});
};
InstanceManager.prototype.destroyNodeInstance = function (instanceName) {
this.activeNodeInstanceMap[instanceName].kill();
delete this.activeNodeInstanceMap[instanceName];
};
InstanceManager.prototype.destroyAllNodeInstances = function (instanceName) {
Object.keys(this.activeNodeInstanceMap).forEach((instanceName) => {
this.destroyNodeInstance(instanceName);
});
};
module.exports = InstanceManager;