[system_tracking] Extract parameters into options object

This commit is contained in:
Joe Fiorini
2015-06-12 13:50:28 -04:00
parent b0d773325b
commit ad0f267435
4 changed files with 285 additions and 80 deletions

View File

@@ -9,11 +9,10 @@ import compareFlatFacts from './compare-facts/flat';
import FactTemplate from './compare-facts/fact-template'; import FactTemplate from './compare-facts/fact-template';
export function compareFacts(module, facts) { export function compareFacts(module, facts) {
if (module.displayType === 'nested') { // If the module has a template or includes a list of keys to display,
return { factData: compareNestedFacts(facts), // then perform a flat comparison, otherwise assume nested
isNestedDisplay: true //
}; if (module.factTemplate || module.nameKey) {
} else {
// For flat structures we compare left-to-right, then right-to-left to // For flat structures we compare left-to-right, then right-to-left to
// make sure we get a good comparison between both hosts // make sure we get a good comparison between both hosts
var compare = _.partialRight(compareFlatFacts, var compare = _.partialRight(compareFlatFacts,
@@ -33,5 +32,9 @@ export function compareFacts(module, facts) {
}; };
}) })
.value(); .value();
} else {
return { factData: compareNestedFacts(facts),
isNestedDisplay: true
};
} }
} }

View File

@@ -21,7 +21,14 @@ function slotFactValues(basisPosition, basisValue, comparatorValue) {
} }
export default export default
function flatCompare(basisFacts, comparatorFacts, nameKey, compareKeys, factTemplate) { function flatCompare(basisFacts,
comparatorFacts, renderOptions) {
var nameKey = renderOptions.nameKey;
var compareKeys = renderOptions.compareKey;
var keyNameMap = renderOptions.keyNameMap;
var valueFormatter = renderOptions.valueFormatter;
var factTemplate = renderOptions.factTemplate;
return basisFacts.facts.reduce(function(arr, basisFact) { return basisFacts.facts.reduce(function(arr, basisFact) {
@@ -33,7 +40,44 @@ export default
var matchingFact = _.where(comparatorFacts.facts, searcher); var matchingFact = _.where(comparatorFacts.facts, searcher);
var diffs; var diffs;
if (!_.isUndefined(factTemplate)) { // Perform comparison and get back comparisonResults; like:
// { 'value':
// { leftValue: 'blah',
// rightValue: 'doo'
// }
// };
//
var comparisonResults =
_.reduce(compareKeys, function(result, compareKey) {
if (_.isEmpty(matchingFact)) {
comparatorValue = 'absent';
} else {
comparatorValue = matchingFact[0][compareKey];
}
var slottedValues = slotFactValues(basisFacts.position,
basisFact[compareKey],
comparatorValue);
if (_.isUndefined(slottedValues.left) && _.isUndefined(slottedValues.right)) {
return result;
}
if (slottedValues.left !== slottedValues.right) {
slottedValues.isDivergent = true;
} else {
slottedValues.isDivergent = false;
}
result[compareKey] = slottedValues;
return result;
}, {});
var hasDiffs = _.any(comparisonResults, { isDivergent: true });
if (hasDiffs && factTemplate.hasTemplate()) {
basisValue = factTemplate.render(basisFact); basisValue = factTemplate.render(basisFact);
@@ -43,45 +87,34 @@ export default
comparatorValue = factTemplate.render(matchingFact[0]); comparatorValue = factTemplate.render(matchingFact[0]);
} }
slottedValues = slotFactValues(basisFacts.position, basisValue, comparatorValue); if (!_.isEmpty(comparisonResults)) {
diffs = slottedValues = slotFactValues(basisFact.position, basisValue, comparatorValue);
{ keyName: basisFact[nameKey],
value1: slottedValues.left,
value2: slottedValues.right
};
} else { diffs =
{ keyName: basisFact[nameKey],
if (_.isEmpty(matchingFact)) { value1: slottedValues.left,
matchingFact = {}; value2: slottedValues.right
} else { };
matchingFact = matchingFact[0];
} }
} else if (hasDiffs) {
diffs = diffs =
_(basisFact).map(function(value, key) { _(comparisonResults).map(function(slottedValues, key) {
var slottedValues = slotFactValues(basisFacts.position, value, matchingFact[key] || 'absent');
var keyName;
if (slottedValues.right !== 'absent') { var keyName = key;
if(slottedValues.left === slottedValues.right) {
return;
}
if (!_.include(compareKeys, key)) { if (keyNameMap && keyNameMap[key]) {
return; keyName = keyNameMap[key];
}
keyName = basisFact[nameKey];
} else {
keyName = key;
} }
return { keyName: keyName, return { keyName: keyName,
value1: slottedValues.left, value1: slottedValues.left,
value1IsAbsent: slottedValues.left === 'absent', value1IsAbsent: slottedValues.left === 'absent',
value2: slottedValues.right, value2: slottedValues.right,
value2IsAbsent: slottedValues.right === 'absent' value2IsAbsent: slottedValues.right === 'absent',
isDivergent: slottedValues.isDivergent
}; };
}).compact() }).compact()
.value(); .value();

View File

@@ -2,29 +2,26 @@ var moduleConfig =
{ 'packages': { 'packages':
{ compareKey: ['release', 'version'], { compareKey: ['release', 'version'],
nameKey: 'name', nameKey: 'name',
displayType: 'flat',
sortKey: 1, sortKey: 1,
factTemplate: "{{epoch|append:':'}}{{version}}-{{release}}{{arch|prepend:'.'}}" factTemplate: "{{epoch|append:':'}}{{version}}-{{release}}{{arch|prepend:'.'}}"
}, },
'services': 'services':
{ compareKey: ['state', 'source'], { compareKey: ['state', 'source'],
nameKey: 'name', nameKey: 'name',
displayType: 'flat',
factTemplate: '{{state}} ({{source}})', factTemplate: '{{state}} ({{source}})',
sortKey: 2 sortKey: 2
}, },
'files': 'files':
{ compareKey: ['size', 'mode', 'md5', 'mtime', 'gid', 'uid'], { compareKey: ['size', 'mode', 'md5', 'mtime', 'gid', 'uid'],
nameKey: 'path', nameKey: 'path',
displayType: 'flat', displayKeys: ['size', 'mode', 'mtime', 'uid', 'gid', 'md5'],
sortKey: 3 sortKey: 3
}, },
'ansible': 'ansible':
{ displayType: 'nested', { sortKey: 4
sortKey: 4
}, },
'custom': 'custom':
{ displayType: 'nested' {
} }
}; };

View File

@@ -1,17 +1,34 @@
import compareFacts from 'tower/system-tracking/compare-facts/flat';
/* jshint node: true */ /* jshint node: true */
/* globals -expect, -_ */ /* globals -expect, -_ */
import compareFacts from 'tower/system-tracking/compare-facts/flat'; var chai = require('chai');
var expect = require('chai').expect;
var _ = require('lodash'); var _ = require('lodash');
var chaiThings = require('chai-things');
chai.use(chaiThings);
global.expect = chai.expect;
global._ = _; global._ = _;
describe('CompareFacts.Flat', function() { describe('CompareFacts.Flat', function() {
function options(overrides) {
return _.merge({}, defaultOptions, overrides);
}
var defaultTemplate =
{ hasTemplate: function() { return false; }
};
var defaultOptions =
{ factTemplate: defaultTemplate,
nameKey: 'name'
};
it('returns empty array with empty basis facts', function() { it('returns empty array with empty basis facts', function() {
var result = compareFacts({ facts: [] }, { facts: [] }); var result = compareFacts({ facts: [] }, { facts: [] }, defaultOptions);
expect(result).to.deep.equal([]); expect(result).to.deep.equal([]);
}); });
@@ -27,39 +44,177 @@ describe('CompareFacts.Flat', function() {
[{ 'name': 'foo', [{ 'name': 'foo',
'value': 'bar' 'value': 'bar'
}] }]
}, 'name', ['value']); }, options({ nameKey: 'name',
compareKey: ['value'],
}));
expect(result).to.deep.equal([]);
});
it('returns empty array with multiple compare keys and no differences', function() {
var result = compareFacts(
{ facts:
[{ 'name': 'foo',
'value': 'bar'
}]
},
{ facts:
[{ 'name': 'foo',
'value': 'bar'
}]
}, options({ compareKey: ['name', 'value']
}));
expect(result).to.deep.equal([]); expect(result).to.deep.equal([]);
}); });
context('when both collections contain facts', function() { context('when both collections contain facts', function() {
it('includes each fact value when a compareKey differs', function() { it('includes each compare key value when a compareKey differs', function() {
var result = compareFacts( var result = compareFacts(
{ position: 'left', { position: 'left',
facts: facts:
[{ 'name': 'foo', [{ 'name': 'foo',
'value': 'bar' 'value': 'bar',
'extra': 'doo'
}] }]
}, },
{ position: 'right', { position: 'right',
facts: facts:
[{ 'name': 'foo', [{ 'name': 'foo',
'value': 'baz' 'value': 'baz',
'extra': 'doo'
}] }]
}, 'name', ['value']); }, options({ compareKey: ['value', 'extra'] }));
expect(result).to.deep.equal( expect(result).to.deep.equal(
[{ displayKeyPath: 'foo', [{ displayKeyPath: 'foo',
nestingLevel: 0, nestingLevel: 0,
facts: facts:
[{ keyName: 'foo', [{ keyName: 'value',
value1: 'bar', value1: 'bar',
value1IsAbsent: false, value1IsAbsent: false,
value2: 'baz', value2: 'baz',
value2IsAbsent: false value2IsAbsent: false,
isDivergent: true
},
{ keyName: 'extra',
value1: 'doo',
value1IsAbsent: false,
value2: 'doo',
value2IsAbsent: false,
isDivergent: false
}] }]
}]); }]);
}); });
it('ignores compare keys with no values in fact', function() {
var result = compareFacts(
{ position: 'left',
facts:
[{ 'name': 'foo',
'value': 'bar',
'extra': 'doo'
}]
},
{ position: 'right',
facts:
[{ 'name': 'foo',
'value': 'baz',
'extra': 'doo'
}]
}, options({ compareKey: ['value', 'extra', 'blah'] }));
expect(result).to.deep.equal(
[{ displayKeyPath: 'foo',
nestingLevel: 0,
facts:
[{ keyName: 'value',
value1: 'bar',
value1IsAbsent: false,
value2: 'baz',
value2IsAbsent: false,
isDivergent: true
},
{ keyName: 'extra',
value1: 'doo',
value1IsAbsent: false,
value2: 'doo',
value2IsAbsent: false,
isDivergent: false
}]
}]);
});
it('allows mapping key names with keyNameMap parameter', function() {
var keyNameMap =
{ 'extra': 'blah'
};
var result = compareFacts(
{ position: 'left',
facts:
[{ 'name': 'foo',
'value': 'bar',
'extra': 'doo'
}]
},
{ position: 'right',
facts:
[{ 'name': 'foo',
'value': 'baz',
'extra': 'doo'
}]
}, options({ compareKey: ['value', 'extra', 'blah'],
keyNameMap: keyNameMap
}));
expect(result[0].facts).to.include.something.that.deep.equals(
{ keyName: 'blah',
value1: 'doo',
value1IsAbsent: false,
value2: 'doo',
value2IsAbsent: false,
isDivergent: false
});
});
// it('allows formatting values with valueFormat parameter', function() {
// var valueFormat =
// function(key, values) {
// if (key === 'extra') {
// return 'formatted';
// }
// }
// var result = compareFacts(
// { position: 'left',
// facts:
// [{ 'name': 'foo',
// 'value': 'bar',
// 'extra': 'doo'
// }]
// },
// { position: 'right',
// facts:
// [{ 'name': 'foo',
// 'value': 'baz',
// 'extra': 'doo'
// }]
// }, 'name', ['value', 'extra', 'blah'], keyNameMap, defaultTemplate, );
// expect(result[0].facts).to.include.something.that.deep.equals(
// { keyName: 'extra',
// value1: 'formatted',
// value1IsAbsent: false,
// value2: 'formatted',
// value2IsAbsent: false,
// isDivergent: false
// });
// });
}); });
context('when value for nameKey is present in one collection but not the other', function() { context('when value for nameKey is present in one collection but not the other', function() {
@@ -77,46 +232,55 @@ describe('CompareFacts.Flat', function() {
it('uses "absent" for the missing value', function() { it('uses "absent" for the missing value', function() {
var facts = factData([{ 'name': 'foo'
}]);
var result = compareFacts(facts[0], facts[1], 'name', ['value']);
expect(result).to.deep.equal(
[{ displayKeyPath: 'foo',
nestingLevel: 0,
facts:
[{ keyName: 'name',
value1: 'foo',
value1IsAbsent: false,
value2: 'absent',
value2IsAbsent: true
}]
}]);
});
it('includes all keys from basisFacts', function() {
var facts = factData([{ 'name': 'foo', var facts = factData([{ 'name': 'foo',
'value': 'bar' 'value': 'bar'
}]); }]);
var result = compareFacts(facts[0], facts[1], 'name', ['value']); var result = compareFacts(facts[0], facts[1],
options({ compareKey: ['value']
}));
expect(result).to.deep.equal( expect(result).to.deep.equal(
[{ displayKeyPath: 'foo', [{ displayKeyPath: 'foo',
nestingLevel: 0, nestingLevel: 0,
facts: facts:
[{ keyName: 'name', [{ keyName: 'value',
value1: 'foo',
value1IsAbsent: false,
value2: 'absent',
value2IsAbsent: true
},
{ keyName: 'value',
value1: 'bar', value1: 'bar',
value1IsAbsent: false, value1IsAbsent: false,
value2: 'absent', value2: 'absent',
value2IsAbsent: true value2IsAbsent: true,
isDivergent: true
}]
}]);
});
it('includes given compare keys from basisFacts', function() {
var facts = factData([{ 'name': 'foo',
'value': 'bar',
'extra': 'doo'
}]);
var result = compareFacts(facts[0], facts[1],
options({ compareKey: ['value', 'extra']
}));
expect(result).to.deep.equal(
[{ displayKeyPath: 'foo',
nestingLevel: 0,
facts:
[{ keyName: 'value',
value1: 'bar',
value1IsAbsent: false,
value2: 'absent',
value2IsAbsent: true,
isDivergent: true
},
{ keyName: 'extra',
value1: 'doo',
value1IsAbsent: false,
value2: 'absent',
value2IsAbsent: true,
isDivergent: true
}] }]
}]); }]);
@@ -132,10 +296,14 @@ describe('CompareFacts.Flat', function() {
{ render: function() { { render: function() {
renderCallCount++; renderCallCount++;
}, },
hasTemplate: function() { return true; },
template: "" template: ""
}; };
compareFacts(facts[0], facts[1], 'name', ['value'], factTemplate); compareFacts(facts[0], facts[1],
options({ compareKey: ['value'],
factTemplate: factTemplate
}));
expect(renderCallCount).to.equal(1); expect(renderCallCount).to.equal(1);
@@ -168,10 +336,14 @@ describe('CompareFacts.Flat', function() {
{ render: function(fact) { { render: function(fact) {
renderCalledWith.push(fact); renderCalledWith.push(fact);
}, },
hasTemplate: function() { return true; },
template: "" template: ""
}; };
compareFacts(factData[0], factData[1], 'name', ['value'], factTemplate); compareFacts(factData[0], factData[1],
options({ compareKey: ['value'],
factTemplate: factTemplate
}));
expect(renderCalledWith).to.include(factData[0].facts[0]); expect(renderCalledWith).to.include(factData[0].facts[0]);
expect(renderCalledWith).to.include(factData[1].facts[0]); expect(renderCalledWith).to.include(factData[1].facts[0]);