From c8fd07a126088f2b2a1365317ea5618692eeec07 Mon Sep 17 00:00:00 2001 From: Sarthak Shyngle <50234097+Sarthak160@users.noreply.github.com> Date: Wed, 8 May 2024 14:09:01 +0530 Subject: [PATCH] feat: add code for getting coverage per req (#108) Signed-off-by: Sarthak Shyngle <50234097+Sarthak160@users.noreply.github.com> --- .vscode/settings.json | 7 --- package-lock.json | 57 ++++++++++++++++++-- package.json | 5 +- v2/dedup/middleware.ts | 116 +++++++++++++++++++++++++++++++++++++++++ v2/dedup/register.ts | 28 ++++++++++ 5 files changed, 202 insertions(+), 11 deletions(-) delete mode 100644 .vscode/settings.json create mode 100644 v2/dedup/middleware.ts create mode 100644 v2/dedup/register.ts diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 48b8096..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "[typescript]": { - "editor.codeActionsOnSave": { - "source.fixAll": "explicit" - } - }, -} diff --git a/package-lock.json b/package-lock.json index 1dae05e..11bd77d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,22 +1,25 @@ { "name": "@keploy/sdk", - "version": "2.0.1", + "version": "2.0.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@keploy/sdk", - "version": "2.0.1", + "version": "2.0.2", "license": "MIT", "dependencies": { "@types/express": "^4.17.21", "@types/node": "^20.11.16", "axios": "^1.6.7", + "cors": "^2.8.5", + "merge-descriptors": "^2.0.0", "tree-kill": "^1.2.2", "typescript": "^5.3.3" }, "devDependencies": { - "@types/axios": "^0.14.0" + "@types/axios": "^0.14.0", + "@types/cors": "^2.8.17" } }, "node_modules/@types/axios": { @@ -46,6 +49,15 @@ "@types/node": "*" } }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/express": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", @@ -141,6 +153,18 @@ "node": ">= 0.8" } }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -181,6 +205,17 @@ "node": ">= 6" } }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -200,6 +235,14 @@ "node": ">= 0.6" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -229,6 +272,14 @@ "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } } } } diff --git a/package.json b/package.json index 088350f..0775935 100644 --- a/package.json +++ b/package.json @@ -23,10 +23,13 @@ "@types/express": "^4.17.21", "@types/node": "^20.11.16", "axios": "^1.6.7", + "cors": "^2.8.5", + "merge-descriptors": "^2.0.0", "tree-kill": "^1.2.2", "typescript": "^5.3.3" }, "devDependencies": { - "@types/axios": "^0.14.0" + "@types/axios": "^0.14.0", + "@types/cors": "^2.8.17" } } diff --git a/v2/dedup/middleware.ts b/v2/dedup/middleware.ts new file mode 100644 index 0000000..754fdba --- /dev/null +++ b/v2/dedup/middleware.ts @@ -0,0 +1,116 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { Request, Response, NextFunction } from "express"; +const fs = require('fs'); +const yaml = require('js-yaml'); + + +// middleware +export default function middleware( + +): (req: Request, res: Response, next: NextFunction) => void { + // console.log("Inside middleware..."); + return (req: Request, res: Response, next: NextFunction) => { + res.on("finish", () => { + + afterMiddleware(req, res); + }); + next(); + + }; +} + + +export function afterMiddleware(req: Request, res: Response) { + let id = req.get("KEPLOY-TEST-ID"); + if (!id) { + console.error("No test ID found in the request headers"); + return; + } + let executedLinesByFile = GetCoverage(); + + let currentData = { + id: id, + executedLinesByFile: executedLinesByFile + }; + + const filePath = 'dedupData.yaml'; + + let existingData = []; + + try { + const fileContent = fs.readFileSync(filePath, 'utf-8'); + existingData = yaml.load(fileContent) || []; + } catch (error) { + // Handle the case where the file doesn't exist or is not valid YAML + // console.error("Error reading existing file:", error); + } + + + + // Add or update the entry for the current id + existingData.push(currentData); + + // Convert the array to YAML format + const yamlData = yaml.dump(existingData); + + // Write the updated YAML data back to the file + fs.writeFileSync(filePath, yamlData, 'utf-8'); + + // Log to the console + // console.log("Executed lines by file:", executedLinesByFile); + // console.log("Data has been appended and logged to", filePath); +} + +// isJsonValid checks whether o is a valid JSON or not + +let count = 0; +const executedLinebyEachTest = new Array(); +function GetCoverage() { + // console.log("Inside GetCoverage"); + count++; + let executedLinesByFile = {}; + // iterate over global.__coverage__ + // @ts-ignore + for (const filename in global.__coverage__) { + // console.log("FIlenamae", filename); + // while (1) { + // @ts-ignore + let coverageData = global.__coverage__[filename]; + // console.log("Inside GetCoverage " + count); + // console.log(coverageData); + + + // for (const filePath of Object.keys(coverageData)) { + const executedLines = new Set(); + const fileCoverage = coverageData; + const statementMap = fileCoverage.statementMap; + const hitCounts = fileCoverage.s; + if (count > 1) { + // iterate over hitcounts and subtract the previous hitcounts + // @ts-ignore + var prevHitCounts = executedLinebyEachTest[count - 2]; + + for (const statementId in hitCounts) { + hitCounts[statementId] = Math.abs( + hitCounts[statementId] - prevHitCounts[statementId] + ); + } + } + + for (const statementId in statementMap) { + if (hitCounts[statementId] > 0) { + const executedLine = statementMap[statementId].start.line; + executedLines.add(executedLine); + } + } + // @ts-ignore + executedLinesByFile[filename] = Array.from(executedLines).sort((a, b) => a - b); + // } + // @ts-ignore + executedLinebyEachTest.push({ ...hitCounts }); + + // console.log("Executed lines by file:", executedLinesByFile); + // extract s from the coverage data + } + return executedLinesByFile; +} diff --git a/v2/dedup/register.ts b/v2/dedup/register.ts new file mode 100644 index 0000000..8f2122a --- /dev/null +++ b/v2/dedup/register.ts @@ -0,0 +1,28 @@ +// @ts-ignore +import Hook from "require-in-the-middle"; +import expressMiddleware from "./middleware"; +import bodyParser from "body-parser"; +import cors from "cors"; +import mixin from "merge-descriptors"; + + +// @ts-ignore +Hook(["express"], function (exports) { + const expressApp = exports; + function keployWrappedExpress() { + const keployApp = expressApp(); + + keployApp.use(bodyParser.json()); + keployApp.use(cors()); + keployApp.use(expressMiddleware()); + keployApp.appliedMiddleware = true; + return keployApp; + } + + // copy the properties and methods of exported Function object into wrapped Funtion(keployWrappedExpress). + // In order to prevent "express._Method_ or express._Field_ is not declared" error. + mixin(keployWrappedExpress, expressApp, false); + exports = keployWrappedExpress; + return exports; +}); +export {};