@gremlin/failure-flags
Advanced tools
Comparing version 0.0.17 to 0.0.18
41
index.js
@@ -27,32 +27,37 @@ /* | ||
let experiment = null; | ||
let experiments = null; | ||
try { | ||
experiment = await fetchExperiment(name, labels, debug); | ||
experiments = await fetchExperiment(name, labels, debug); | ||
} catch(ignore) { | ||
if(debug) console.log('unable to fetch experiment', ignore); | ||
if(debug) console.log('unable to fetch experiments', ignore); | ||
return resolveOrFalse(debug, dataPrototype); | ||
} | ||
if(experiment == null) { | ||
if(debug) console.log('no experiment for', name, labels); | ||
if(experiments == null) { | ||
if(debug) console.log('no experiments for', name, labels); | ||
return resolveOrFalse(debug, dataPrototype); | ||
} | ||
if(!Array.isArray(experiments)) { | ||
experiments = [experiments] | ||
} | ||
if(debug) console.log('fetched experiment', experiment); | ||
if(debug) console.log('fetched experiments: ', experiments); | ||
const dice = Math.random(); | ||
if(experiment.rate && | ||
typeof experiment.rate != "string" && | ||
!isNaN(experiment.rate) && | ||
experiment.rate >= 0 && | ||
experiment.rate <= 1 && | ||
dice > experiment.rate) { | ||
if(debug) console.log('probablistically skipped', behaviorError) | ||
return resolveOrFalse(debug, dataPrototype); | ||
} | ||
filteredExperiments = experiments.filter((experiment) => { | ||
if(typeof experiment.rate == "number" && | ||
!isNaN(experiment.rate) && | ||
experiment.rate >= 0 && | ||
experiment.rate <= 1 && | ||
dice > experiment.rate) { | ||
return false; | ||
} | ||
return true; | ||
}); | ||
if(debug) console.log('filtered experiments: ', filteredExperiments); | ||
try { | ||
if (dataPrototype) { | ||
return await behavior(experiment, dataPrototype); | ||
return await behavior(filteredExperiments, dataPrototype); | ||
} else { | ||
await behavior(experiment); | ||
await behavior(filteredExperiments); | ||
return true; | ||
@@ -59,0 +64,0 @@ } |
@@ -68,2 +68,26 @@ /* | ||
}, | ||
defaultBehaviorZeroRate: [{ | ||
guid: "6884c0df-ed70-4bc8-84c0-dfed703bc8a7", | ||
failureFlagName: "defaultBehaviorZeroRate", | ||
rate: 0, | ||
selector: { | ||
"a":"1", | ||
"b":"2" | ||
}, | ||
effect: { | ||
"latency": "10", | ||
"exception": {} | ||
} | ||
},{ | ||
guid: "6884c0df-ed70-4bc8-84c0-dfed703bc8a7", | ||
failureFlagName: "defaultBehaviorZeroRate", | ||
rate: 0, | ||
selector: { | ||
"a":"1", | ||
"b":"2" | ||
}, | ||
effect: { | ||
"latency": "20" | ||
} | ||
}], | ||
defaultBehaviorWithMessage: { | ||
@@ -94,3 +118,3 @@ guid: "6884c0df-ed70-4bc8-84c0-dfed703bc8a7", | ||
}, | ||
latencySupportsNumber: { | ||
latencySupportsNumber: [{ | ||
guid: "6884c0df-ed70-4bc8-84c0-dfed703bc8a7", | ||
@@ -106,3 +130,3 @@ failureFlagName: "defaultBehavior", | ||
} | ||
}, | ||
}], | ||
latencySupportsString: { | ||
@@ -220,3 +244,3 @@ guid: "6884c0df-ed70-4bc8-84c0-dfed703bc8a7", | ||
behavior: 'not a function', | ||
debug: false})).toBe(false); | ||
debug: false})).toBe(false); | ||
expect(setTimeout).toHaveBeenCalledTimes(0); | ||
@@ -250,2 +274,14 @@ }); | ||
test('ifExperimentActive does nothing if all experiments probablistically skipped', async () => { | ||
try { | ||
expect(await failureflags.ifExperimentActive({ | ||
name: 'defaultBehaviorZeroRate', | ||
labels: {a:'1',b:'2'}, | ||
debug: false})).toBe(true); | ||
} catch(e) { | ||
expect(true).toBe(false); | ||
} | ||
expect(setTimeout).toHaveBeenCalledTimes(0); | ||
}); | ||
test('around / instead example', async () => { | ||
@@ -252,0 +288,0 @@ if (!await failureflags.ifExperimentActive({name:'custom'})) { |
{ | ||
"name": "@gremlin/failure-flags", | ||
"version": "0.0.17", | ||
"version": "0.0.18", | ||
"description": "Failure Flags is a node SDK for working with the Gremlin fault injection platform to build application-level chaos experiments and reliability tests. This library works in concert with Gremlin-Lambda, a Lambda extension, or Gremlin-Container a container sidecar agent. This architecture minimizes the impact to your application code, simplifies configuration, and makes adoption painless.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -16,42 +16,50 @@ /* | ||
*/ | ||
const latency = async (experiment) => { | ||
if (!experiment.effect.latency) | ||
return; | ||
const latency = async (experiments) => { | ||
for (let i = 0; i < experiments.length; ++i) { | ||
let experiment = experiments[i]; | ||
if (!experiment.effect || !experiment.effect.latency) | ||
continue; | ||
const latency = experiment.effect.latency; | ||
if(typeof latency === "number") { | ||
await timeout(latency); | ||
} else if(typeof latency === "string") { | ||
await timeout(parseInt(latency, 10)); | ||
} else if(typeof latency === "object") { | ||
let ms = (latency.ms && typeof latency.ms === "number")? latency.ms : 0; | ||
let jitter = (latency.jitter && typeof latency.jitter === "number")? latency.jitter * Math.random() : 0; | ||
await timeout(ms + jitter); | ||
const latency = experiment.effect.latency; | ||
if(typeof latency === "number") { | ||
await timeout(latency); | ||
} else if(typeof latency === "string") { | ||
await timeout(parseInt(latency, 10)); | ||
} else if(typeof latency === "object") { | ||
let ms = (latency.ms && typeof latency.ms === "number")? latency.ms : 0; | ||
let jitter = (latency.jitter && typeof latency.jitter === "number")? latency.jitter * Math.random() : 0; | ||
await timeout(ms + jitter); | ||
} | ||
} | ||
} | ||
const exception = (experiment) => { | ||
if (!experiment.effect.exception) | ||
return; | ||
const exception = (experiments) => { | ||
for (let i = 0; i < experiments.length; ++i) { | ||
let experiment = experiments[i]; | ||
if (!experiment.effect || !experiment.effect.exception) | ||
continue; | ||
const exception = experiment.effect.exception; | ||
if (typeof exception === "string") { | ||
throw new Error(exception); | ||
} else if (typeof exception === "object") { | ||
let toThrow = new Error('Exception injected by Failure Flags'); | ||
Object.assign(toThrow, exception) | ||
throw toThrow; | ||
const exception = experiment.effect.exception; | ||
if (typeof exception === "string") { | ||
throw new Error(exception); | ||
} else if (typeof exception === "object") { | ||
let toThrow = new Error('Exception injected by Failure Flags'); | ||
Object.assign(toThrow, exception) | ||
throw toThrow; | ||
} | ||
} | ||
} | ||
const data = async (experiment, prototype) => { | ||
if (!experiment.effect.data || typeof experiment.effect.data !== "object") | ||
return prototype; | ||
const data = async (experiments, prototype) => { | ||
let toUse = prototype? prototype : {}; | ||
for (let i = 0; i < experiments.length; ++i) { | ||
let experiment = experiments[i]; | ||
if (!experiment.effect || !experiment.effect.data || typeof experiment.effect.data !== "object") | ||
continue; | ||
const data = experiment.effect.data; | ||
const res = Object.create(toUse); | ||
Object.assign(res, data); | ||
return res; | ||
const data = experiment.effect.data; | ||
const res = Object.create(toUse); | ||
Object.assign(res, data); | ||
return res; | ||
} | ||
} | ||
@@ -58,0 +66,0 @@ |
42984
640