UNPKG

zester_utils

Version:

Utilities for writing tests to run using zester

278 lines (218 loc) 6.32 kB
const mqc = require('mysql_query_collector') const http = require('http') const dgram = require('dgram') const net = require('net') const traverse = require('object-traversal').traverse const expr = require('node-expr') //const m = require('data-matching'); //const sm = require('string-matching') const deasync = require('deasync') const _ = require('lodash') const _collected_data = {} var _interpolation_dict = null //const traverseTemplate = require('traverse-template') const eval_handlebars = (obj) => { function scan_and_interpolate({ parent, key, value, meta }) { if (typeof value === 'string') { var res = value.replace(/{{(.+?)}}/g, function(match, contents, offset, input_string) { //console.log("got ", contents) var e = new expr.Expr(contents) return e.test(_interpolation_dict) }) parent[key] = res } } traverse(obj, scan_and_interpolate) } const types = require('mysql/lib/protocol/constants/types.js') const querystringParse = require("querystring").parse const nodeRedisProtocol = require('node-redis-protocol') const redisProto = require('redis-proto') var send_dbquery_reply = (conn, reply) => { //console.log("before", reply) eval_handlebars(reply) //console.log("after", reply) mqc.send_reply(conn, reply) } var send_init_db_reply = (conn, reply) => { eval_handlebars(reply) mqc.send_reply(conn, reply) } var send_http_reply = (res, reply) => { eval_handlebars(reply) res.writeHead(reply.status, reply.headers) if(_.some(reply.headers, (v,k) => v.toLowerCase() == 'application/json')) { res.end(JSON.stringify(reply.body)) } else { res.end(reply.body) } } var send_udp_reply = (socket, rinfo, reply) => { eval_handlebars(reply) socket.send(reply.body, rinfo.port, rinfo.address, err => { if(err) { throw `Error when sending UDP packet ${reply} to ${rinfo.address}:${rinfo.port}: ${err}` } }); } var send_redis_reply = (socket, reply) => { eval_handlebars(reply) var data = redisProto.encode(reply.body) //console.log("send_redis_reply: data=" + data) if(Array.isArray(reply.body)) { socket.write("*1\r\n", err => { if(err) { throw `Error when writing TCP packet ${data}: ${err}` } socket.write(data, err => { if(err) { throw `Error when writing TCP packet ${data}: ${err}` } }); }); } else { socket.write(data, err => { if(err) { throw `Error when writing TCP packet ${data}: ${err}` } }); } } module.exports = { setup: (servers, event_cb, interpolation_dict) => { _interpolation_dict = interpolation_dict var mysql_servers = servers.filter(s => s.type == 'mysql') var http_servers = servers.filter(s => s.type == 'http') var udp_servers = servers.filter(s => s.type == 'udp') var redis_servers = servers.filter(s => s.type == 'redis') var ready_servers = 0; var update_ready_servers = c => { ready_servers += c } mqc.setup(mysql_servers, () => { update_ready_servers(mysql_servers.length) }, (conn, server, query) => { //console.debug(`Simulated MySQL server ${server_name} got query: ${query}`) var evt = { name: 'dbquery_request', server: server.name, query: query, conn: conn, } event_cb(evt) return null }, (conn, server, database_name) => { var evt = { name: 'init_db_request', server: server.name, database_name: database_name, conn: conn, } event_cb(evt) //return {type: 'ok'} return null } ) http_servers.forEach(server => { var post_http_request = (server, req, res, body, event_cb) => { req_clone = { ...req, headers: { ...req.headers } } // need to clone the object and force req.headers to be realized as new node versions changed it use a getter function or proxy object req_clone.body = body var evt = { name: 'http_request', server: server.name, req: req_clone, res: res, } event_cb(evt) } var s = http.createServer((req, res) => { var data = "" var content_type = req.headers['content-type'] req.on('data', function(chunk) { data += chunk.toString() }) req.on('end', function() { var body switch(content_type) { case 'application/json': body = JSON.parse(data) break case 'application/x-www-form-urlencoded': body = querystringParse(data) break default: body = data break } post_http_request(server, req, res, body, event_cb) }) }) s.listen({ host: server.address, port: server.port, }) s.on('error', function (e) { throw e }); s.on('listening', function (e) { //console.debug(`HTTP server ${server.name} created. Listening ${server.host}:${server.port}`) update_ready_servers(1) }); }) udp_servers.forEach(server => { var socket = dgram.createSocket('udp4'); socket.on('error', err => { throw `server ${server.name} error:\n${err.stack}` }); socket.on('message', (msg, rinfo) => { msg = msg.toString() //console.debug(`server got: ${msg} (${typeof msg}) from ${rinfo.address}:${rinfo.port}`) // event_cb({ name: 'udp_request', server: server.name, msg: msg, rinfo: rinfo, socket: socket, }) }); socket.on('listening', () => { //console.debug(`UDP server ${server.name} listening ${server.host}:${server.port}`) update_ready_servers(1) }); socket.bind(server.port, server.host); }) redis_servers.forEach(server => { var s = net.createServer(socket => { var rp = new nodeRedisProtocol.ResponseParser() rp.on('response', response => { event_cb({ name: 'redis_msg', server: server.name, msg: response, socket: socket, }) }) socket.on('error', err => { throw `server ${server.name} error:\n${err.stack}` }) socket.on('data', data => { rp.parse(data) }) }) s.listen(server.port, server.host) s.on('listening', () => { update_ready_servers(1) }) }) deasync.loopWhile(() => ready_servers != servers.length) }, send_dbquery_reply: send_dbquery_reply, send_init_db_reply: send_init_db_reply, send_http_reply: send_http_reply, send_udp_reply: send_udp_reply, send_redis_reply: send_redis_reply, }