зеркало из https://github.com/mozilla/fxa-shared.git
feat(feature-flags): implement LaunchDarkly abstraction
This commit is contained in:
Родитель
f7f0f49c29
Коммит
681d27d4d7
|
@ -21,7 +21,7 @@ module.exports = initialise;
|
|||
* @returns {FeatureFlags}
|
||||
*/
|
||||
function initialise (config, defaults) {
|
||||
const implementation = require(`./${config.implementation}`)(config);
|
||||
const implementation = require(`./${config.implementation}`)(config[config.implementation]);
|
||||
const { interval } = config;
|
||||
|
||||
if (! (interval > 0 && interval !== Infinity)) {
|
||||
|
|
|
@ -4,19 +4,40 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const request = require('request-promise');
|
||||
|
||||
const BASE_URI = 'https://app.launchdarkly.com/api/v2/flags';
|
||||
const { NODE_ENV: ENV } = process.env;
|
||||
const RETRY_LIMIT = 3;
|
||||
const PERMANENT_ERRORS = new Set([ 400, 401, 409 ]);
|
||||
|
||||
module.exports = initialise;
|
||||
|
||||
/**
|
||||
* Initialise the LaunchDarkly implementation.
|
||||
*
|
||||
* API docs: https://apidocs.launchdarkly.com/v2.0/docs
|
||||
*
|
||||
* @param {Object} config
|
||||
* @param {Object} log
|
||||
* @param {String} config.accessToken
|
||||
* @param {String} config.projectKey
|
||||
* @param {Object} config.redis
|
||||
* @param {Boolean} config.redis.enabled
|
||||
* @param {String} config.redis.host
|
||||
* @param {Number} config.redis.port
|
||||
* @param {String} config.redis.prefix
|
||||
*
|
||||
* @returns {FeatureFlags}
|
||||
*/
|
||||
function initialise () {
|
||||
function initialise (config) {
|
||||
const { accessToken: ACCESS_TOKEN } = config;
|
||||
const FLAGS_URL = `${BASE_URI}/${config.projectKey}?env=${ENV}`;
|
||||
|
||||
// TODO: flesh out implementation
|
||||
if (config.redis.enabled) {
|
||||
// TODO: set up redis
|
||||
// TODO: move this up a level if it turns out we have to
|
||||
// do it manually for each implementation
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} FeatureFlags
|
||||
|
@ -30,7 +51,58 @@ function initialise () {
|
|||
*
|
||||
* @returns {Promise}
|
||||
*/
|
||||
function get () {
|
||||
return Promise.reject(new Error('Not implemented'));
|
||||
async function get (iteration = 0) {
|
||||
try {
|
||||
return JSON.parse(
|
||||
await request(FLAGS_URL, {
|
||||
simple: true,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
authorization: ACCESS_TOKEN
|
||||
}
|
||||
})
|
||||
).items.reduce(reduceFlags, {});
|
||||
} catch (response) {
|
||||
const { statusCode } = response;
|
||||
|
||||
if (iteration === RETRY_LIMIT || PERMANENT_ERRORS.has(statusCode)) {
|
||||
throw response;
|
||||
}
|
||||
|
||||
if (statusCode === 429) {
|
||||
let backoff = parseInt(response.headers['retry-after']) * 1000;
|
||||
if (isNaN(backoff)) {
|
||||
backoff = parseInt(response.headers['x-ratelimit-reset']) - Date.now();
|
||||
}
|
||||
|
||||
if (backoff > 0) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
get(iteration + 1)
|
||||
.then(resolve, reject);
|
||||
}, backoff);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return get(iteration + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function reduceFlags (flags, flag) {
|
||||
const variations = flag.variations.map(({ value }) => {
|
||||
try {
|
||||
if (typeof value === 'string') {
|
||||
return JSON.parse(value);
|
||||
}
|
||||
} catch (error) {
|
||||
}
|
||||
|
||||
return value;
|
||||
});
|
||||
// XXX: This doesn't work where there is more than one variation
|
||||
// XXX: This doesn't work if the default variation is changed in the LaunchDarkly UI
|
||||
flags[flag.key] = flag.environments[ENV].on ? variations[0] : variations[1];
|
||||
return flags;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fxa-shared",
|
||||
"version": "1.0.15",
|
||||
"version": "1.0.18",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -136,12 +136,40 @@
|
|||
"integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
|
||||
"dev": true
|
||||
},
|
||||
"asn1": {
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
|
||||
"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
|
||||
"requires": {
|
||||
"safer-buffer": "~2.1.0"
|
||||
}
|
||||
},
|
||||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
||||
},
|
||||
"assertion-error": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
|
||||
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
|
||||
"dev": true
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
||||
},
|
||||
"aws-sign2": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
||||
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
|
||||
},
|
||||
"aws4": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
|
||||
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
|
||||
},
|
||||
"babel-code-frame": {
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
|
||||
|
@ -188,6 +216,19 @@
|
|||
"resolved": "https://registry.npmjs.org/bcp47/-/bcp47-1.1.2.tgz",
|
||||
"integrity": "sha1-NUvjMH/9CEM6ePXh4glYRfifx/4="
|
||||
},
|
||||
"bcrypt-pbkdf": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
|
||||
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
|
||||
"requires": {
|
||||
"tweetnacl": "^0.14.3"
|
||||
}
|
||||
},
|
||||
"bluebird": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz",
|
||||
"integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw=="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
|
@ -225,6 +266,11 @@
|
|||
"integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
|
||||
"dev": true
|
||||
},
|
||||
"caseless": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
|
||||
},
|
||||
"chai": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz",
|
||||
|
@ -324,6 +370,14 @@
|
|||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"dev": true
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
|
||||
"integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==",
|
||||
"requires": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.11.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
|
||||
|
@ -351,8 +405,7 @@
|
|||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
||||
"dev": true
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "5.1.0",
|
||||
|
@ -365,6 +418,14 @@
|
|||
"which": "^1.2.9"
|
||||
}
|
||||
},
|
||||
"dashdash": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
||||
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "3.2.5",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz",
|
||||
|
@ -404,6 +465,11 @@
|
|||
"rimraf": "^2.2.8"
|
||||
}
|
||||
},
|
||||
"delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
||||
},
|
||||
"diff": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
|
||||
|
@ -419,6 +485,15 @@
|
|||
"esutils": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"ecc-jsbn": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
|
||||
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
|
||||
"requires": {
|
||||
"jsbn": "~0.1.0",
|
||||
"safer-buffer": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
|
@ -538,6 +613,11 @@
|
|||
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
|
||||
"dev": true
|
||||
},
|
||||
"extend": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
|
||||
},
|
||||
"external-editor": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
|
||||
|
@ -549,6 +629,11 @@
|
|||
"tmp": "^0.0.33"
|
||||
}
|
||||
},
|
||||
"extsprintf": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
|
||||
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
|
||||
|
@ -558,8 +643,7 @@
|
|||
"fast-json-stable-stringify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
|
||||
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
|
||||
"dev": true
|
||||
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
|
||||
},
|
||||
"fast-levenshtein": {
|
||||
"version": "2.0.6",
|
||||
|
@ -608,6 +692,21 @@
|
|||
"write": "^0.2.1"
|
||||
}
|
||||
},
|
||||
"forever-agent": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
||||
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
|
||||
},
|
||||
"form-data": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
|
||||
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.6",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
|
@ -626,6 +725,14 @@
|
|||
"integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
|
||||
"dev": true
|
||||
},
|
||||
"getpass": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
|
||||
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
|
||||
|
@ -672,6 +779,43 @@
|
|||
"integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==",
|
||||
"dev": true
|
||||
},
|
||||
"har-schema": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
||||
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
|
||||
},
|
||||
"har-validator": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
|
||||
"integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
|
||||
"requires": {
|
||||
"ajv": "^6.5.5",
|
||||
"har-schema": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": {
|
||||
"version": "6.8.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.8.1.tgz",
|
||||
"integrity": "sha512-eqxCp82P+JfqL683wwsL73XmFs1eG6qjw+RD3YHx+Jll1r0jNd4dh8QG9NYAeNGA/hnZjeEDgtTskgJULbxpWQ==",
|
||||
"requires": {
|
||||
"fast-deep-equal": "^2.0.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
|
||||
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"has-ansi": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
|
||||
|
@ -693,6 +837,16 @@
|
|||
"integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
|
||||
"dev": true
|
||||
},
|
||||
"http-signature": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
|
||||
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0",
|
||||
"jsprim": "^1.2.2",
|
||||
"sshpk": "^1.7.0"
|
||||
}
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
|
@ -800,6 +954,11 @@
|
|||
"integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==",
|
||||
"dev": true
|
||||
},
|
||||
"is-typedarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
|
||||
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
|
@ -812,6 +971,11 @@
|
|||
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
|
||||
"dev": true
|
||||
},
|
||||
"isstream": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
||||
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
|
||||
|
@ -828,6 +992,16 @@
|
|||
"esprima": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"jsbn": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
|
||||
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
|
||||
},
|
||||
"json-schema": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
|
||||
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
|
||||
|
@ -840,6 +1014,22 @@
|
|||
"integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
|
||||
"dev": true
|
||||
},
|
||||
"json-stringify-safe": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
|
||||
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
|
||||
},
|
||||
"jsprim": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
|
||||
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0",
|
||||
"extsprintf": "1.3.0",
|
||||
"json-schema": "0.2.3",
|
||||
"verror": "1.10.0"
|
||||
}
|
||||
},
|
||||
"just-extend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz",
|
||||
|
@ -859,8 +1049,7 @@
|
|||
"lodash": {
|
||||
"version": "4.17.11",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
|
||||
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
|
||||
},
|
||||
"lodash.get": {
|
||||
"version": "4.4.2",
|
||||
|
@ -890,6 +1079,19 @@
|
|||
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
|
||||
"dev": true
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.37.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz",
|
||||
"integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg=="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.21",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz",
|
||||
"integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==",
|
||||
"requires": {
|
||||
"mime-db": "~1.37.0"
|
||||
}
|
||||
},
|
||||
"mimic-fn": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
|
||||
|
@ -1034,6 +1236,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"oauth-sign": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
|
||||
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
|
@ -1119,6 +1326,11 @@
|
|||
"integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
|
||||
"dev": true
|
||||
},
|
||||
"performance-now": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
|
||||
},
|
||||
"pify": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
|
@ -1181,6 +1393,21 @@
|
|||
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
|
||||
"dev": true
|
||||
},
|
||||
"psl": {
|
||||
"version": "1.1.31",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz",
|
||||
"integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw=="
|
||||
},
|
||||
"punycode": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
|
@ -1202,6 +1429,52 @@
|
|||
"integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==",
|
||||
"dev": true
|
||||
},
|
||||
"request": {
|
||||
"version": "2.88.0",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
|
||||
"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
|
||||
"requires": {
|
||||
"aws-sign2": "~0.7.0",
|
||||
"aws4": "^1.8.0",
|
||||
"caseless": "~0.12.0",
|
||||
"combined-stream": "~1.0.6",
|
||||
"extend": "~3.0.2",
|
||||
"forever-agent": "~0.6.1",
|
||||
"form-data": "~2.3.2",
|
||||
"har-validator": "~5.1.0",
|
||||
"http-signature": "~1.2.0",
|
||||
"is-typedarray": "~1.0.0",
|
||||
"isstream": "~0.1.2",
|
||||
"json-stringify-safe": "~5.0.1",
|
||||
"mime-types": "~2.1.19",
|
||||
"oauth-sign": "~0.9.0",
|
||||
"performance-now": "^2.1.0",
|
||||
"qs": "~6.5.2",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"tough-cookie": "~2.4.3",
|
||||
"tunnel-agent": "^0.6.0",
|
||||
"uuid": "^3.3.2"
|
||||
}
|
||||
},
|
||||
"request-promise": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz",
|
||||
"integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=",
|
||||
"requires": {
|
||||
"bluebird": "^3.5.0",
|
||||
"request-promise-core": "1.1.1",
|
||||
"stealthy-require": "^1.1.0",
|
||||
"tough-cookie": ">=2.3.3"
|
||||
}
|
||||
},
|
||||
"request-promise-core": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz",
|
||||
"integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=",
|
||||
"requires": {
|
||||
"lodash": "^4.13.1"
|
||||
}
|
||||
},
|
||||
"require-uncached": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
|
||||
|
@ -1273,14 +1546,12 @@
|
|||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"dev": true
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.5.1",
|
||||
|
@ -1350,6 +1621,27 @@
|
|||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
|
||||
"dev": true
|
||||
},
|
||||
"sshpk": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
|
||||
"integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
|
||||
"requires": {
|
||||
"asn1": "~0.2.3",
|
||||
"assert-plus": "^1.0.0",
|
||||
"bcrypt-pbkdf": "^1.0.0",
|
||||
"dashdash": "^1.12.0",
|
||||
"ecc-jsbn": "~0.1.1",
|
||||
"getpass": "^0.1.1",
|
||||
"jsbn": "~0.1.0",
|
||||
"safer-buffer": "^2.0.2",
|
||||
"tweetnacl": "~0.14.0"
|
||||
}
|
||||
},
|
||||
"stealthy-require": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
|
||||
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||
|
@ -1439,6 +1731,35 @@
|
|||
"os-tmpdir": "~1.0.2"
|
||||
}
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "2.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
|
||||
"integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
|
||||
"requires": {
|
||||
"psl": "^1.1.24",
|
||||
"punycode": "^1.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"punycode": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
|
||||
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
|
||||
}
|
||||
}
|
||||
},
|
||||
"tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
|
||||
"requires": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"tweetnacl": {
|
||||
"version": "0.14.5",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
||||
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
|
||||
},
|
||||
"type-check": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
|
||||
|
@ -1460,12 +1781,35 @@
|
|||
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
|
||||
"dev": true
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
|
||||
"integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
|
||||
"requires": {
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
|
||||
"dev": true
|
||||
},
|
||||
"uuid": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
|
||||
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
|
||||
},
|
||||
"verror": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
||||
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0",
|
||||
"core-util-is": "1.0.2",
|
||||
"extsprintf": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"which": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
"bluebird": "3.5.3",
|
||||
"generic-pool": "3.6.1",
|
||||
"moment": "2.20.1",
|
||||
"redis": "2.8.0"
|
||||
"redis": "2.8.0",
|
||||
"request": "2.88.0",
|
||||
"request-promise": "4.2.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,7 +94,10 @@ describe('feature-flags/index:', () => {
|
|||
beforeEach(done => {
|
||||
featureFlags = initialise({
|
||||
implementation: 'foo',
|
||||
interval: 300000
|
||||
interval: 300000,
|
||||
foo: {
|
||||
bar: 'baz'
|
||||
}
|
||||
});
|
||||
resolve({ bar: 'baz' });
|
||||
setImmediate(done);
|
||||
|
@ -113,8 +116,7 @@ describe('feature-flags/index:', () => {
|
|||
const args = implementationFactory.args[0];
|
||||
assert.lengthOf(args, 1);
|
||||
assert.deepEqual(args[0], {
|
||||
implementation: 'foo',
|
||||
interval: 300000
|
||||
bar: 'baz'
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,376 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
'use strict';
|
||||
|
||||
const { assert } = require('chai');
|
||||
const proxyquire = require('proxyquire').noCallThru();
|
||||
const sinon = require('sinon');
|
||||
|
||||
describe('feature-flags/launch-darkly:', () => {
|
||||
let response, request, initialise, origSetTimeout;
|
||||
|
||||
beforeEach(() => {
|
||||
origSetTimeout = setTimeout;
|
||||
// eslint-disable-next-line no-global-assign
|
||||
setTimeout = sinon.spy();
|
||||
request = sinon.spy(() => {
|
||||
if (response.isError) {
|
||||
return Promise.reject(response);
|
||||
}
|
||||
return Promise.resolve(response);
|
||||
});
|
||||
initialise = proxyquire('../../feature-flags/launch-darkly', {
|
||||
'request-promise': request
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// eslint-disable-next-line no-global-assign
|
||||
setTimeout = origSetTimeout;
|
||||
});
|
||||
|
||||
it('returned the expected interface', () => {
|
||||
assert.isFunction(initialise);
|
||||
assert.lengthOf(initialise, 1);
|
||||
});
|
||||
|
||||
it('does not throw if config is valid', () => {
|
||||
assert.doesNotThrow(() => initialise({
|
||||
accessToken: 'foo',
|
||||
projectKey: 'bar',
|
||||
redis: {
|
||||
enabled: true,
|
||||
host: '127.0.0.1',
|
||||
port: 6379,
|
||||
prefix: 'featureFlags:'
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
it('throws if config is missing', () => {
|
||||
assert.throws(() => initialise());
|
||||
});
|
||||
|
||||
it('throws if redis settings aren\'t set', () => {
|
||||
assert.throws(() => initialise({
|
||||
accessToken: 'foo',
|
||||
projectKey: 'bar'
|
||||
}));
|
||||
});
|
||||
|
||||
describe('initialise:', () => {
|
||||
let launchDarkly;
|
||||
|
||||
beforeEach(() => {
|
||||
launchDarkly = initialise({
|
||||
accessToken: 'foo',
|
||||
projectKey: 'bar',
|
||||
redis: {
|
||||
enabled: true,
|
||||
host: '127.0.0.1',
|
||||
port: 6379,
|
||||
prefix: 'featureFlags:'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('returned the expected interface', () => {
|
||||
assert.isObject(launchDarkly);
|
||||
assert.isFunction(launchDarkly.get);
|
||||
assert.lengthOf(launchDarkly.get, 0);
|
||||
});
|
||||
|
||||
it('did not call request', () => {
|
||||
assert.equal(request.callCount, 0);
|
||||
});
|
||||
|
||||
describe('get with successful request:', () => {
|
||||
let result;
|
||||
|
||||
beforeEach(async () => {
|
||||
response = JSON.stringify({
|
||||
items: [
|
||||
{
|
||||
environments: {
|
||||
[process.env.NODE_ENV]: {
|
||||
on: true
|
||||
}
|
||||
},
|
||||
key: 'foo',
|
||||
variations: [
|
||||
{ value: true },
|
||||
{ value: false }
|
||||
]
|
||||
},
|
||||
{
|
||||
environments: {
|
||||
[process.env.NODE_ENV]: {
|
||||
on: false
|
||||
}
|
||||
},
|
||||
key: 'bar',
|
||||
variations: [
|
||||
{ value: '{"wibble":"blee"}' },
|
||||
{ value: '{"blee":"wibble"}' }
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
result = await launchDarkly.get();
|
||||
});
|
||||
|
||||
it('returned the response body', () => {
|
||||
assert.deepEqual(result, {
|
||||
foo: true,
|
||||
bar: {
|
||||
blee: 'wibble'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('called request correctly', () => {
|
||||
assert.equal(request.callCount, 1);
|
||||
const args = request.args[0];
|
||||
assert.lengthOf(args, 2);
|
||||
assert.equal(args[0], `https://app.launchdarkly.com/api/v2/flags/bar?env=${process.env.NODE_ENV}`);
|
||||
assert.deepEqual(args[1], {
|
||||
simple: true,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
authorization: 'foo'
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
[ 400, 401, 409 ].forEach(statusCode => {
|
||||
describe(`get with ${statusCode} response:`, () => {
|
||||
let error;
|
||||
|
||||
beforeEach(() => {
|
||||
response = {
|
||||
isError: true,
|
||||
statusCode,
|
||||
headers: {
|
||||
'retry-after': 10,
|
||||
'x-ratelimit-reset': Date.now() + 2000
|
||||
}
|
||||
};
|
||||
return launchDarkly.get().then(() => {}, e => error = e);
|
||||
});
|
||||
|
||||
it('rejected', () => {
|
||||
assert.equal(error, response);
|
||||
});
|
||||
|
||||
it('called request', () => {
|
||||
assert.equal(request.callCount, 1);
|
||||
});
|
||||
|
||||
it('did not call setTimeout', () => {
|
||||
assert.equal(setTimeout.callCount, 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('get with 429 response and Retry-After header:', () => {
|
||||
let completed, result, error;
|
||||
|
||||
beforeEach(done => {
|
||||
response = {
|
||||
isError: true,
|
||||
statusCode: 429,
|
||||
headers: {
|
||||
'retry-after': 10,
|
||||
'x-ratelimit-reset': Date.now() + 2000
|
||||
}
|
||||
};
|
||||
completed = false;
|
||||
launchDarkly.get().then(r => {
|
||||
completed = true;
|
||||
result = r;
|
||||
}, e => {
|
||||
completed = true;
|
||||
error = e;
|
||||
});
|
||||
setImmediate(done);
|
||||
});
|
||||
|
||||
it('did not complete', () => {
|
||||
assert.isFalse(completed);
|
||||
});
|
||||
|
||||
it('called request', () => {
|
||||
assert.equal(request.callCount, 1);
|
||||
});
|
||||
|
||||
it('called setTimeout correctly', () => {
|
||||
assert.equal(setTimeout.callCount, 1);
|
||||
const args = setTimeout.args[0];
|
||||
assert.lengthOf(args, 2);
|
||||
assert.isFunction(args[0]);
|
||||
assert.equal(args[1], 10000);
|
||||
});
|
||||
|
||||
describe('retry successfully:', () => {
|
||||
beforeEach(done => {
|
||||
response = JSON.stringify({
|
||||
items: [
|
||||
{
|
||||
environments: {
|
||||
[process.env.NODE_ENV]: {
|
||||
on: false
|
||||
}
|
||||
},
|
||||
key: 'foo',
|
||||
variations: [
|
||||
{ value: true },
|
||||
{ value: false }
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
setTimeout.args[0][0]();
|
||||
setImmediate(done);
|
||||
});
|
||||
|
||||
it('resolved', () => {
|
||||
assert.isTrue(completed);
|
||||
assert.deepEqual(result, {
|
||||
foo: false
|
||||
});
|
||||
});
|
||||
|
||||
it('called request', () => {
|
||||
assert.equal(request.callCount, 2);
|
||||
});
|
||||
|
||||
it('did not call setTimeout', () => {
|
||||
assert.equal(setTimeout.callCount, 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('retry unsuccessfully:', () => {
|
||||
beforeEach(done => {
|
||||
setTimeout.args[0][0]();
|
||||
setImmediate(done);
|
||||
});
|
||||
|
||||
it('did not complete', () => {
|
||||
assert.isFalse(completed);
|
||||
});
|
||||
|
||||
it('called request', () => {
|
||||
assert.equal(request.callCount, 2);
|
||||
});
|
||||
|
||||
it('called setTimeout', () => {
|
||||
assert.equal(setTimeout.callCount, 2);
|
||||
});
|
||||
|
||||
describe('retry unsuccessfully:', () => {
|
||||
beforeEach(done => {
|
||||
setTimeout.args[1][0]();
|
||||
setImmediate(done);
|
||||
});
|
||||
|
||||
it('did not complete', () => {
|
||||
assert.isFalse(completed);
|
||||
});
|
||||
|
||||
it('called request', () => {
|
||||
assert.equal(request.callCount, 3);
|
||||
});
|
||||
|
||||
it('called setTimeout', () => {
|
||||
assert.equal(setTimeout.callCount, 3);
|
||||
});
|
||||
|
||||
describe('retry unsuccessfully:', () => {
|
||||
beforeEach(done => {
|
||||
setTimeout.args[2][0]();
|
||||
setImmediate(done);
|
||||
});
|
||||
|
||||
it('rejected', () => {
|
||||
assert.isTrue(completed);
|
||||
assert.equal(error, response);
|
||||
});
|
||||
|
||||
it('called request', () => {
|
||||
assert.equal(request.callCount, 4);
|
||||
});
|
||||
|
||||
it('did not call setTimeout', () => {
|
||||
assert.equal(setTimeout.callCount, 3);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('get with 429 response and X-Ratelimit-Reset header:', () => {
|
||||
let completed;
|
||||
|
||||
beforeEach(done => {
|
||||
response = {
|
||||
isError: true,
|
||||
statusCode: 429,
|
||||
headers: {
|
||||
'x-ratelimit-reset': Date.now() + 2000
|
||||
}
|
||||
};
|
||||
completed = false;
|
||||
launchDarkly.get().then(() => completed = true, () => completed = true);
|
||||
setImmediate(done);
|
||||
});
|
||||
|
||||
it('did not complete', () => {
|
||||
assert.isFalse(completed);
|
||||
});
|
||||
|
||||
it('called request', () => {
|
||||
assert.equal(request.callCount, 1);
|
||||
});
|
||||
|
||||
it('called setTimeout correctly', () => {
|
||||
assert.equal(setTimeout.callCount, 1);
|
||||
const args = setTimeout.args[0];
|
||||
assert.lengthOf(args, 2);
|
||||
assert.isFunction(args[0]);
|
||||
assert.isAbove(args[1], 1000);
|
||||
assert.isAtMost(args[1], 2000);
|
||||
});
|
||||
});
|
||||
|
||||
describe('get with 500 response:', () => {
|
||||
let error;
|
||||
|
||||
beforeEach(() => {
|
||||
response = {
|
||||
isError: true,
|
||||
statusCode: 500,
|
||||
headers: {
|
||||
'retry-after': 10,
|
||||
'x-ratelimit-reset': Date.now() + 2000
|
||||
}
|
||||
};
|
||||
return launchDarkly.get().then(() => {}, e => error = e);
|
||||
});
|
||||
|
||||
it('rejected', () => {
|
||||
assert.equal(error, response);
|
||||
});
|
||||
|
||||
it('called request four times', () => {
|
||||
assert.equal(request.callCount, 4);
|
||||
});
|
||||
|
||||
it('did not call setTimeout', () => {
|
||||
assert.equal(setTimeout.callCount, 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Загрузка…
Ссылка в новой задаче