"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const os_1 = __importDefault(require("os"));
const logger_1 = __importDefault(require("../logger"));
const handlebars_1 = __importDefault(require("handlebars"));
/**
* Parser class for GRPC Protocol mocks to define handlers for:
* - Unary calls
* - Server streaming calls
* - Client streaming calls
* - Bidirectional streaming calls
*/
class GrpcParser {
/**
*
* @param {string} grpcMocksDir location of mocks dir for grpc mocks
*/
constructor(grpcMocksDir) {
/**
* - Get the path of the determined handler from the call
* - Find a mock file for the handler
* - If mock file exists, apply handler compilation to generate actual values from helpers
* - Execute callback with the response and delay
* - Remove delay key if present before sending the response
* - If mock file is not found, log error and send the same error to client
* @param {any} call call object recieved with every unary call
* @param {any} callback callback to be executed once server is ready to return response
*/
this.camouflageMock = (call, callback) => {
try {
let handlerPath = call.call.handler.path;
let mockFile = handlerPath.replace(".", "/");
let mockFilePath = path_1.default.join(this.grpcMocksDir, mockFile + ".mock");
if (fs_1.default.existsSync(mockFilePath)) {
const template = handlebars_1.default.compile(fs_1.default.readFileSync(mockFilePath, "utf-8").toString());
const fileContent = template({ request: call.request });
logger_1.default.debug(`Mock file path: ${mockFilePath}`);
logger_1.default.debug(`Response: ${fileContent}`);
const response = JSON.parse(fileContent);
const delay = response.delay || 0;
delete response.delay;
setTimeout(() => {
callback(null, response);
}, delay);
}
else {
logger_1.default.error(`No suitable mock file was found for ${mockFilePath}`);
callback(null, { error: `No suitable mock file was found for ${mockFilePath}` });
}
}
catch (error) {
logger_1.default.error(error);
callback(null, { error: error });
}
};
/**
* - Get the path of the determined handler from the call
* - Find a mock file for the handler
* - If mock file exists, apply handler compilation to generate actual values from helpers
* - Split the contents of file with ==== to get responses each stream
* - Run a forEach and execute call.write() with the response and delay
* - On last index of streamArray, execute call.end()
* - Remove delay key if present before sending the response
* - If mock file is not found, log error and send the same error to client
* @param {any} call call object recieved with every unary call
* @param {any} callback callback to be executed once server is ready to return response
*/
this.camouflageMockServerStream = (call) => {
let handlerPath = call.call.handler.path;
let mockFile = handlerPath.replace(".", "/");
let mockFilePath = path_1.default.join(this.grpcMocksDir, mockFile + ".mock");
if (fs_1.default.existsSync(mockFilePath)) {
try {
const template = handlebars_1.default.compile(fs_1.default.readFileSync(mockFilePath, "utf-8").toString());
const fileContent = template({ request: call.request });
logger_1.default.debug(`Mock file path: ${mockFilePath}`);
let streamArr = fileContent.split("====");
let delay = 0;
streamArr.forEach((stream, index) => {
let parsedStream = JSON.parse(stream.replace(os_1.default.EOL, ""));
delay = delay + (parsedStream.delay || 0);
delete parsedStream["delay"];
logger_1.default.debug(`Sending stream: ${JSON.stringify(parsedStream, null, 2)}`);
logger_1.default.debug(`Sending stream with delay of: ${delay}`);
switch (index) {
case streamArr.length - 1:
setTimeout(() => {
call.write(JSON.parse(stream));
call.end();
}, delay);
break;
default:
setTimeout(() => {
call.write(JSON.parse(stream));
}, delay);
break;
}
});
}
catch (error) {
logger_1.default.error(error);
call.end();
}
}
else {
logger_1.default.error(`No suitable mock file was found for ${mockFilePath}`);
call.write({ error: `No suitable mock file was found for ${mockFilePath}` });
call.end();
}
};
/**
* - Get the path of the determined handler from the call
* - Find a mock file for the handler
* - If mock file exists, apply handler compilation to generate actual values from helpers
* - No action required on recieving client's streams
* - Once client calls end, respond with the compiled contents of the mockfile and delay
* - Remove delay key if present before sending the response
* - If mock file is not found, log error and send the same error to client
* @param {any} call call object recieved with every unary call
* @param {any} callback callback to be executed once server is ready to return response
*/
this.camouflageMockClientStream = (call, callback) => {
call.on("data", () => {
// TODO: Not sure if it's needed
});
call.on("end", () => {
try {
let handlerPath = call.call.handler.path;
let mockFile = handlerPath.replace(".", "/");
let mockFilePath = path_1.default.join(this.grpcMocksDir, mockFile + ".mock");
if (fs_1.default.existsSync(mockFilePath)) {
const template = handlebars_1.default.compile(fs_1.default.readFileSync(mockFilePath, "utf-8").toString());
const fileContent = template({ request: call.request });
logger_1.default.debug(`Mock file path: ${mockFilePath}`);
logger_1.default.debug(`Response: ${fileContent}`);
const response = JSON.parse(fileContent);
const delay = response.delay || 0;
delete response.delay;
setTimeout(() => {
callback(null, response);
}, delay);
}
else {
logger_1.default.error(`No suitable mock file was found for ${mockFilePath}`);
callback(null, { error: `No suitable mock file was found for ${mockFilePath}` });
}
}
catch (error) {
logger_1.default.error(error);
callback(null, { error: error });
}
});
};
/**
* - Get the path of the determined handler from the call
* - Find a mock file for the handler
* - If mock file exists, apply handler compilation to generate actual values from helpers
* - Follow a ping pong model, i.e. for every client's stream, respond with a server stream.
* - On client stream, respond with filecontent.data
* - Once client calls end, respond with filecontent.end
* - Remove delay key if present before sending the response
* - If mock file is not found, log error and send the same error to client
* @param {any} call call object recieved with every unary call
* @param {any} callback callback to be executed once server is ready to return response
*/
this.camouflageMockBidiStream = (call) => {
let handlerPath = call.call.handler.path;
let mockFile = handlerPath.replace(".", "/");
let mockFilePath = path_1.default.join(this.grpcMocksDir, mockFile + ".mock");
call.on("data", () => {
if (fs_1.default.existsSync(mockFilePath)) {
try {
const template = handlebars_1.default.compile(fs_1.default.readFileSync(mockFilePath, "utf-8").toString());
const fileContent = template({ request: call.request });
logger_1.default.debug(`Mock file path: ${mockFilePath}`);
logger_1.default.debug(`Response: ${fileContent}`);
const response = JSON.parse(fileContent);
const delay = response.data.delay || 0;
delete response.data.delay;
setTimeout(() => {
call.write(response.data);
}, delay);
}
catch (error) {
logger_1.default.error(error);
call.end();
}
}
else {
logger_1.default.error(`No suitable mock file was found for ${mockFilePath}`);
call.write({ error: `No suitable mock file was found for ${mockFilePath}` });
call.end();
}
});
call.on("end", () => {
if (fs_1.default.existsSync(mockFilePath)) {
try {
const template = handlebars_1.default.compile(fs_1.default.readFileSync(mockFilePath, "utf-8").toString());
const fileContent = template({ request: call.request });
logger_1.default.debug(`Mock file path: ${mockFilePath}`);
logger_1.default.debug(`Response: ${fileContent}`);
const response = JSON.parse(fileContent);
if (response.end) {
const delay = response.end.delay || 0;
delete response.end.delay;
setTimeout(() => {
call.write(response.end);
call.end();
}, delay);
}
else {
call.end();
}
}
catch (error) {
logger_1.default.error(error);
call.end();
}
}
else {
logger_1.default.error(`No suitable mock file was found for ${mockFilePath}`);
call.write({ error: `No suitable mock file was found for ${mockFilePath}` });
call.end();
}
});
};
this.grpcMocksDir = grpcMocksDir;
}
}
exports.default = GrpcParser;
//# sourceMappingURL=GrpcParser.js.map