diff --git a/src/client.d.ts b/src/client.d.ts index 2b41365..24c264a 100644 --- a/src/client.d.ts +++ b/src/client.d.ts @@ -1,4 +1,5 @@ import { Switcher } from './switcher'; +import { SwitcherResult } from './lib/result'; /** * Quick start with the following 3 steps. @@ -118,15 +119,6 @@ export class Client { } -/** - * ResultDetail is a detailed response from the API. - */ -export type ResultDetail = { - result: boolean; - reason: string | undefined; - metadata: object | undefined; -} - /** * Criteria defines the condition(s) to evaluate the switcher when using Client.assume(key) */ @@ -149,7 +141,7 @@ export type Criteria = { export type LoggerRecord = { key: string; input: string[][]; - response: ResultDetail + response: SwitcherResult } /** @@ -303,5 +295,5 @@ declare class Key { /** * Return key response */ - getResponse(input?: string[][]): ResultDetail; + getResponse(input?: string[][]): SwitcherResult; } \ No newline at end of file diff --git a/src/client.js b/src/client.js index a3551f5..868b303 100644 --- a/src/client.js +++ b/src/client.js @@ -15,7 +15,7 @@ import { import TimedMatch from './lib/utils/timed-match/index.js'; import ExecutionLogger from './lib/utils/executionLogger.js'; import SnapshotAutoUpdater from './lib/utils/snapshotAutoUpdater.js'; -import { SnapshotNotFoundError } from './lib/exceptions/index.js'; +import { ClientError } from './lib/exceptions/index.js'; import { loadDomain, validateSnapshot, checkSwitchersLocal } from './lib/snapshot.js'; import { Switcher } from './switcher.js'; import { Auth } from './lib/remoteAuth.js'; @@ -106,7 +106,7 @@ export class Client { static async checkSnapshot() { if (!GlobalSnapshot.snapshot) { - throw new SnapshotNotFoundError('Snapshot is not loaded. Use Client.loadSnapshot()'); + throw new ClientError('Snapshot is not loaded. Use Client.loadSnapshot()'); } if (Auth.isTokenExpired()) { @@ -264,10 +264,4 @@ export class SwitcherOptions { static build() { return new SwitcherOptions(); } -} - -export class ResultDetail { - static build() { - return new ResultDetail(); - } } \ No newline at end of file diff --git a/src/lib/bypasser/key.js b/src/lib/bypasser/key.js index 76b3ff6..cb15c04 100644 --- a/src/lib/bypasser/key.js +++ b/src/lib/bypasser/key.js @@ -1,3 +1,4 @@ +import { SwitcherResult } from '../result.js'; import Criteria from './criteria.js'; /** @@ -67,11 +68,7 @@ export default class Key { result = this.#getResultBasedOnCriteria(this.#criteria, input); } - return { - result, - reason: this.#reason, - metadata: this.#metadata, - }; + return SwitcherResult.create(result, this.#reason, this.#metadata); } #getResultBasedOnCriteria(criteria, input) { diff --git a/src/lib/exceptions/index.js b/src/lib/exceptions/index.js index 7d74782..f7c051a 100644 --- a/src/lib/exceptions/index.js +++ b/src/lib/exceptions/index.js @@ -1,34 +1,20 @@ -export class AuthError extends Error { - constructor(message) { - super(`Something went wrong: ${message}`); - this.name = this.constructor.name; - } +export class ClientError extends Error { + constructor(message) { + super(`Something went wrong: ${message}`); + this.name = this.constructor.name; + } } -export class CriteriaError extends Error { - constructor(message) { - super(`Something went wrong: ${message}`); - this.name = this.constructor.name; - } +export class RemoteError extends ClientError { + constructor(message) { + super(message); + this.name = this.constructor.name; + } } -export class CheckSwitcherError extends Error { - constructor(notFound) { - super(`Something went wrong: [${notFound}] not found`); - this.name = this.constructor.name; - } +export class CheckSwitcherError extends ClientError { + constructor(notFound) { + super(`[${notFound}] not found`); + this.name = this.constructor.name; + } } - -export class SnapshotServiceError extends Error { - constructor(message) { - super(`Something went wrong: ${message}`); - this.name = this.constructor.name; - } -} - -export class SnapshotNotFoundError extends Error { - constructor(message) { - super(`Something went wrong: ${message}`); - this.name = this.constructor.name; - } -} \ No newline at end of file diff --git a/src/lib/remote.js b/src/lib/remote.js index 5428edd..a000c2e 100644 --- a/src/lib/remote.js +++ b/src/lib/remote.js @@ -1,15 +1,13 @@ import fs from 'node:fs'; import { Agent } from 'node:https'; -import { AuthError, CheckSwitcherError, CriteriaError, SnapshotServiceError } from './exceptions/index.js'; +import { CheckSwitcherError, ClientError, RemoteError } from './exceptions/index.js'; import FetchFacade from './utils/fetchFacade.js'; import * as util from './utils/index.js'; import { GlobalAuth } from './globals/globalAuth.js'; let httpClient; -const getConnectivityError = (code) => `Connection has been refused - ${code}`; - const getHeader = (token) => { return { 'Authorization': `Bearer ${token}`, @@ -19,7 +17,7 @@ const getHeader = (token) => { export function setCerts(certPath) { if (!fs.existsSync(certPath)) { - throw new Error(`Invalid certificate path '${certPath}'`); + throw new RemoteError(`Invalid certificate path '${certPath}'`); } httpClient = new Agent({ @@ -36,7 +34,7 @@ export function getEntry(input) { return undefined; } - let entry = []; + const entry = []; for (const inputValues of input) { entry.push({ strategy: inputValues[0], @@ -67,9 +65,9 @@ export async function auth(context) { return response.json(); } - throw new Error(`[auth] failed with status ${response.status}`); + throw new RemoteError(`[auth] failed with status ${response.status}`); } catch (e) { - throw new AuthError(e.errno ? getConnectivityError(e.errno) : e.message); + throw errorHandler(e); } } @@ -95,10 +93,10 @@ export async function checkCriteria(key, input, showDetail = false) { if (response.status == 200) { return response.json(); } - - throw new Error(`[checkCriteria] failed with status ${response.status}`); + + throw new RemoteError(`[checkCriteria] failed with status ${response.status}`); } catch (e) { - throw new CriteriaError(e.errno ? getConnectivityError(e.errno) : e.message); + throw errorHandler(e); } } @@ -112,7 +110,7 @@ export async function checkSwitchers(switcherKeys) { }); if (response.status != 200) { - throw new Error(`[checkSwitchers] failed with status ${response.status}`); + throw new RemoteError(`[checkSwitchers] failed with status ${response.status}`); } const json = response.json(); @@ -120,7 +118,7 @@ export async function checkSwitchers(switcherKeys) { throw new CheckSwitcherError(json.not_found); } } catch (e) { - throw new CriteriaError(e.errno ? getConnectivityError(e.errno) : e.message); + throw errorHandler(e); } } @@ -136,9 +134,9 @@ export async function checkSnapshotVersion(version) { return response.json(); } - throw new Error(`[checkSnapshotVersion] failed with status ${response.status}`); + throw new RemoteError(`[checkSnapshotVersion] failed with status ${response.status}`); } catch (e) { - throw new SnapshotServiceError(e.errno ? getConnectivityError(e.errno) : e.message); + throw errorHandler(e); } } @@ -171,8 +169,16 @@ export async function resolveSnapshot(domain, environment, component) { return JSON.stringify(response.json(), null, 4); } - throw new Error(`[resolveSnapshot] failed with status ${response.status}`); + throw new RemoteError(`[resolveSnapshot] failed with status ${response.status}`); } catch (e) { - throw new SnapshotServiceError(e.errno ? getConnectivityError(e.errno) : e.message); + throw errorHandler(e); } +} + +function errorHandler(e) { + if (!(e instanceof ClientError)) { + throw new RemoteError(e.errno ? `Connection has been refused - ${e.errno}` : e.message); + } + + throw e; } \ No newline at end of file diff --git a/src/lib/resolver.js b/src/lib/resolver.js index 2613480..a7d2b00 100644 --- a/src/lib/resolver.js +++ b/src/lib/resolver.js @@ -1,130 +1,143 @@ import { processOperation } from './snapshot.js'; import { getEntry } from '../lib/remote.js'; import * as util from '../lib/utils/index.js'; +import { SwitcherResult } from './result.js'; -async function resolveCriteria({ domain }, switcher) { - let result = true, reason = ''; - - try { - if (!domain.activated) { - throw new CriteriaFailed('Domain disabled'); - } - - const { group } = domain; - if (!(await checkGroup(group, switcher))) { - throw new Error(`Something went wrong: {"error":"Unable to load a key ${switcher.key}"}`); - } - - reason = 'Success'; - } catch (e) { - if (e instanceof CriteriaFailed) { - result = false; - reason = e.message; - } else { - throw e; - } +/** + * Resolves the criteria for a given switcher request against the snapshot data. + * + * @param {SnapshotData} data - The snapshot data containing domain and group information. + * @param {SwitcherRequest} switcher - The switcher request to be evaluated. + * @returns {Promise} - The result of the switcher evaluation. + */ +async function resolveCriteria(data, switcher) { + if (!data.domain.activated) { + return SwitcherResult.disabled('Domain disabled'); } - return { - result, - reason - }; + const { group } = data.domain; + return await checkGroup(group, switcher); } /** - * @param {*} groups from a specific Domain - * @param {*} switcher Switcher to check - * @return true if Switcher found + * Checks if a switcher is valid within a specific group of the domain. + * + * @param {Group[]} groups - The list of groups to check against. + * @param {SwitcherRequest} switcher - The switcher request to be evaluated. + * @returns {Promise} - The result of the switcher evaluation. + * @throws {Error} - If the switcher key is not found in any group. */ async function checkGroup(groups, switcher) { const key = util.get(switcher.key, ''); - if (groups) { - for (const group of groups) { - const { config } = group; - const configFound = config.filter(c => c.key === key); + for (const group of groups) { + const { config } = group; + const configFound = config.filter(c => c.key === key); - // Switcher Configs are always supplied as the snapshot is loaded from components linked to the Switcher. - if (await checkConfig(group, configFound[0], switcher)) { - return true; + if (configFound.length) { + if (!group.activated) { + return SwitcherResult.disabled('Group disabled'); } + + return await checkConfig(configFound[0], switcher); } } - return false; + + throw new Error( + `Something went wrong: {"error":"Unable to load a key ${switcher.key}"}`, + ); } /** - * @param {*} group in which Switcher has been found - * @param {*} config Switcher found - * @param {*} switcher Switcher to check - * @return true if Switcher found + * Checks if a switcher is valid within a specific configuration. + * + * @param {Config} config Configuration to check + * @param {SwitcherRequest} switcher - The switcher request to be evaluated. + * @return {Promise} - The result of the switcher evaluation. */ -async function checkConfig(group, config, switcher) { - if (!config) { - return false; - } - - if (!group.activated) { - throw new CriteriaFailed('Group disabled'); - } - +async function checkConfig(config, switcher) { if (!config.activated) { - throw new CriteriaFailed('Config disabled'); + return SwitcherResult.disabled('Config disabled'); } if (hasRelayEnabled(config) && switcher.isRelayRestricted) { - throw new CriteriaFailed(`Config '${config.key}' is restricted to relay`); + return SwitcherResult.disabled('Config has Relay enabled'); } if (config.strategies) { - return await checkStrategy(config, util.get(switcher.input, [])); + return await checkStrategy(config, switcher.input); } - return true; + return SwitcherResult.enabled(); } +/** + * Checks if a switcher is valid against the strategies defined in the configuration. + * + * @param {Config} config - The configuration containing strategies. + * @param {string[][]} [input] - The input data to be evaluated against the strategies. + * @returns {Promise} - The result of the strategy evaluation. + */ async function checkStrategy(config, input) { const { strategies } = config; - const entry = getEntry(input); + const entry = getEntry(util.get(input, [])); - for (const strategy of strategies) { - if (!strategy.activated) { + for (const strategyConfig of strategies) { + if (!strategyConfig.activated) { continue; } - await checkStrategyInput(entry, strategy); + const strategyResult = await checkStrategyConfig(strategyConfig, entry); + if (strategyResult) { + return strategyResult; + } } - return true; + return SwitcherResult.enabled(); } -async function checkStrategyInput(entry, { strategy, operation, values }) { - if (entry?.length) { - const strategyEntry = entry.filter(e => e.strategy === strategy); - if (strategyEntry.length == 0 || !(await processOperation(strategy, operation, strategyEntry[0].input, values))) { - throw new CriteriaFailed(`Strategy '${strategy}' does not agree`); - } - } else { - throw new CriteriaFailed(`Strategy '${strategy}' did not receive any input`); +/** + * Checks if a strategy configuration is valid against the provided entry data. + * + * @param {Strategy} strategyConfig - The strategy configuration to be checked. + * @param {Entry[]} [entry] - The entry data to be evaluated against the strategy. + * @returns {Promise} - The result of the strategy evaluation or undefined if valid. + */ +async function checkStrategyConfig(strategyConfig, entry) { + if (!entry?.length) { + return SwitcherResult.disabled(`Strategy '${strategyConfig.strategy}' did not receive any input`); } + + const strategyEntry = entry.filter((e) => e.strategy === strategyConfig.strategy); + if (await isStrategyFulfilled(strategyEntry, strategyConfig)) { + return SwitcherResult.disabled(`Strategy '${strategyConfig.strategy}' does not agree`); + } + + return undefined; } function hasRelayEnabled(config) { return config.relay?.activated; } +async function isStrategyFulfilled(strategyEntry, strategyConfig) { + return strategyEntry.length == 0 || + !(await processOperation(strategyConfig, strategyEntry[0].input)); +} + +/** + * Checks the criteria for a switcher request against the local snapshot. + * + * @param {Snapshot | undefined} snapshot - The snapshot containing the data to check against. + * @param {SwitcherRequest} switcher - The switcher request to be evaluated. + * @returns {Promise} - The result of the switcher evaluation. + * @throws {Error} - If the snapshot is not loaded. + */ export default async function checkCriteriaLocal(snapshot, switcher) { if (!snapshot) { throw new Error('Snapshot not loaded. Try to use \'Client.loadSnapshot()\''); } - + const { data } = snapshot; return resolveCriteria(data, switcher); -} - -class CriteriaFailed extends Error { - constructor(reason) { - super(reason); - this.name = this.constructor.name; - } } \ No newline at end of file diff --git a/src/lib/result.js b/src/lib/result.js new file mode 100644 index 0000000..584c55e --- /dev/null +++ b/src/lib/result.js @@ -0,0 +1,64 @@ +/** + * SwitcherResult represents the result of the criteria evaluation. + * It represents: + * + * - `result`: a boolean indicating if the criteria was met. + * - `reason`: an optional string providing a reason for the result. + * - `metadata`: an optional object containing additional metadata about the result. + */ +export class SwitcherResult { + #result; + #reason; + #metadata; + + constructor(result = false, reason = undefined, metadata = undefined) { + this.#result = result; + this.#reason = reason; + this.#metadata = metadata; + } + + static create(result = false, reason = undefined, metadata = undefined) { + return new SwitcherResult(result, reason, metadata); + } + + static enabled(reason = 'Success', metadata = undefined) { + return new SwitcherResult(true, reason, metadata); + } + + static disabled(reason = undefined, metadata = undefined) { + return new SwitcherResult(false, reason, metadata); + } + + /** + * Returns the object as a JSON representation + * This method is automatically called when JSON.stringify() is used + */ + toJSON() { + return { + result: this.#result, + reason: this.#reason, + metadata: this.#metadata, + }; + } + + /** + * @returns {boolean} - Returns true if the result is successful. + */ + get result() { + return this.#result; + } + + /** + * @returns {string | undefined} - Returns the reason for the result, if any. + */ + get reason() { + return this.#reason; + } + + /** + * @returns {object | undefined} - Returns additional metadata about the result, if any. + */ + get metadata() { + return this.#metadata; + } +} diff --git a/src/lib/snapshot.js b/src/lib/snapshot.js index fe84a40..f95b5e3 100644 --- a/src/lib/snapshot.js +++ b/src/lib/snapshot.js @@ -86,7 +86,9 @@ const OperationsType = Object.freeze({ HAS_ALL: 'HAS_ALL' }); -const processOperation = async (strategy, operation, input, values) => { +const processOperation = async (strategyConfig, input) => { + const { strategy, operation, values } = strategyConfig; + switch(strategy) { case StrategiesType.NETWORK: return processNETWORK(operation, input, values); diff --git a/src/switcher.d.ts b/src/switcher.d.ts index 196d20b..29b10bd 100644 --- a/src/switcher.d.ts +++ b/src/switcher.d.ts @@ -1,4 +1,4 @@ -import { ResultDetail } from "./client"; +import { SwitcherResult } from './lib/result.js'; /** * Switcher handles criteria execution and validations. @@ -20,9 +20,9 @@ export class Switcher { /** * Execute criteria * - * @returns boolean or ResultDetail when detail() is used + * @returns boolean or SwitcherResult when detail() is used */ - isItOn(key?: string): Promise; + isItOn(key?: string): Promise; /** * Define a delay (ms) for the next async execution. @@ -37,7 +37,7 @@ export class Switcher { remote(forceRemote?: boolean): Switcher; /** - * When enabled, isItOn will return a ResultDetail object + * When enabled, isItOn will return a SwitcherResult object */ detail(showDetail?: boolean): Switcher; @@ -45,7 +45,7 @@ export class Switcher { * Define a default result when the client enters in panic mode */ defaultResult(defaultResult: boolean): Switcher; - + /** * Allow local snapshots to ignore or require Relay verification. */ @@ -83,7 +83,7 @@ export class Switcher { /** * Adds REGEX_VALIDATION input for strategy validation - */ + */ checkRegex(input: string): Switcher; /** diff --git a/src/switcher.js b/src/switcher.js index b5c5f7b..529476c 100644 --- a/src/switcher.js +++ b/src/switcher.js @@ -4,6 +4,7 @@ import checkCriteriaLocal from './lib/resolver.js'; import * as remote from './lib/remote.js'; import * as util from './lib/utils/index.js'; import { Auth } from './lib/remoteAuth.js'; +import { SwitcherResult } from './lib/result.js'; import { GlobalAuth } from './lib/globals/globalAuth.js'; import { GlobalOptions } from './lib/globals/globalOptions.js'; import { GlobalSnapshot } from './lib/globals/globalSnapshot.js'; @@ -176,10 +177,7 @@ export class Switcher extends SwitcherRequest { throw err; } - const response = { - result: this._defaultResult, - reason: 'Default result' - }; + const response = SwitcherResult.create(this._defaultResult, 'Default result'); this.#notifyError(err); return response; diff --git a/src/types/index.d.ts b/src/types/index.d.ts index ac07170..66c66aa 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -1,10 +1,10 @@ -import { Client, type ResultDetail, type SwitcherContext, type SwitcherOptions } from "../client"; -import { Switcher } from "../switcher"; +import { Client, type SwitcherContext, type SwitcherOptions } from "../client"; +import { Switcher, SwitcherResult } from "../switcher"; export { Switcher, Client, - ResultDetail, + SwitcherResult, SwitcherContext, SwitcherOptions } \ No newline at end of file diff --git a/switcher-client.js b/switcher-client.js index 1c4bc7e..a3d2cde 100644 --- a/switcher-client.js +++ b/switcher-client.js @@ -15,6 +15,7 @@ * @module */ -export { Client, ResultDetail, SwitcherContext, SwitcherOptions } from './src/client.js'; +export { Client, SwitcherContext, SwitcherOptions } from './src/client.js'; export { Switcher } from './src/switcher.js'; +export { SwitcherResult } from './src/lib/result.js'; export { StrategiesType } from './src/lib/snapshot.js'; \ No newline at end of file diff --git a/tests/helper/utils.js b/tests/helper/utils.js index b0113e6..167a66d 100644 --- a/tests/helper/utils.js +++ b/tests/helper/utils.js @@ -19,7 +19,7 @@ export async function assertReject(assert, promise, expectedError) { }); assert.isNotNull(result); - assert.equal(expectedError, result.message); + assert.equal(result.message, expectedError); } export async function assertResolve(assert, promise) { @@ -46,7 +46,7 @@ export async function assertUntilResolve(assert, actual, expected) { if (!actual()) { console.warn('Async test could not resolve in time'); } else { - assert.equal(expected, actual()); + assert.equal(actual(), expected); } } diff --git a/tests/snapshot/default_disabled.json b/tests/snapshot/default_disabled.json new file mode 100644 index 0000000..7d30c80 --- /dev/null +++ b/tests/snapshot/default_disabled.json @@ -0,0 +1,10 @@ +{ + "data": { + "domain": { + "name": "Business", + "description": "Business description", + "activated": false, + "group": [] + } + } +} \ No newline at end of file diff --git a/tests/strategy-operations/date.test.js b/tests/strategy-operations/date.test.js index ce467f8..33ce8ec 100644 --- a/tests/strategy-operations/date.test.js +++ b/tests/strategy-operations/date.test.js @@ -15,69 +15,76 @@ describe('Processing strategy: DATE', () => { '2019-12-01T08:30' ]; + const givenStrategyConfig = (operation, values) => ({ + strategy: StrategiesType.DATE, + operation: operation, + values: values, + activated: true, + }); + it('should agree when input is LOWER', async () => { - const result = await processOperation( - StrategiesType.DATE, OperationsType.LOWER, '2019-11-26', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.LOWER, mock_values1); + const result = await processOperation(strategyConfig, '2019-11-26'); assert.isTrue(result); }); it('should agree when input is LOWER or SAME', async () => { - const result = await processOperation( - StrategiesType.DATE, OperationsType.LOWER, '2019-12-01', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.LOWER, mock_values1); + const result = await processOperation(strategyConfig, '2019-12-01'); assert.isTrue(result); }); it('should NOT agree when input is NOT LOWER', async () => { - const result = await processOperation( - StrategiesType.DATE, OperationsType.LOWER, '2019-12-02', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.LOWER, mock_values1); + const result = await processOperation(strategyConfig, '2019-12-02'); assert.isFalse(result); }); it('should agree when input is GREATER', async () => { - const result = await processOperation( - StrategiesType.DATE, OperationsType.GREATER, '2019-12-02', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.GREATER, mock_values1); + const result = await processOperation(strategyConfig, '2019-12-02'); assert.isTrue(result); }); it('should agree when input is GREATER or SAME', async () => { - const result = await processOperation( - StrategiesType.DATE, OperationsType.GREATER, '2019-12-01', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.GREATER, mock_values1); + const result = await processOperation(strategyConfig, '2019-12-01'); assert.isTrue(result); }); it('should NOT agree when input is NOT GREATER', async () => { - const result = await processOperation( - StrategiesType.DATE, OperationsType.GREATER, '2019-11-10', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.GREATER, mock_values1); + const result = await processOperation(strategyConfig, '2019-11-10'); assert.isFalse(result); }); it('should agree when input is in BETWEEN', async () => { - const result = await processOperation( - StrategiesType.DATE, OperationsType.BETWEEN, '2019-12-03', mock_values2); + const strategyConfig = givenStrategyConfig(OperationsType.BETWEEN, mock_values2); + const result = await processOperation(strategyConfig, '2019-12-03'); assert.isTrue(result); }); it('should NOT agree when input is NOT in BETWEEN', async () => { - const result = await processOperation( - StrategiesType.DATE, OperationsType.BETWEEN, '2019-12-12', mock_values2); + const strategyConfig = givenStrategyConfig(OperationsType.BETWEEN, mock_values2); + const result = await processOperation(strategyConfig, '2019-12-12'); assert.isFalse(result); }); it('should agree when input is LOWER including time', async () => { - const result = await processOperation( - StrategiesType.DATE, OperationsType.LOWER, '2019-12-01T07:00', mock_values3); + const strategyConfig = givenStrategyConfig(OperationsType.LOWER, mock_values3); + const result = await processOperation(strategyConfig, '2019-12-01T07:00'); assert.isTrue(result); }); it('should NOT agree when input is NOT LOWER including time', async () => { - const result = await processOperation( - StrategiesType.DATE, OperationsType.LOWER, '2019-12-01T07:00', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.LOWER, mock_values1); + const result = await processOperation(strategyConfig, '2019-12-01T07:00'); assert.isFalse(result); }); it('should agree when input is GREATER including time', async () => { - const result = await processOperation( - StrategiesType.DATE, OperationsType.GREATER, '2019-12-01T08:40', mock_values3); + const strategyConfig = givenStrategyConfig(OperationsType.GREATER, mock_values3); + const result = await processOperation(strategyConfig, '2019-12-01T08:40'); assert.isTrue(result); }); diff --git a/tests/strategy-operations/network.test.js b/tests/strategy-operations/network.test.js index 4279078..45247f6 100644 --- a/tests/strategy-operations/network.test.js +++ b/tests/strategy-operations/network.test.js @@ -18,56 +18,64 @@ describe('Processing strategy: NETWORK', () => { '192.168.56.58' ]; + const givenStrategyConfig = (operation, values) => ({ + strategy: StrategiesType.NETWORK, + operation: operation, + values: values, + activated: true, + }); + it('should agree when input range EXIST', async () => { - const result = await processOperation( - StrategiesType.NETWORK, OperationsType.EXIST, '10.0.0.3', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.EXIST, mock_values1); + const result = await processOperation(strategyConfig, '10.0.0.3'); assert.isTrue(result); }); it('should agree when input range EXIST - Irregular CIDR', async function () { - const result = await processOperation(StrategiesType.NETWORK, OperationsType.EXIST, '10.0.0.3', ['10.0.0.3/24']); + const strategyConfig = givenStrategyConfig(OperationsType.EXIST, ['10.0.0.3/24']); + const result = await processOperation(strategyConfig, '10.0.0.3'); assert.isTrue(result); }); it('should NOT agree when input range DOES NOT EXIST', async () => { - const result = await processOperation( - StrategiesType.NETWORK, OperationsType.EXIST, '10.0.0.4', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.EXIST, mock_values1); + const result = await processOperation(strategyConfig, '10.0.0.4'); assert.isFalse(result); }); it('should agree when input DOES NOT EXIST', async () => { - const result = await processOperation( - StrategiesType.NETWORK, OperationsType.NOT_EXIST, '10.0.0.4', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.NOT_EXIST, mock_values1); + const result = await processOperation(strategyConfig, '10.0.0.4'); assert.isTrue(result); }); it('should NOT agree when input EXIST but assumed that it DOES NOT EXIST', async () => { - const result = await processOperation( - StrategiesType.NETWORK, OperationsType.NOT_EXIST, '10.0.0.3', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.NOT_EXIST, mock_values1); + const result = await processOperation(strategyConfig, '10.0.0.3'); assert.isFalse(result); }); it('should agree when input IP EXIST', async () => { - const result = await processOperation( - StrategiesType.NETWORK, OperationsType.EXIST, '192.168.56.58', mock_values3); + const strategyConfig = givenStrategyConfig(OperationsType.EXIST, mock_values3); + const result = await processOperation(strategyConfig, '192.168.56.58'); assert.isTrue(result); }); it('should agree when input IP DOES NOT EXIST', async () => { - const result = await processOperation( - StrategiesType.NETWORK, OperationsType.NOT_EXIST, '192.168.56.50', mock_values3); + const strategyConfig = givenStrategyConfig(OperationsType.NOT_EXIST, mock_values3); + const result = await processOperation(strategyConfig, '192.168.56.50'); assert.isTrue(result); }); it('should agree when input range EXIST for multiple ranges', async () => { - const result = await processOperation( - StrategiesType.NETWORK, OperationsType.EXIST, '192.168.0.3', mock_values2); + const strategyConfig = givenStrategyConfig(OperationsType.EXIST, mock_values2); + const result = await processOperation(strategyConfig, '192.168.0.3'); assert.isTrue(result); }); it('should NOT agree when input range DOES NOT EXIST for multiple ranges', async () => { - const result = await processOperation( - StrategiesType.NETWORK, OperationsType.NOT_EXIST, '127.0.0.0', mock_values2); + const strategyConfig = givenStrategyConfig(OperationsType.NOT_EXIST, mock_values2); + const result = await processOperation(strategyConfig, '127.0.0.0'); assert.isTrue(result); }); diff --git a/tests/strategy-operations/numeric.test.js b/tests/strategy-operations/numeric.test.js index a247226..601c2fa 100644 --- a/tests/strategy-operations/numeric.test.js +++ b/tests/strategy-operations/numeric.test.js @@ -15,105 +15,107 @@ describe('Processing strategy: NUMERIC', () => { '1.5' ]; + const givenStrategyConfig = (operation, values) => ({ + strategy: StrategiesType.NUMERIC, + operation: operation, + values: values, + activated: true, + }); + it('should agree when input EXIST in values - String type', async () => { - const result = await processOperation( - StrategiesType.NUMERIC, OperationsType.EXIST, '3', mock_values2); + const strategyConfig = givenStrategyConfig(OperationsType.EXIST, mock_values2); + const result = await processOperation(strategyConfig, '3'); assert.isTrue(result); }); it('should agree when input EXIST in values - Number type', async () => { - const result = await processOperation( - StrategiesType.NUMERIC, OperationsType.EXIST, 3, mock_values2); + const strategyConfig = givenStrategyConfig(OperationsType.EXIST, mock_values2); + const result = await processOperation(strategyConfig, 3); assert.isTrue(result); }); it('should NOT agree when input exist but test as DOES NOT EXIST ', async () => { - const result = await processOperation( - StrategiesType.NUMERIC, OperationsType.NOT_EXIST, '1', mock_values2); + const strategyConfig = givenStrategyConfig(OperationsType.NOT_EXIST, mock_values2); + const result = await processOperation(strategyConfig, '1'); assert.isFalse(result); }); it('should agree when input DOES NOT EXIST in values', async () => { - const result = await processOperation( - StrategiesType.NUMERIC, OperationsType.NOT_EXIST, '2', mock_values2); + const strategyConfig = givenStrategyConfig(OperationsType.NOT_EXIST, mock_values2); + const result = await processOperation(strategyConfig, '2'); assert.isTrue(result); }); it('should agree when input is EQUAL to value', async () => { - const result = await processOperation( - StrategiesType.NUMERIC, OperationsType.EQUAL, '1', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.EQUAL, mock_values1); + const result = await processOperation(strategyConfig, '1'); assert.isTrue(result); }); it('should NOT agree when input is not equal but test as EQUAL', async () => { - const result = await processOperation( - StrategiesType.NUMERIC, OperationsType.EQUAL, '2', mock_values1); - assert.isFalse(result); + const strategyConfig = givenStrategyConfig(OperationsType.EQUAL, mock_values1); + const result = await processOperation(strategyConfig, '2'); + assert.isFalse(result); }); it('should agree when input is NOT EQUAL to value', async () => { - const result = await processOperation( - StrategiesType.NUMERIC, OperationsType.NOT_EQUAL, '2', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.NOT_EQUAL, mock_values1); + const result = await processOperation(strategyConfig, '2'); assert.isTrue(result); }); it('should agree when input is GREATER than value', async () => { - let result = await processOperation( - StrategiesType.NUMERIC, OperationsType.GREATER, '2', mock_values1); + let strategyConfig = givenStrategyConfig(OperationsType.GREATER, mock_values1); + let result = await processOperation(strategyConfig, '2'); assert.isTrue(result); // test decimal - result = await processOperation( - StrategiesType.NUMERIC, OperationsType.GREATER, '1.01', mock_values1); + result = await processOperation(strategyConfig, '1.01'); assert.isTrue(result); - result = await processOperation( - StrategiesType.NUMERIC, OperationsType.GREATER, '1.55', mock_values3); + strategyConfig = givenStrategyConfig(OperationsType.GREATER, mock_values3); + result = await processOperation(strategyConfig, '1.55'); assert.isTrue(result); }); it('should NOT agree when input is lower but tested as GREATER than value', async () => { - let result = await processOperation( - StrategiesType.NUMERIC, OperationsType.GREATER, '0', mock_values1); + let strategyConfig = givenStrategyConfig(OperationsType.GREATER, mock_values1); + let result = await processOperation(strategyConfig, '0'); assert.isFalse(result); // test decimal - result = await processOperation( - StrategiesType.NUMERIC, OperationsType.GREATER, '0.99', mock_values1); + result = await processOperation(strategyConfig, '0.99'); assert.isFalse(result); - result = await processOperation( - StrategiesType.NUMERIC, OperationsType.GREATER, '1.49', mock_values3); + strategyConfig = givenStrategyConfig(OperationsType.GREATER, mock_values3); + result = await processOperation(strategyConfig, '1.49'); assert.isFalse(result); }); it('should agree when input is LOWER than value', async () => { - let result = await processOperation( - StrategiesType.NUMERIC, OperationsType.LOWER, '0', mock_values1); + let strategyConfig = givenStrategyConfig(OperationsType.LOWER, mock_values1); + let result = await processOperation(strategyConfig, '0'); assert.isTrue(result); // test decimal - result = await processOperation( - StrategiesType.NUMERIC, OperationsType.LOWER, '0.99', mock_values1); + result = await processOperation(strategyConfig, '0.99'); assert.isTrue(result); - result = await processOperation( - StrategiesType.NUMERIC, OperationsType.LOWER, '1.49', mock_values3); + strategyConfig = givenStrategyConfig(OperationsType.LOWER, mock_values3); + result = await processOperation(strategyConfig, '1.49'); assert.isTrue(result); }); it('should agree when input is BETWEEN values', async () => { - let result = await processOperation( - StrategiesType.NUMERIC, OperationsType.BETWEEN, '1', mock_values2); + const strategyConfig = givenStrategyConfig(OperationsType.BETWEEN, mock_values2); + let result = await processOperation(strategyConfig, '1'); assert.isTrue(result); // test decimal - result = await processOperation( - StrategiesType.NUMERIC, OperationsType.BETWEEN, '2.99', mock_values2); + result = await processOperation(strategyConfig, '2.99'); assert.isTrue(result); - result = await processOperation( - StrategiesType.NUMERIC, OperationsType.BETWEEN, '1.001', mock_values2); + result = await processOperation(strategyConfig, '1.001'); assert.isTrue(result); }); }); \ No newline at end of file diff --git a/tests/strategy-operations/payload.test.js b/tests/strategy-operations/payload.test.js index 6261582..c629229 100644 --- a/tests/strategy-operations/payload.test.js +++ b/tests/strategy-operations/payload.test.js @@ -39,6 +39,13 @@ describe('Processing strategy: PAYLOAD', () => { env: 'default' }); + const givenStrategyConfig = (operation, values) => ({ + strategy: StrategiesType.PAYLOAD, + operation: operation, + values: values, + activated: true, + }); + it('should read keys from payload #1', () => { const keys = payloadReader(JSON.parse(fixture_values2)); assert.deepEqual(keys, [ @@ -78,54 +85,58 @@ describe('Processing strategy: PAYLOAD', () => { }); it('should return TRUE when payload has field', async () => { - assert.isTrue(await processOperation( - StrategiesType.PAYLOAD, OperationsType.HAS_ONE, fixture_1, ['login'])); + const strategyConfig = givenStrategyConfig(OperationsType.HAS_ONE, ['login']); + assert.isTrue(await processOperation(strategyConfig, fixture_1)); }); it('should return FALSE when payload does not have field', async () => { - assert.isFalse(await processOperation( - StrategiesType.PAYLOAD, OperationsType.HAS_ONE, fixture_1, ['user'])); + const strategyConfig = givenStrategyConfig(OperationsType.HAS_ONE, ['user']); + assert.isFalse(await processOperation(strategyConfig, fixture_1)); }); it('should return TRUE when payload has nested field', async () => { - assert.isTrue(await processOperation( - StrategiesType.PAYLOAD, OperationsType.HAS_ONE, fixture_values2, [ - 'order.qty', 'order.total' - ])); + const strategyConfig = givenStrategyConfig(OperationsType.HAS_ONE, [ + 'order.qty', 'order.total' + ]); + + assert.isTrue(await processOperation(strategyConfig, fixture_values2)); }); it('should return TRUE when payload has nested field with arrays', async () => { - assert.isTrue(await processOperation( - StrategiesType.PAYLOAD, OperationsType.HAS_ONE, fixture_values2, [ - 'order.deliver.tracking.status' - ])); + const strategyConfig = givenStrategyConfig(OperationsType.HAS_ONE, [ + 'order.deliver.tracking.status' + ]); + + assert.isTrue(await processOperation(strategyConfig, fixture_values2)); }); it('should return TRUE when payload has all', async () => { - assert.isTrue(await processOperation( - StrategiesType.PAYLOAD, OperationsType.HAS_ALL, fixture_values2, [ - 'product', - 'order', - 'order.qty', - 'order.deliver', - 'order.deliver.expect', - 'order.deliver.tracking', - 'order.deliver.tracking.date', - 'order.deliver.tracking.status' - ])); + const strategyConfig = givenStrategyConfig(OperationsType.HAS_ALL, [ + 'product', + 'order', + 'order.qty', + 'order.deliver', + 'order.deliver.expect', + 'order.deliver.tracking', + 'order.deliver.tracking.date', + 'order.deliver.tracking.status' + ]); + + assert.isTrue(await processOperation(strategyConfig, fixture_values2)); }); it('should return FALSE when payload does not have all', async () => { - assert.isFalse(await processOperation( - StrategiesType.PAYLOAD, OperationsType.HAS_ALL, fixture_values2, [ - 'product', - 'order', - 'order.NOT_EXIST_KEY', - ])); + const strategyConfig = givenStrategyConfig(OperationsType.HAS_ALL, [ + 'product', + 'order', + 'order.NOT_EXIST_KEY', + ]); + + assert.isFalse(await processOperation(strategyConfig, fixture_values2)); }); it('should return FALSE when payload is not a JSON string', async () => { - assert.isFalse(await processOperation( - StrategiesType.PAYLOAD, OperationsType.HAS_ALL, 'NOT_JSON', [])); + const strategyConfig = givenStrategyConfig(OperationsType.HAS_ALL, []); + assert.isFalse(await processOperation(strategyConfig, 'NOT_JSON')); }); }); \ No newline at end of file diff --git a/tests/strategy-operations/regex.test.js b/tests/strategy-operations/regex.test.js index b2f18e1..e7d53ed 100644 --- a/tests/strategy-operations/regex.test.js +++ b/tests/strategy-operations/regex.test.js @@ -15,6 +15,13 @@ const mock_values3 = [ 'USER_[0-9]{1,2}' ]; +const givenStrategyConfig = (operation, values) => ({ + strategy: StrategiesType.REGEX, + operation: operation, + values: values, + activated: true, +}); + describe('Processing strategy: [REGEX Safe] ', function() { this.beforeAll(function() { TimedMatch.initializeWorker(); @@ -25,71 +32,71 @@ describe('Processing strategy: [REGEX Safe] ', function() { }); it('should agree when expect to exist using EXIST operation', async () => { - let result = await processOperation( - StrategiesType.REGEX, OperationsType.EXIST, 'USER_1', mock_values1); + let strategyConfig = givenStrategyConfig(OperationsType.EXIST, mock_values1); + let result = await processOperation(strategyConfig, 'USER_1'); assert.isTrue(result); - result = await processOperation( - StrategiesType.REGEX, OperationsType.EXIST, 'user-01', mock_values2); + strategyConfig = givenStrategyConfig(OperationsType.EXIST, mock_values2); + result = await processOperation(strategyConfig, 'user-01'); assert.isTrue(result); }); it('should NOT agree when expect to exist using EXIST operation', async () => { - let result = await processOperation( - StrategiesType.REGEX, OperationsType.EXIST, 'USER_123', mock_values1); + let strategyConfig = givenStrategyConfig(OperationsType.EXIST, mock_values1); + let result = await processOperation(strategyConfig, 'USER_123'); assert.isFalse(result); //mock_values3 does not require exact match - result = await processOperation( - StrategiesType.REGEX, OperationsType.EXIST, 'USER_123', mock_values3); + strategyConfig = givenStrategyConfig(OperationsType.EXIST, mock_values3); + result = await processOperation(strategyConfig, 'USER_123'); assert.isTrue(result); }); it('should agree when expect to not exist using NOT_EXIST operation', async () => { - let result = await processOperation( - StrategiesType.REGEX, OperationsType.NOT_EXIST, 'USER_123', mock_values1); + let strategyConfig = givenStrategyConfig(OperationsType.NOT_EXIST, mock_values1); + let result = await processOperation(strategyConfig, 'USER_123'); assert.isTrue(result); - result = await processOperation( - StrategiesType.REGEX, OperationsType.NOT_EXIST, 'user-123', mock_values2); + strategyConfig = givenStrategyConfig(OperationsType.NOT_EXIST, mock_values2); + result = await processOperation(strategyConfig, 'user-123'); assert.isTrue(result); }); it('should NOT agree when expect to not exist using NOT_EXIST operation', async () => { - const result = await processOperation( - StrategiesType.REGEX, OperationsType.NOT_EXIST, 'USER_12', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.NOT_EXIST, mock_values1); + const result = await processOperation(strategyConfig, 'USER_12'); assert.isFalse(result); }); it('should agree when expect to be equal using EQUAL operation', async () => { - const result = await processOperation( - StrategiesType.REGEX, OperationsType.EQUAL, 'USER_11', mock_values3); + const strategyConfig = givenStrategyConfig(OperationsType.EQUAL, mock_values3); + const result = await processOperation(strategyConfig, 'USER_11'); assert.isTrue(result); }); it('should NOT agree when expect to be equal using EQUAL operation', async () => { - const result = await processOperation( - StrategiesType.REGEX, OperationsType.EQUAL, 'user-11', mock_values3); + const strategyConfig = givenStrategyConfig(OperationsType.EQUAL, mock_values3); + const result = await processOperation(strategyConfig, 'user-11'); assert.isFalse(result); }); it('should agree when expect to not be equal using NOT_EQUAL operation', async () => { - const result = await processOperation( - StrategiesType.REGEX, OperationsType.NOT_EQUAL, 'USER_123', mock_values3); + const strategyConfig = givenStrategyConfig(OperationsType.NOT_EQUAL, mock_values3); + const result = await processOperation(strategyConfig, 'USER_123'); assert.isTrue(result); }); it('should NOT agree when expect to not be equal using NOT_EQUAL operation', async () => { - const result = await processOperation( - StrategiesType.REGEX, OperationsType.NOT_EQUAL, 'USER_1', mock_values3); + const strategyConfig = givenStrategyConfig(OperationsType.NOT_EQUAL, mock_values3); + const result = await processOperation(strategyConfig, 'USER_1'); assert.isFalse(result); }); it('should NOT agree when match cannot finish (reDoS attempt)', async function () { this.timeout(3100); - - const result = await processOperation( - StrategiesType.REGEX, OperationsType.EQUAL, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', ['^(([a-z])+.)+[A-Z]([a-z])+$']); + + const strategyConfig = givenStrategyConfig(OperationsType.EQUAL, ['^(([a-z])+.)+[A-Z]([a-z])+$']); + const result = await processOperation(strategyConfig, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); assert.isFalse(result); }); }); @@ -100,7 +107,8 @@ describe('Strategy [REGEX] tests:', function() { }); it('should agree when expect to exist using EXIST operation', async function () { - const result = await processOperation(StrategiesType.REGEX, OperationsType.EXIST, 'USER_1', mock_values1); - assert.isTrue(result); + const strategyConfig = givenStrategyConfig(OperationsType.EXIST, mock_values1); + const result = await processOperation(strategyConfig, 'USER_1'); + assert.isTrue(result); }); }); \ No newline at end of file diff --git a/tests/strategy-operations/time.test.js b/tests/strategy-operations/time.test.js index cf61f0a..2df57f6 100644 --- a/tests/strategy-operations/time.test.js +++ b/tests/strategy-operations/time.test.js @@ -11,51 +11,58 @@ describe('Processing strategy: TIME', () => { '08:00', '10:00' ]; + const givenStrategyConfig = (operation, values) => ({ + strategy: StrategiesType.TIME, + operation: operation, + values: values, + activated: true, + }); + it('should agree when input is LOWER', async () => { - const result = await processOperation( - StrategiesType.TIME, OperationsType.LOWER, '06:00', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.LOWER, mock_values1); + const result = await processOperation(strategyConfig, '06:00'); assert.isTrue(result); }); it('should agree when input is LOWER or SAME', async () => { - const result = await processOperation( - StrategiesType.TIME, OperationsType.LOWER, '08:00', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.LOWER, mock_values1); + const result = await processOperation(strategyConfig, '08:00'); assert.isTrue(result); }); it('should NOT agree when input is NOT LOWER', async () => { - const result = await processOperation( - StrategiesType.TIME, OperationsType.LOWER, '10:00', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.LOWER, mock_values1); + const result = await processOperation(strategyConfig, '10:00'); assert.isFalse(result); }); it('should agree when input is GREATER', async () => { - const result = await processOperation( - StrategiesType.TIME, OperationsType.GREATER, '10:00', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.GREATER, mock_values1); + const result = await processOperation(strategyConfig, '10:00'); assert.isTrue(result); }); it('should agree when input is GREATER or SAME', async () => { - const result = await processOperation( - StrategiesType.TIME, OperationsType.GREATER, '08:00', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.GREATER, mock_values1); + const result = await processOperation(strategyConfig, '08:00'); assert.isTrue(result); }); it('should NOT agree when input is NOT GREATER', async () => { - const result = await processOperation( - StrategiesType.TIME, OperationsType.GREATER, '06:00', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.GREATER, mock_values1); + const result = await processOperation(strategyConfig, '06:00'); assert.isFalse(result); }); it('should agree when input is in BETWEEN', async () => { - const result = await processOperation( - StrategiesType.TIME, OperationsType.BETWEEN, '09:00', mock_values2); + const strategyConfig = givenStrategyConfig(OperationsType.BETWEEN, mock_values2); + const result = await processOperation(strategyConfig, '09:00'); assert.isTrue(result); }); it('should NOT agree when input is NOT in BETWEEN', async () => { - const result = await processOperation( - StrategiesType.TIME, OperationsType.BETWEEN, '07:00', mock_values2); + const strategyConfig = givenStrategyConfig(OperationsType.BETWEEN, mock_values2); + const result = await processOperation(strategyConfig, '07:00'); assert.isFalse(result); }); diff --git a/tests/strategy-operations/value.test.js b/tests/strategy-operations/value.test.js index 84b284c..3af5a8d 100644 --- a/tests/strategy-operations/value.test.js +++ b/tests/strategy-operations/value.test.js @@ -11,45 +11,52 @@ describe('Processing strategy: VALUE', () => { 'USER_1', 'USER_2' ]; + const givenStrategyConfig = (operation, values) => ({ + strategy: StrategiesType.VALUE, + operation: operation, + values: values, + activated: true, + }); + it('should agree when input EXIST', async () => { - const result = await processOperation( - StrategiesType.VALUE, OperationsType.EXIST, 'USER_1', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.EXIST, mock_values1); + const result = await processOperation(strategyConfig, 'USER_1'); assert.isTrue(result); }); it('should NOT agree when input DOES NOT EXIST', async () => { - const result = await processOperation( - StrategiesType.VALUE, OperationsType.EXIST, 'USER_123', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.EXIST, mock_values1); + const result = await processOperation(strategyConfig, 'USER_123'); assert.isFalse(result); }); it('should agree when input DOES NOT EXIST', async () => { - const result = await processOperation( - StrategiesType.VALUE, OperationsType.NOT_EXIST, 'USER_123', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.NOT_EXIST, mock_values1); + const result = await processOperation(strategyConfig, 'USER_123'); assert.isTrue(result); }); it('should agree when input is EQUAL', async () => { - const result = await processOperation( - StrategiesType.VALUE, OperationsType.EQUAL, 'USER_1', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.EQUAL, mock_values1); + const result = await processOperation(strategyConfig, 'USER_1'); assert.isTrue(result); }); it('should NOT agree when input is NOT EQUAL', async () => { - const result = await processOperation( - StrategiesType.VALUE, OperationsType.EQUAL, 'USER_2', mock_values1); + const strategyConfig = givenStrategyConfig(OperationsType.EQUAL, mock_values1); + const result = await processOperation(strategyConfig, 'USER_2'); assert.isFalse(result); }); it('should agree when input is NOT EQUAL', async () => { - const result = await processOperation( - StrategiesType.VALUE, OperationsType.NOT_EQUAL, 'USER_123', mock_values2); + const strategyConfig = givenStrategyConfig(OperationsType.NOT_EQUAL, mock_values2); + const result = await processOperation(strategyConfig, 'USER_123'); assert.isTrue(result); }); it('should NOT agree when input is NOT EQUAL', async () => { - const result = await processOperation( - StrategiesType.VALUE, OperationsType.NOT_EQUAL, 'USER_2', mock_values2); + const strategyConfig = givenStrategyConfig(OperationsType.NOT_EQUAL, mock_values2); + const result = await processOperation(strategyConfig, 'USER_2'); assert.isFalse(result); }); }); \ No newline at end of file diff --git a/tests/switcher-client.test.js b/tests/switcher-client.test.js index 045d489..af571d8 100644 --- a/tests/switcher-client.test.js +++ b/tests/switcher-client.test.js @@ -1,7 +1,7 @@ import { rmdir } from 'fs'; import { assert } from 'chai'; -import { Client, ResultDetail, SwitcherContext, SwitcherOptions } from '../switcher-client.js'; +import { Client, SwitcherContext, SwitcherOptions } from '../switcher-client.js'; import { StrategiesType } from '../src/lib/snapshot.js'; import { assertReject, assertResolve, deleteGeneratedSnapshot } from './helper/utils.js'; import TimedMatch from '../src/lib/utils/timed-match/index.js'; @@ -80,6 +80,11 @@ describe('E2E test - Switcher local:', function () { assert.isTrue(response.result); assert.equal(response.reason, 'Success'); + assert.deepEqual(response.toJSON(), { + result: true, + reason: 'Success', + metadata: undefined + }); }); it('should be valid - No prepare function needed', async function () { @@ -225,6 +230,27 @@ describe('E2E test - Switcher local:', function () { }); +describe('E2E test - Client local #2:', function () { + this.beforeAll(async function () { + Client.buildContext({ domain: contextSettings.domain, environment: 'default_disabled' }, options); + + await Client.loadSnapshot(); + switcher = Client.getSwitcher(); + }); + + this.afterAll(function () { + Client.unloadSnapshot(); + TimedMatch.terminateWorker(); + }); + + it('should be invalid - Client domain disabled', async function () { + assert.isFalse(await switcher.isItOn('FF2FOR2040')); + assert.equal(Client.getLogger('FF2FOR2040')[0].response.reason, + 'Domain disabled'); + }); + +}); + describe('E2E test - Client testing (assume) feature:', function () { this.beforeAll(async function () { Client.buildContext(contextSettings, options); @@ -243,6 +269,16 @@ describe('E2E test - Client testing (assume) feature:', function () { Client.forget('FF2FOR2020'); switcher = Client.getSwitcher(); }); + + it('should replace the result of isItOn with Client.assume', async function () { + await switcher.prepare('DUMMY'); + + Client.assume('DUMMY').true(); + assert.isTrue(await switcher.isItOn()); + + Client.assume('DUMMY').false(); + assert.isFalse(await switcher.isItOn()); + }); it('should be valid assuming key to be false and then forgetting it', async function () { await switcher @@ -325,15 +361,12 @@ describe('Type placeholders:', function () { }); it('should check exported types', function () { - const resultDetail = ResultDetail.build(); const switcherContext = SwitcherContext.build(); const switcherOptions = SwitcherOptions.build(); - assert.isTrue(resultDetail instanceof ResultDetail); assert.isTrue(switcherContext instanceof SwitcherContext); assert.isTrue(switcherOptions instanceof SwitcherOptions); - assert.isNotNull(resultDetail); assert.isNotNull(switcherContext); assert.isNotNull(switcherOptions); }); diff --git a/tests/switcher-functional.test.js b/tests/switcher-functional.test.js index bc6c59b..efd6f4d 100644 --- a/tests/switcher-functional.test.js +++ b/tests/switcher-functional.test.js @@ -293,7 +293,7 @@ describe('Integrated test - Switcher:', function () { fetchStub.restore(); }); - it('should NOT be valid - API returned 429 (too many requests) at checkHealth/auth', async function () { + it('should NOT be valid - API returned 429 (too many requests) at auth', async function () { // given API responses given(fetchStub, 0, { status: 429 }); given(fetchStub, 1, { error: 'Too many requests', status: 429 }); @@ -333,17 +333,24 @@ describe('Integrated test - Switcher:', function () { it('should use silent mode when fail to check criteria', async function () { // given API responses given(fetchStub, 0, { json: () => generateAuth('[auth_token]', 5), status: 200 }); - given(fetchStub, 1, { status: 429 }); + given(fetchStub, 1, { status: 429 }); // [POST@/criteria] + givenError(fetchStub, 2, { errno: 'ECONNREFUSED' }); // [GET@/check] used in the 2nd isItOn call // test let asyncErrorMessage = null; - Client.buildContext(contextSettings, { silentMode: '5m', regexSafe: false, snapshotLocation: './tests/snapshot/' }); + Client.buildContext(contextSettings, { silentMode: '1s', regexSafe: false, snapshotLocation: './tests/snapshot/' }); Client.subscribeNotifyError((error) => asyncErrorMessage = error.message); const switcher = Client.getSwitcher(); + + // assert silent mode being used while registering the error await assertResolve(assert, switcher.isItOn('FF2FOR2021')); await assertUntilResolve(assert, () => asyncErrorMessage, 'Something went wrong: [checkCriteria] failed with status 429'); + + // assert silent mode being used in the next call + await sleep(1500); + await assertResolve(assert, switcher.isItOn('FF2FOR2021')); }); }); @@ -410,7 +417,7 @@ describe('Integrated test - Switcher:', function () { //test Client.buildContext(contextSettings); await assertReject(assert, Client.checkSwitchers(['FEATURE01', 'FEATURE02']), - 'Something went wrong: Something went wrong: [FEATURE02] not found'); + 'Something went wrong: [FEATURE02] not found'); }); it('should throw when no switcher keys were provided', async function() {