From eba61effa0f7d467585a2231a38c5bb1118ae92c Mon Sep 17 00:00:00 2001 From: re-Tick Date: Sat, 18 Mar 2023 14:22:38 +0530 Subject: [PATCH 1/2] fix(src/utils): adds ctx parameter in processDep the executionContext was getting undefined for mocking dependency call outputs Signed-off-by: re-Tick --- integrations/mongoose/delete.ts | 8 ++++---- integrations/mongoose/find.ts | 8 ++++---- integrations/mongoose/insert.ts | 8 ++++---- integrations/mongoose/update.ts | 8 ++++---- integrations/node-fetch/require.ts | 2 +- integrations/octokit/require.ts | 2 +- package.json | 2 +- src/util.ts | 22 +++++++++++++--------- 8 files changed, 32 insertions(+), 28 deletions(-) diff --git a/integrations/mongoose/delete.ts b/integrations/mongoose/delete.ts index 1040c0c..a6ae421 100644 --- a/integrations/mongoose/delete.ts +++ b/integrations/mongoose/delete.ts @@ -35,7 +35,7 @@ export function kDeleteOne(...args) { // wrap callback of updateOne to capture the mongodb-native-driver outputs // @ts-ignore args[args.length - 1] = function (...outputs) { - ProcessDep(meta, ...outputs); + ProcessDep(ctx, meta, ...outputs); // calls the actual mongoose callback for findOne callback.apply(this, outputs); }; @@ -50,7 +50,7 @@ export function kDeleteOne(...args) { if (typeof callback === "function") { // mocked outputs of updateOne opperation const outputs: any[] = [null, {}]; - const mocks = ProcessDep(meta, ...outputs); + const mocks = ProcessDep(ctx, meta, ...outputs); // calls the actual mongoose callback for findOne // @ts-ignore callback.apply(this, mocks); @@ -102,7 +102,7 @@ export function kDeleteMany(...args) { // wrap callback of deleteMany to capture the mongodb-native-driver outputs // @ts-ignore args[args.length - 1] = function (...outputs) { - ProcessDep(meta, ...outputs); + ProcessDep(ctx, meta, ...outputs); // calls the actual mongoose callback for findOne callback.apply(this, outputs); }; @@ -117,7 +117,7 @@ export function kDeleteMany(...args) { if (typeof callback === "function") { // mocked outputs of deleteMany opperation const outputs: any[] = [null, {}]; - const mocks = ProcessDep(meta, ...outputs); + const mocks = ProcessDep(ctx, meta, ...outputs); // calls the actual mongoose callback for findOne // @ts-ignore callback.apply(this, mocks); diff --git a/integrations/mongoose/find.ts b/integrations/mongoose/find.ts index 25099fb..c400b15 100644 --- a/integrations/mongoose/find.ts +++ b/integrations/mongoose/find.ts @@ -35,7 +35,7 @@ export function kFindOne(...args) { // wrap callback of findOne to capture the mongodb-native-driver outputs // @ts-ignore args[args.length - 1] = function (...outputs) { - ProcessDep(meta, ...outputs); + ProcessDep(ctx, meta, ...outputs); // calls the actual mongoose callback for findOne callback.apply(this, outputs); }; @@ -51,7 +51,7 @@ export function kFindOne(...args) { if (typeof callback === "function") { // mocked outputs of findOne opperation const outputs: any[] = [null, {}]; - const mocks = ProcessDep(meta, ...outputs); + const mocks = ProcessDep(ctx, meta, ...outputs); // calls the actual mongoose callback for findOne // @ts-ignore callback.apply(this, mocks); @@ -110,7 +110,7 @@ export function kFind(...args) { // call the actual toArray method of cursor const result = await actualToArray.apply(outputs[1], cb); // encode and stores the documents in executionContext - ProcessDep(meta, outputs[0], result); + ProcessDep(ctx, meta, outputs[0], result); // calls the actual user defined callback cb(outputs[0], result); return result; @@ -135,7 +135,7 @@ export function kFind(...args) { const outputs = [null, {}]; let result: any[] = []; // returns the mocked outputs of find call - const mocks = ProcessDep(meta, outputs[0], result); + const mocks = ProcessDep(ctx, meta, outputs[0], result); if (mocks !== undefined && mocks.length == 2) { result = mocks[1]; outputs[0] = mocks[0]; diff --git a/integrations/mongoose/insert.ts b/integrations/mongoose/insert.ts index cc53319..7bc169d 100644 --- a/integrations/mongoose/insert.ts +++ b/integrations/mongoose/insert.ts @@ -34,7 +34,7 @@ export function kInsertMany(...args) { // wrap callback of insertMany to capture the mongodb-native-driver outputs // @ts-ignore args[args.length - 1] = function (...outputs) { - ProcessDep(meta, ...outputs); + ProcessDep(ctx, meta, ...outputs); // calls the actual mongoose callback for findOne callback.apply(this, outputs); }; @@ -49,7 +49,7 @@ export function kInsertMany(...args) { if (typeof callback === "function") { // mocked outputs of insertMany opperation const outputs: any[] = [null, {}]; - const mocks = ProcessDep(meta, ...outputs); + const mocks = ProcessDep(ctx, meta, ...outputs); // calls the actual mongoose callback for findOne // @ts-ignore callback.apply(this, mocks); @@ -100,7 +100,7 @@ export function kInsertOne(...args) { // wrap callback of insertOne to capture the mongodb-native-driver outputs // @ts-ignore args[args.length - 1] = function (...outputs) { - ProcessDep(meta, ...outputs); + ProcessDep(ctx, meta, ...outputs); // calls the actual mongoose callback for findOne callback.apply(this, outputs); }; @@ -115,7 +115,7 @@ export function kInsertOne(...args) { if (typeof callback === "function") { // mocked outputs of insertOne opperation const outputs: any[] = [null, {}]; - const mocks = ProcessDep(meta, ...outputs); + const mocks = ProcessDep(ctx, meta, ...outputs); // calls the actual mongoose callback for findOne // @ts-ignore callback.apply(this, mocks); diff --git a/integrations/mongoose/update.ts b/integrations/mongoose/update.ts index 84caaed..19f737d 100644 --- a/integrations/mongoose/update.ts +++ b/integrations/mongoose/update.ts @@ -34,7 +34,7 @@ export function kUpdateOne(...args) { // wrap callback of updateOne to capture the mongodb-native-driver outputs // @ts-ignore args[args.length - 1] = function (...outputs) { - ProcessDep(meta, ...outputs); + ProcessDep(ctx, meta, ...outputs); // calls the actual mongoose callback for findOne callback.apply(this, outputs); }; @@ -49,7 +49,7 @@ export function kUpdateOne(...args) { if (typeof callback === "function") { // mocked outputs of updateOne opperation const outputs: any[] = [null, {}]; - const mocks = ProcessDep(meta, ...outputs); + const mocks = ProcessDep(ctx, meta, ...outputs); // calls the actual mongoose callback for findOne // @ts-ignore callback.apply(this, mocks); @@ -102,7 +102,7 @@ export function kUpdateMany(...args) { // wrap callback of updateMany to capture the mongodb-native-driver outputs // @ts-ignore args[args.length - 1] = function (...outputs) { - ProcessDep(meta, ...outputs); + ProcessDep(ctx, meta, ...outputs); // calls the actual mongoose callback for findOne callback.apply(this, outputs); }; @@ -117,7 +117,7 @@ export function kUpdateMany(...args) { if (typeof callback === "function") { // mocked outputs of updateMany opperation const outputs: any[] = [null, {}]; - const mocks = ProcessDep(meta, ...outputs); + const mocks = ProcessDep(ctx, meta, ...outputs); // calls the actual mongoose callback for findOne // @ts-ignore callback.apply(this, mocks); diff --git a/integrations/node-fetch/require.ts b/integrations/node-fetch/require.ts index 30a76d0..9e19ae7 100644 --- a/integrations/node-fetch/require.ts +++ b/integrations/node-fetch/require.ts @@ -133,7 +133,7 @@ export function wrappedNodeFetch(fetch: any) { } ctx.mocks.shift(); } else { - ProcessDep({}, outputs); + ProcessDep(ctx, {}, outputs); } rinit.headers = new Headers(outputs[1].headers); rinit.status = outputs[1].status; diff --git a/integrations/octokit/require.ts b/integrations/octokit/require.ts index 3d92460..6b2c19a 100644 --- a/integrations/octokit/require.ts +++ b/integrations/octokit/require.ts @@ -189,7 +189,7 @@ export function wrappedNodeFetch(fetchFunc: Function) { } ctx.mocks.shift(); } else { - ProcessDep({}, outputs); + ProcessDep(ctx, {}, outputs); } rinit.headers = new Headers(outputs[1].headers); rinit.status = outputs[1].status; diff --git a/package.json b/package.json index 8ea57c5..59a6909 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "commit": "cz" }, "repository": "git@github.com:keploy/typescript-sdk.git", - "author": "Rajat Sharma ", + "author": "Keploy ", "license": "MIT", "devDependencies": { "@commitlint/cli": "^16.2.1", diff --git a/src/util.ts b/src/util.ts index 3e22de0..885e0e3 100644 --- a/src/util.ts +++ b/src/util.ts @@ -25,15 +25,19 @@ const transformToSnakeCase = (obj: any): object => { export { transformToSnakeCase }; -export function ProcessDep(meta: { [key: string]: string }, ...outputs: any[]) { - if ( - getExecutionContext() == undefined || - getExecutionContext().context == undefined - ) { - console.error("keploy context is not present to mock dependencies"); - return; - } - const kctx = getExecutionContext().context; +export function ProcessDep( + kctx: any, + meta: { [key: string]: string }, + ...outputs: any[] +) { + // if ( + // getExecutionContext() == undefined || + // getExecutionContext().context == undefined + // ) { + // console.error("keploy context is not present to mock dependencies"); + // return; + // } + // const kctx = getExecutionContext().context; switch (kctx.mode) { case "record": const res: DataBytes[] = []; From e5e2111df8237878358f0feb79e0716a73586b21 Mon Sep 17 00:00:00 2001 From: re-Tick Date: Mon, 10 Apr 2023 14:21:48 +0530 Subject: [PATCH 2/2] fix(mock): returns a promise to sync the mocks in ctx Signed-off-by: re-Tick --- mock/mock.ts | 128 +++++++++++++++++++++++++++---------------------- mock/utils.ts | 7 ++- src/context.ts | 6 +-- 3 files changed, 78 insertions(+), 63 deletions(-) diff --git a/mock/mock.ts b/mock/mock.ts index 0712a43..94cdfd4 100644 --- a/mock/mock.ts +++ b/mock/mock.ts @@ -4,7 +4,7 @@ import * as protoLoader from "@grpc/proto-loader"; import path, { resolve } from "path"; import { ProtoGrpcType } from "../proto/services"; import Mode, { MODE_TEST } from "../src/mode"; -import { createExecutionContext, getExecutionContext } from "../src/context"; +import { createExecutionContext } from "../src/context"; import { startRecordingMocks } from "./utils"; const PORT = 6789; @@ -26,12 +26,26 @@ export interface Config { Path: string; Mode: string; } -export function NewContext(conf: Config) { + +// NewContext is used to populate the context to mock/capture the dependency calls. +// Since, grpc unary calls are made, Promise is returned to sync the outputs +// before the external dependency calls from unit tests. +export function NewContext(conf: Config): Promise { const mode = new Mode(); - let path = conf !== undefined && conf.Path !== undefined ? conf.Path : ""; - // default mode: TEST + // default mode should be TEST mode.SetMode(MODE_TEST); + if ( + process.env.KEPLOY_MODE !== undefined && + Mode.Valid(process.env.KEPLOY_MODE) + ) { + mode.SetMode(process.env.KEPLOY_MODE); + } + // mode mostly dependent on conf.Mode + if (Mode.Valid(conf.Mode)) { + mode.SetMode(conf.Mode); + } + let path = conf !== undefined && conf.Path !== undefined ? conf.Path : ""; if (path === "") { try { path = process.cwd(); @@ -50,53 +64,6 @@ export function NewContext(conf: Config) { path += "/mocks"; mockPath = path; - if ( - process.env.KEPLOY_MODE !== undefined && - Mode.Valid(process.env.KEPLOY_MODE) - ) { - // if (process.) - mode.SetMode(process.env.KEPLOY_MODE); - } - // mode mostly dependent on conf.Mode - if (Mode.Valid(conf.Mode)) { - mode.SetMode(conf.Mode); - } - switch (mode.GetMode()) { - case "test": - if (conf.Name === "") { - console.log( - "🚨 Please enter the auto generated name to mock the dependencies using Keploy." - ); - } - createExecutionContext({ - mode: mode.GetMode(), - testId: conf.Name, - mocks: [], - fileExport: true, - }); - const ctx = getExecutionContext().context; - grpcClient.GetMocks({ Path: path, Name: conf.Name }, (err, response) => { - if (err) { - console.error(err); - return; - } - ctx.mocks = response?.Mocks; - return response; - }); - break; - case "record": - createExecutionContext({ - mode: mode.GetMode(), - testId: conf.Name, - mocks: [], - fileExport: true, - }); - break; - default: - console.log("Keploy mode: (", mode.GetMode(), ") is not a valid mode"); - break; - } - let name = ""; if (conf.Name !== "") { name = "for " + conf.Name; @@ -108,10 +75,57 @@ export function NewContext(conf: Config) { name, ".\n If you dont see any logs about your dependencies below, your dependency/s are NOT wrapped.\n" ); - startRecordingMocks( - path + "/" + conf.Name + ".yaml", - mode.GetMode(), - name, - conf.Name - ); + const ctx: { mode: string; testId: string; fileExport: boolean; mocks: any } = + { + mode: mode.GetMode(), + testId: conf.Name, + fileExport: true, + mocks: [], + }; + switch (mode.GetMode()) { + case "test": + if (conf.Name === "") { + console.log( + "🚨 Please enter the auto generated name to mock the dependencies using Keploy." + ); + } + createExecutionContext(ctx); + case "record": + createExecutionContext(ctx); + } + + // returns Promise to sync the outputs from the grpc unary calls + return new Promise((rsolve, reject) => { + switch (mode.GetMode()) { + case "test": + grpcClient.GetMocks( + { Path: path, Name: conf.Name }, + (err, response) => { + if (err) { + console.error(err); + reject(err); + return; + } + ctx.mocks = response?.Mocks; + rsolve("passed"); + return response; + } + ); + break; + case "record": + startRecordingMocks( + path + "/" + conf.Name + ".yaml", + mode.GetMode(), + name, + conf.Name, + rsolve, + reject + ); + break; + default: + console.log("Keploy mode: (", mode.GetMode(), ") is not a valid mode"); + reject(`Keploy mode: (${mode.GetMode()}) is not a valid mode`); + break; + } + }); } diff --git a/mock/utils.ts b/mock/utils.ts index cbeee52..5a7ae64 100644 --- a/mock/utils.ts +++ b/mock/utils.ts @@ -1,4 +1,3 @@ -import { response } from "express"; import { Mock } from "../proto/services/Mock"; import { grpcClient, MockIds, mockPath } from "./mock"; @@ -20,7 +19,9 @@ export function startRecordingMocks( path: string, mode: string, name: string, - mockId: string + mockId: string, + resolve: (value: string | PromiseLike) => void, + reject: (reason?: string) => void ) { grpcClient.StartMocking( { @@ -30,6 +31,7 @@ export function startRecordingMocks( function (err, response) { if (err !== null) { console.error("failed to start mocking due to error: ", err); + reject(`failed to start mocking due to error: ${err}`); return; } if (response?.Exists) { @@ -42,6 +44,7 @@ export function startRecordingMocks( ); MockIds[mockId] = true; } + resolve("Passed"); } ); } diff --git a/src/context.ts b/src/context.ts index 120fdac..6bb2d97 100644 --- a/src/context.ts +++ b/src/context.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -/* eslint-disable @typescript-eslint/no-explicit-any */ import asyncHooks from "async_hooks"; const executionContextMap = new Map(); @@ -7,14 +5,14 @@ const executionContextMap = new Map(); const asyncHook = asyncHooks.createHook({ init, destroy }); asyncHook.enable(); -function init(asyncId: any, type: any, triggerAsyncId: any) { +function init(asyncId: number, type: string, triggerAsyncId: number) { const parentContext = executionContextMap.get(triggerAsyncId); if (!parentContext) return; executionContextMap.set(asyncId, { context: parentContext.context }); } -function destroy(asyncId: any) { +function destroy(asyncId: number) { executionContextMap.delete(asyncId); }