Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions src/lib/remote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import {
CriteriaError,
SnapshotServiceError,
} from './exceptions/index.ts';
import { RetryOptions, SwitcherContext, SwitcherOptions } from '../types/index.d.ts';

const getConnectivityError = (code: string) => `Connection has been refused - ${code}`;

const getHeader = (token: string) => {
const getHeader = (token: string | undefined) => {
return {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
Expand All @@ -37,7 +38,7 @@ export const getEntry = (input?: string[][]) => {
return entry;
};

export const checkAPIHealth = async (url: string, options: any) => {
export const checkAPIHealth = async (url: string, options: SwitcherOptions, retryOptions: RetryOptions) => {
try {
const response = await fetch(`${url}/check`, { method: 'get' });
if (response.status != 200) {
Expand All @@ -47,7 +48,7 @@ export const checkAPIHealth = async (url: string, options: any) => {
if (options && 'silentMode' in options) {
if (options.silentMode) {
const expirationTime = new DateMoment(new Date())
.add(options.retryTime, options.retryDurationIn).getDate();
.add(retryOptions.retryTime, retryOptions.retryDurationIn).getDate();

return {
data: {
Expand All @@ -61,7 +62,7 @@ export const checkAPIHealth = async (url: string, options: any) => {
};

export const checkCriteria = async (
context: any,
context: SwitcherContext,
key?: string,
input?: string[][],
showReason = false,
Expand All @@ -85,7 +86,7 @@ export const checkCriteria = async (
}
};

export const auth = async (context: any) => {
export const auth = async (context: SwitcherContext) => {
try {
const response = await fetch(`${context.url}/criteria/auth`, {
method: 'post',
Expand All @@ -95,7 +96,7 @@ export const auth = async (context: any) => {
environment: context.environment,
}),
headers: {
'switcher-api-key': context.apiKey,
'switcher-api-key': context.apiKey || '',
'Content-Type': 'application/json',
},
});
Expand All @@ -108,7 +109,7 @@ export const auth = async (context: any) => {

export const checkSwitchers = async (
url: string,
token: string,
token: string | undefined,
switcherKeys: string[],
) => {
try {
Expand Down
11 changes: 6 additions & 5 deletions src/lib/resolver.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// deno-lint-ignore-file no-explicit-any
import { processOperation } from './snapshot.ts';
import * as services from '../lib/remote.ts';
import { Config, Group, Snapshot, SnapshotData } from '../types/index.d.ts';

async function resolveCriteria(
data: any,
data: SnapshotData,
key: string,
input?: string[][],
) {
Expand Down Expand Up @@ -44,7 +45,7 @@ async function resolveCriteria(
* @return true if Switcher found
*/
async function checkGroup(
groups: any[],
groups: Group[],
key: string,
input?: string[][],
) {
Expand All @@ -68,7 +69,7 @@ async function checkGroup(
* @param {*} input Strategy input if exists
* @return true if Switcher found
*/
async function checkConfig(group: any, config: any, input?: string[][]) {
async function checkConfig(group: Group, config: Config, input?: string[][]) {
if (!config) {
return false;
}
Expand All @@ -88,7 +89,7 @@ async function checkConfig(group: any, config: any, input?: string[][]) {
return true;
}

async function checkStrategy(config: any, input: string[][]) {
async function checkStrategy(config: Config, input: string[][]) {
const { strategies } = config;
const entry = services.getEntry(input);

Expand Down Expand Up @@ -127,7 +128,7 @@ async function checkStrategyInput(entry?: any[], strategyInput?: any) {
}

export default async function checkCriteriaOffline(
snapshot: any,
snapshot: Snapshot | undefined,
key: string,
input?: string[][],
) {
Expand Down
17 changes: 9 additions & 8 deletions src/lib/snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import TimedMatch from './utils/timed-match/index.ts';
import { parseJSON, payloadReader } from './utils/payloadReader.ts';
import { CheckSwitcherError } from './exceptions/index.ts';
import { checkSnapshotVersion, resolveSnapshot } from './remote.ts';
import { Snapshot, SwitcherContext } from '../types/index.d.ts';

export const loadDomain = (snapshotLocation: string, environment: string) => {
let dataJSON;
Expand Down Expand Up @@ -36,23 +37,23 @@ export const loadDomain = (snapshotLocation: string, environment: string) => {
};

export const validateSnapshot = async (
context: any,
snapshotLocation: string,
context: SwitcherContext,
snapshotLocation: string | undefined,
snapshotVersion: number,
) => {
const { status } = await checkSnapshotVersion(
context.url,
context.token,
context.url || '',
context.token || '',
snapshotVersion,
);

if (!status) {
const snapshot = await resolveSnapshot(
context.url,
context.token,
context.url || '',
context.token || '',
context.domain,
context.environment,
context.component,
context.component || '',
);

Deno.writeTextFile(
Expand All @@ -64,7 +65,7 @@ export const validateSnapshot = async (
return false;
};

export const checkSwitchers = (snapshot: any, switcherKeys: string[]) => {
export const checkSwitchers = (snapshot: Snapshot, switcherKeys: string[]) => {
const { group } = snapshot.data.domain;
const notFound = [];
let found = false;
Expand Down
51 changes: 30 additions & 21 deletions src/switcher-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import TimedMatch from './lib/utils/timed-match/index.ts';
import { checkSwitchers, loadDomain, validateSnapshot } from './lib/snapshot.ts';
import * as services from './lib/remote.ts';
import checkCriteriaOffline from './lib/resolver.ts';
import { RetryOptions, Snapshot, SwitcherContext, SwitcherOptions } from './types/index.d.ts';

const DEFAULT_ENVIRONMENT = 'default';
const DEFAULT_SNAPSHOT_LOCATION = './snapshot/';
Expand All @@ -26,9 +27,10 @@ export class Switcher {
private static _watcher: Deno.FsWatcher;
private static _watchDebounce = new Map<string, number>();

private static _snapshot: any;
private static _context: any;
private static _options: any;
private static _snapshot?: Snapshot;
private static _context: SwitcherContext;
private static _options: SwitcherOptions;
private static _retryOptions: RetryOptions;

private _delay = 0;
private _nextRun = 0;
Expand All @@ -41,11 +43,14 @@ export class Switcher {
* @param context Necessary arguments
* @param options
*/
static buildContext(context: any, options?: any) {
static buildContext(context: SwitcherContext, options?: SwitcherOptions) {
this._testEnabled = DEFAULT_TEST_MODE;

this._snapshot = undefined;
this._context = {};
this._context = {
domain: context.domain,
environment: context.environment,
};
this._context = context;
this._context.url = context.url;
this._context.environment = context.environment || DEFAULT_ENVIRONMENT;
Expand Down Expand Up @@ -75,11 +80,15 @@ export class Switcher {
}

if ('retryAfter' in options) {
this._options.retryTime = options.retryAfter.slice(0, -1);
this._options.retryDurationIn = options.retryAfter.slice(-1);
this._retryOptions = {
retryTime: parseInt(options.retryAfter?.slice(0, -1) || DEFAULT_RETRY_TIME.charAt(0)),
retryDurationIn: options.retryAfter?.slice(-1) || DEFAULT_RETRY_TIME.charAt(1),
};
} else {
this._options.retryTime = DEFAULT_RETRY_TIME.charAt(0);
this._options.retryDurationIn = DEFAULT_RETRY_TIME.charAt(1);
this._retryOptions = {
retryTime: parseInt(DEFAULT_RETRY_TIME.charAt(0)),
retryDurationIn: DEFAULT_RETRY_TIME.charAt(1),
};
}

this._initTimedMatch(options);
Expand Down Expand Up @@ -128,11 +137,11 @@ export class Switcher {
*/
static async loadSnapshot(watchSnapshot?: boolean) {
Switcher._snapshot = loadDomain(
Switcher._options.snapshotLocation,
Switcher._options.snapshotLocation || '',
Switcher._context.environment,
);
if (
Switcher._snapshot.data.domain.version == 0 &&
Switcher._snapshot?.data.domain.version == 0 &&
!Switcher._options.offline
) {
await Switcher.checkSnapshot();
Expand Down Expand Up @@ -193,12 +202,12 @@ export class Switcher {
* @throws when one or more Switcher Keys were not found
*/
static async checkSwitchers(switcherKeys: string[]) {
if (Switcher._options.offline) {
if (Switcher._options.offline && Switcher._snapshot) {
checkSwitchers(Switcher._snapshot, switcherKeys);
} else {
await Switcher._auth();
await services.checkSwitchers(
Switcher._context.url,
Switcher._context.url || '',
Switcher._context.token,
switcherKeys,
);
Expand All @@ -210,7 +219,7 @@ export class Switcher {
if (event.kind === 'modify') {
try {
Switcher._snapshot = loadDomain(
Switcher._options.snapshotLocation,
Switcher._options.snapshotLocation || '',
Switcher._context.environment,
);

Expand Down Expand Up @@ -250,8 +259,8 @@ export class Switcher {
) {
const expirationTime = new DateMoment(new Date())
.add(
Switcher._options.retryTime,
Switcher._options.retryDurationIn,
Switcher._retryOptions.retryTime,
Switcher._retryOptions.retryDurationIn,
)
.getDate();

Expand All @@ -260,11 +269,11 @@ export class Switcher {
}
}

const response = await services.checkAPIHealth(Switcher._context.url, {
silentMode: Switcher._options.silentMode,
retryTime: Switcher._options.retryTime,
retryDurationIn: Switcher._options.retryDurationIn,
});
const response = await services.checkAPIHealth(
Switcher._context.url || '',
Switcher._options,
Switcher._retryOptions,
);

if (response) {
Switcher._context.token = response.data.token;
Expand Down
59 changes: 59 additions & 0 deletions src/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,62 @@ declare global {
input: string;
}
}

export interface SwitcherContext {
url?: string;
apiKey?: string;
domain: string;
component?: string;
environment: string;
token?: string;
exp?: number;
}

export interface SwitcherOptions {
offline?: boolean;
logger?: boolean;
snapshotLocation?: string;
silentMode?: boolean;
retryAfter?: string;
regexMaxBlackList?: number;
regexMaxTimeLimit?: number;
}

export interface RetryOptions {
retryTime: number;
retryDurationIn: string;
}

export interface Snapshot {
data: SnapshotData;
}

export interface SnapshotData {
domain: Domain;
}

export interface Domain {
name: string;
version: number;
activated: boolean;
group: Group[];
}

export interface Group {
name: string;
activated: boolean;
config: Config[];
}

export interface Config {
key: string;
activated: boolean;
strategies: Strategy[];
}

export interface Strategy {
strategy: string;
activated: boolean;
operation: string;
values: string[];
}
4 changes: 2 additions & 2 deletions test/switcher-integrated.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// deno-lint-ignore-file no-explicit-any
import { describe, it, afterAll, afterEach, beforeEach } from 'https://deno.land/std@0.188.0/testing/bdd.ts';
import { assertEquals, assertNotEquals, assertRejects, assertFalse } from 'https://deno.land/std@0.188.0/testing/asserts.ts';
import { assertSpyCalls, spy } from 'https://deno.land/std@0.177.0/testing/mock.ts';
Expand All @@ -14,10 +13,11 @@ import {
checkNumeric,
checkPayload
} from '../mod.ts';
import { SwitcherContext } from '../src/types/index.d.ts';

describe('Integrated test - Switcher:', function () {

let contextSettings: any;
let contextSettings: SwitcherContext;

afterAll(function() {
Switcher.unloadSnapshot();
Expand Down
4 changes: 2 additions & 2 deletions test/switcher-snapshot.test.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
// deno-lint-ignore-file no-explicit-any
import { describe, it, afterAll, beforeEach } from 'https://deno.land/std@0.188.0/testing/bdd.ts';
import { assertRejects, assertFalse, assertExists } from 'https://deno.land/std@0.188.0/testing/asserts.ts';
import { delay } from 'https://deno.land/std@0.177.0/async/delay.ts';
import { existsSync } from 'https://deno.land/std@0.110.0/fs/mod.ts';
import { given, givenError, tearDown, generateAuth, generateStatus, assertTrue } from './helper/utils.ts';

import { Switcher } from '../mod.ts';
import { SwitcherContext } from '../src/types/index.d.ts';

const testSettings = { sanitizeOps: false, sanitizeResources: false, sanitizeExit: false };

describe('E2E test - Switcher offline - Snapshot:', function () {
const token = '[token]';
let contextSettings: any;
let contextSettings: SwitcherContext;

const dataBuffer = Deno.readTextFileSync('./snapshot/dev.json');
const dataJSON = dataBuffer.toString();
Expand Down