diff --git a/lib/is-flaky.js b/lib/is-flaky.js new file mode 100644 index 000000000..8a8a775bd --- /dev/null +++ b/lib/is-flaky.js @@ -0,0 +1,44 @@ +'use strict'; + +var _ = require('lodash'); +var lsb = require('dotenv').config({path: '/etc/lsb-release', silent: true}); + +var distro = lsb['DISTRIB_ID'] || ''; +var release = lsb['DISTRIB_RELEASE'] || ''; +var version = process.version; +var platform = [process.platform, process.arch].join('-'); + +function isStringFlaky(flaky) { + var checks = [distro, release, version, platform]; + return _.some(checks, function (check) { + return check.search(flaky) !== -1; + }); +} + +function isArrayFlaky(arr) { + return _.some(arr, function(item) { + if (typeof item === 'string') return isStringFlaky(item); + if (typeof item === 'object') return isObjectFlaky(item); + return false; + }); +} + +function isObjectFlaky(obj) { + return _.some(obj, function(value, key) { + if (!isStringFlaky(key)) return false; + if (typeof value === 'boolean') return value; + if (typeof value === 'string') return isStringFlaky(value); + if (value instanceof Array) return isArrayFlaky(value); + return false; + }); +} + +function isFlaky(flaky) { + if (typeof flaky === 'boolean') return flaky; + if (typeof flaky === 'string') return isStringFlaky(flaky); + if (flaky instanceof Array) return isArrayFlaky(flaky); + if (typeof flaky === 'object') return isObjectFlaky(flaky); + return false; +} + +module.exports = isFlaky; diff --git a/lib/lookup.js b/lib/lookup.js index a1ea229ec..45cd6b934 100644 --- a/lib/lookup.js +++ b/lib/lookup.js @@ -3,6 +3,8 @@ var normgit = require('normalize-git-url'); var util = require('util'); var path = require('path'); +var isFlaky = require('./is-flaky'); + // construct the tarball url using the repo, spec and prefix config function makeUrl(repo, spec, tags, prefix) { prefix = prefix || ''; @@ -83,6 +85,7 @@ function resolve(context, next) { context.emit('info','lookup-script',rep.script); context.options.script = rep.script; } + context.module.flaky = isFlaky(context.module.flaky); } else { context.emit('info','lookup-notfound',detail.name); } diff --git a/lib/lookup.json b/lib/lookup.json index c51278342..079e840a0 100644 --- a/lib/lookup.json +++ b/lib/lookup.json @@ -34,7 +34,8 @@ }, "glob": { "replace": true, - "prefix": "v" + "prefix": "v", + "flaky": ["v6", "v7"] }, "gulp-util": { "replace": true, @@ -52,7 +53,8 @@ "replace": true }, "body-parser": { - "replace": true + "replace": true, + "flaky": ["v6", "v7"] }, "uglify-js": { "replace": true, @@ -73,7 +75,7 @@ "eslint": { "replace": true, "prefix": "v", - "flaky": true + "flaky": "ppc" }, "tape": { "replace": true, @@ -102,7 +104,7 @@ "react": { "replace": true, "prefix": "v", - "flaky": true + "flaky": ["v6", "v7"] }, "gulp": { "replace": true, diff --git a/package.json b/package.json index 061992daf..40340ed6c 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "chalk": "^1.1.3", "columnify": "^1.5.1", "commander": "^2.8.1", + "dotenv": "^2.0.0", "lodash": "^4.6.1", "node-uuid": "^1.4.3", "normalize-git-url": "^3.0.1", diff --git a/test/test-is-flaky.js b/test/test-is-flaky.js new file mode 100644 index 000000000..170a60ed5 --- /dev/null +++ b/test/test-is-flaky.js @@ -0,0 +1,133 @@ +'use strict'; + +var test = require('tap').test; +var rewire = require('rewire'); + +var isFlaky = rewire('../lib/is-flaky'); + +var platformCache = isFlaky.__get__('platform'); +var versionCache = isFlaky.__get__('version'); + +var flake = { + v5: ['darwin', 'hurd', 'x86'] +}; + +var notFlake = { + v4: ['darwin', 'hurd', 'x86'], + x86: 'hurd', + darwin: 'v0.10' +}; + +var invalid = { + 'v5': [123, false, false] +}; + +function shim() { + isFlaky.__set__('version', 'v5.3.1'); + isFlaky.__set__('platform', 'darwin-x64'); +} + +function revertShim() { + isFlaky.__set__('version', versionCache); + isFlaky.__set__('platform', platformCache); +} + +function testVersions(t, testFunction) { + t.ok(testFunction(process.version), 'the current version is what it is matched against'); + shim(); + t.ok(testFunction('v5'), 'the module is flaky on the current platform'); + t.notok(testFunction('v2'), 'the module is not flaky on the current platform'); + revertShim(); +} + +function testPlatforms(t, testFunction) { + t.ok(testFunction(process.platform), 'the current platform is what it is matched against'); + shim(); + t.ok(testFunction('darwin'), 'darwin is flaky'); + t.ok(testFunction('x64'), 'x64 is flaky'); + t.ok(testFunction('darwin-x64'), 'darwin-x64 is flaky'); + t.notok(testFunction('darwin-x86'), 'darwin-x86 is stable'); + t.notok(testFunction('hurd-x86'), 'hurd-x86 is stable'); + t.notok(testFunction('hurd-x64'), 'hurd-x64 is stable'); + t.notok(testFunction('hurd'), 'hurd is stable'); + revertShim(); +} + +function testArrays(t, testFunction) { + shim(); + t.ok(testFunction([ + flake, + flake, + notFlake, + invalid + ]), 'flaky array of object'); + t.notok(testFunction([ + notFlake, + notFlake, + notFlake, + invalid + ]), 'not flaky array of objects'); + + t.ok(testFunction([ + 'hurd', + 'x86', + 'v4', + 'darwin' + ]), 'flakey array of string'); + + t.notok(testFunction([ + 'hurd', + 'x86', + 'v4' + ]), 'not flakey array of string'); + + t.notok(testFunction([ + true, + false, + 123 + ]), 'not flaky invalid input'); + + revertShim(); +} + +function testObjects(t, testFunction) { + shim(); + t.ok(testFunction(flake), 'it should be flake'); + t.notok(testFunction(notFlake), 'it should not be flake'); + t.notok(testFunction(invalid), 'invalid input should not give a false positive'); + t.notok(testFunction({ + a: 123, + v5: false + }), 'another invalid input that should not give a false positive'); + revertShim(); +} + +test('isStringFlaky', function (t) { + var isStringFlaky = isFlaky.__get__('isStringFlaky'); + testVersions(t, isStringFlaky); + testPlatforms(t, isStringFlaky); + t.end(); +}); + +test('isObjectFlaky', function (t) { + var isObjectFlaky = isFlaky.__get__('isObjectFlaky'); + testObjects(t, isObjectFlaky); + t.end(); +}); + +test('isArrayFlaky', function (t) { + var isArrayFlaky = isFlaky.__get__('isArrayFlaky'); + testArrays(t, isArrayFlaky); + t.end(); +}); + +test('isFlaky', function (t) { + testVersions(t, isFlaky); + testPlatforms(t, isFlaky); + testArrays(t, isFlaky); + testObjects(t, isFlaky); + t.ok(isFlaky(true), 'true is flaky'); + t.notok(isFlaky(false), 'false is not flaky'); + t.notok(isFlaky(123), 'invalid input is not flaky'); + t.end(); +});