From eb660b80be82c32a09729ab1f5075936c86715db Mon Sep 17 00:00:00 2001 From: "radek.Bednarik" Date: Fri, 15 Dec 2023 09:44:03 +0100 Subject: [PATCH 1/2] dev: retrieve active expectations added --- README.md | 39 ++++++++++---- src/cli/cli.ts | 14 +++++ src/cli/handlers/getActive.handler.ts | 75 +++++++++++++++++++++++++++ src/client/client.ts | 15 ++++++ src/io/io.ts | 17 +++++- 5 files changed, 150 insertions(+), 10 deletions(-) create mode 100644 src/cli/handlers/getActive.handler.ts diff --git a/README.md b/README.md index 9308223..036c1d4 100644 --- a/README.md +++ b/README.md @@ -19,16 +19,17 @@ npx expectations -h Usage: expectations [options] [command] Options: - -V, --version output the version number - -c, --config set config path. defaults to './mockserver.config.json' (default: "./mockserver.config.json") - --concurrency set number of concurrent requests. defaults to '10' (default: "10") - -h, --help display help for command + -V, --version output the version number + -c, --config set config path. defaults to './mockserver.config.json' (default: "./mockserver.config.json") + --concurrency set number of concurrent requests. defaults to '10' (default: "10") + -h, --help display help for command Commands: - set send prepared expectations up to the mockserver instance - clear clear all expectations from the mockserver instance - reset resets everything in the running mockserver instance - help [command] display help for command + set send prepared expectations up to the mockserver instance + clear clear all expectations from the mockserver instance + reset resets all expectations and request logs in the running mockserver instance + get-active [options] get all active expectations from the mockserver instance + help [command] display help for command ``` ## Installation for development @@ -65,12 +66,14 @@ File can be placed anywhere. If `-c` or `--config` option is not provided, progr Concurrency of promises sets, how many promises many promises will be held in the queue at max to resolve. Defaults to `10`. -This limiting is applied for both `set` and `clear` commands. +This limiting is applied for both `set`, `clear` and `get-active` commands. - `set` is limited for how many expectations requests to mock-server can be sent at once. - `clear` is limited for how many `expectations.json` files can be processed at once. If the expectations array in the file contains multiple expectations, they will be processed one by one sequentially. +- `get-active` is limited for how many requests to mock-server regarding active expectations for the given expectation of the `.expectations.json` file can be sent at once. + Uses [p-queue](https://github.com/sindresorhus/p-queue) library under the hood. ```bash @@ -172,10 +175,28 @@ npx expectations clear ./examples/expectations ./examples/expectations2 ### Reset MockServer +Resets all expectations and logs in the running mockserver instance. + ```bash npx expectations reset ``` +### Get Active Expectations + +You have to provide the path(s) to the directory or file containing the expectations. + +You may provide option `-s` or `--save` to save the active expectations to the `.json` file. + +Otherwise, the expectations are only logged to the console with `trace` log level. + +```bash +# retrieves active expectations from the mockserver instance and does NOT save them to the file. +npx expectations -c some/path/to/mockserver.config.json get-active ./examples/expectations/expectation1.json + +# retrieves active expectations from the mockserver instance and saves them to the file. +npx expectations -c some/path/to/mockserver.config.json get-active examples/expectations/expectation1.json -s retrieved-active-expectations.json +``` + ## Logging Logging is done via [pino.js](https://getpino.io/) library. Currently, there is only the possibility to log to the console. diff --git a/src/cli/cli.ts b/src/cli/cli.ts index 9d69272..c7e2d49 100644 --- a/src/cli/cli.ts +++ b/src/cli/cli.ts @@ -2,6 +2,8 @@ import { createCommand } from "commander"; import { setHandler } from "./handlers/set.handler.js"; import { clearHandler } from "./handlers/clear.handler.js"; import { resetHandler } from "./handlers/reset.handler.js"; +import { getActiveHandler } from "./handlers/getActive.handler.js"; +import { saveJsonFile } from "../io/io.js"; export const program = createCommand(); @@ -32,3 +34,15 @@ program .action(async () => { await resetHandler(program.optsWithGlobals()); }); + +program + .command("get-active") + .description("get all active expectations from the mockserver instance") + .argument("", "paths to the expectations files or dirs") + .option("-s, --save ", "save active expectations to file") + .action(async (paths, options) => { + const expectations = await getActiveHandler(paths, program.optsWithGlobals()); + if (options.save) { + await saveJsonFile(options.save, expectations); + } + }); diff --git a/src/cli/handlers/getActive.handler.ts b/src/cli/handlers/getActive.handler.ts new file mode 100644 index 0000000..176c56d --- /dev/null +++ b/src/cli/handlers/getActive.handler.ts @@ -0,0 +1,75 @@ +import Client from "../../client/client.js"; +import { logger } from "../../log/logger.js"; +import { getAllFilePaths, readJsonFile } from "../../io/io.js"; +import { globalOptsHandler } from "./globalOpts.handler.js"; +import PQueue from "p-queue"; +import { resolve } from "path"; +import type { OptionValues } from "commander"; +import type { PathOrRequestDefinition } from "mockserver-client/mockServerClient.js"; +import { Expectation } from "mockserver-client"; + +const log = logger.child({ module: "get-active" }); + +async function getActiveExpectation(client: Client, expectations: PathOrRequestDefinition) { + try { + const response = await client.getActiveExpectations(expectations); + + return response; + } catch (error: any) { + log.error("Error getting active expectations:", error); + return null; + } +} + +export async function getActiveHandler(paths: string[], options: OptionValues) { + try { + log.trace(`Handling get-active command with args: ${JSON.stringify({ paths, options })}`); + + const opts = await globalOptsHandler(options); + const concurrency = parseInt(opts["concurrency"]); + + const allPaths: string[] = []; + + for (const path of paths) { + const expectationsPaths = await getAllFilePaths(path); + allPaths.push(...expectationsPaths); + } + + log.trace(`All expectations filepaths resolved to: ${JSON.stringify(allPaths)}`); + + const client = new Client({ + proto: opts["config"].proto, + host: opts["config"].host, + port: opts["config"].port, + }); + + const activeExpectations: Expectation[] = []; + const queue = new PQueue({ concurrency }); + + queue.on("completed", (result) => { + log.trace(`Retrieved active expectation: ${JSON.stringify(result)}`); + activeExpectations.push(result); + }); + + log.trace(`Expectations will be set with promises concurrency: ${concurrency}`); + + for (const path of allPaths) { + const fullPath = resolve(path); + + log.trace(`Getting active expectations from file: ${fullPath}`); + + const expectations: Expectation[] = await readJsonFile(fullPath); + + for (const expectation of expectations) { + queue.add(() => getActiveExpectation(client, expectation)); + } + } + + await queue.onIdle(); + + return activeExpectations; + } catch (error: any) { + log.error(error.message); + throw error; + } +} diff --git a/src/client/client.ts b/src/client/client.ts index 067c1fa..a900448 100644 --- a/src/client/client.ts +++ b/src/client/client.ts @@ -82,4 +82,19 @@ export default class Client { throw error; } } + + public async getActiveExpectations(pathOrRequestDefinition: PathOrRequestDefinition) { + try { + log.trace("Getting active expectations"); + + const response = await this.client.retrieveActiveExpectations(pathOrRequestDefinition); + + log.trace(`Active expectations request response: ${JSON.stringify(response)}`); + + return response; + } catch (error: any) { + log.error(error.message); + throw error; + } + } } diff --git a/src/io/io.ts b/src/io/io.ts index 0efaab8..28d75b7 100644 --- a/src/io/io.ts +++ b/src/io/io.ts @@ -1,4 +1,4 @@ -import { readFile, opendir, access } from "node:fs/promises"; +import { readFile, opendir, access, writeFile } from "node:fs/promises"; import { resolve, join } from "node:path"; import { logger } from "../log/logger.js"; @@ -23,6 +23,21 @@ export async function readJsonFile(filePath: string): Promise { } } +export async function saveJsonFile(filePath: string, data: any): Promise { + try { + const fullPath = resolve(filePath); + + log.trace(`Saving JSON file: ${fullPath} with data: ${JSON.stringify(data)}}`); + + await writeFile(resolve(filePath), JSON.stringify(data, null, 2), "utf-8"); + + log.trace(`JSON file saved`); + } catch (error: any) { + log.error("Error saving JSON file:", error.message); + throw error; + } +} + export async function getAllFilePaths(directoryPath: string, fileNameEnd = ".expectations.json"): Promise { const filepaths: string[] = []; From 822a9463fd163a7ec5669591b70c7987c963242f Mon Sep 17 00:00:00 2001 From: "radek.Bednarik" Date: Fri, 15 Dec 2023 09:44:15 +0100 Subject: [PATCH 2/2] 0.2.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index aa8cf37..4b1a6c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mockserver-cli", - "version": "0.1.6", + "version": "0.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mockserver-cli", - "version": "0.1.6", + "version": "0.2.0", "license": "ISC", "dependencies": { "commander": "^11.1.0", diff --git a/package.json b/package.json index 75bd701..472b5fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@bednarik_radek/mockserver-cli", - "version": "0.1.6", + "version": "0.2.0", "description": "CLI utility for Mock-server client. Allows for easy creation/deletion of expectations on the Mock-server instance.", "main": "index.js", "type": "module",