mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-03 10:11:03 +00:00
Test and debugbar tools to simulate single nodes appearing
This commit is contained in:
@@ -35,6 +35,21 @@ describe('NodesLayout', () => {
|
||||
'n2-n4': {id: 'n2-n4', source: 'n2', target: 'n4'}
|
||||
})
|
||||
},
|
||||
addNode15: {
|
||||
nodes: fromJS({
|
||||
n1: {id: 'n1'},
|
||||
n2: {id: 'n2'},
|
||||
n3: {id: 'n3'},
|
||||
n4: {id: 'n4'},
|
||||
n5: {id: 'n5'}
|
||||
}),
|
||||
edges: fromJS({
|
||||
'n1-n3': {id: 'n1-n3', source: 'n1', target: 'n3'},
|
||||
'n1-n4': {id: 'n1-n4', source: 'n1', target: 'n4'},
|
||||
'n1-n5': {id: 'n1-n5', source: 'n1', target: 'n5'},
|
||||
'n2-n4': {id: 'n2-n4', source: 'n2', target: 'n4'}
|
||||
})
|
||||
},
|
||||
removeEdge24: {
|
||||
nodes: fromJS({
|
||||
n1: {id: 'n1'},
|
||||
@@ -86,6 +101,19 @@ describe('NodesLayout', () => {
|
||||
edges: fromJS({
|
||||
'n1-n4': {id: 'n1-n4', source: 'n1', target: 'n4'}
|
||||
})
|
||||
},
|
||||
singlePortrait6: {
|
||||
nodes: fromJS({
|
||||
n1: {id: 'n1'},
|
||||
n2: {id: 'n2'},
|
||||
n3: {id: 'n3'},
|
||||
n4: {id: 'n4'},
|
||||
n5: {id: 'n5'},
|
||||
n6: {id: 'n6'}
|
||||
}),
|
||||
edges: fromJS({
|
||||
'n1-n4': {id: 'n1-n4', source: 'n1', target: 'n4'}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
@@ -282,4 +310,65 @@ describe('NodesLayout', () => {
|
||||
expect(nodes.n1.x).toBeLessThan(nodes.n5.x);
|
||||
expect(nodes.n2.x).toEqual(nodes.n5.x);
|
||||
});
|
||||
|
||||
it('renders an additional single node in single nodes group', () => {
|
||||
let result = NodesLayout.doLayout(
|
||||
nodeSets.singlePortrait.nodes,
|
||||
nodeSets.singlePortrait.edges);
|
||||
|
||||
nodes = result.nodes.toJS();
|
||||
|
||||
// first square row on same level as top-most other node
|
||||
expect(nodes.n1.y).toEqual(nodes.n2.y);
|
||||
expect(nodes.n1.y).toEqual(nodes.n3.y);
|
||||
expect(nodes.n4.y).toEqual(nodes.n5.y);
|
||||
|
||||
// all singles right to other nodes
|
||||
expect(nodes.n1.x).toEqual(nodes.n4.x);
|
||||
expect(nodes.n1.x).toBeLessThan(nodes.n2.x);
|
||||
expect(nodes.n1.x).toBeLessThan(nodes.n3.x);
|
||||
expect(nodes.n1.x).toBeLessThan(nodes.n5.x);
|
||||
expect(nodes.n2.x).toEqual(nodes.n5.x);
|
||||
|
||||
options.cachedLayout = result;
|
||||
options.nodeCache = options.nodeCache.merge(result.nodes);
|
||||
options.edgeCache = options.edgeCache.merge(result.edge);
|
||||
|
||||
result = NodesLayout.doLayout(
|
||||
nodeSets.singlePortrait6.nodes,
|
||||
nodeSets.singlePortrait6.edges,
|
||||
options
|
||||
);
|
||||
|
||||
nodes = result.nodes.toJS();
|
||||
|
||||
expect(nodes.n1.x).toBeLessThan(nodes.n2.x);
|
||||
expect(nodes.n1.x).toBeLessThan(nodes.n3.x);
|
||||
expect(nodes.n1.x).toBeLessThan(nodes.n5.x);
|
||||
expect(nodes.n1.x).toBeLessThan(nodes.n6.x);
|
||||
});
|
||||
|
||||
it('adds a new node to existing layout in a line', () => {
|
||||
let result = NodesLayout.doLayout(
|
||||
nodeSets.initial4.nodes,
|
||||
nodeSets.initial4.edges);
|
||||
|
||||
nodes = result.nodes.toJS();
|
||||
|
||||
coords = getNodeCoordinates(result.nodes);
|
||||
options.cachedLayout = result;
|
||||
options.nodeCache = options.nodeCache.merge(result.nodes);
|
||||
options.edgeCache = options.edgeCache.merge(result.edge);
|
||||
|
||||
result = NodesLayout.doLayout(
|
||||
nodeSets.addNode15.nodes,
|
||||
nodeSets.addNode15.edges,
|
||||
options
|
||||
);
|
||||
|
||||
nodes = result.nodes.toJS();
|
||||
|
||||
expect(nodes.n1.x).toBeGreaterThan(nodes.n5.x);
|
||||
expect(nodes.n1.y).toEqual(nodes.n5.y);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -274,6 +274,13 @@ export function hasUnseenNodes(nodes, cache) {
|
||||
return hasUnseen;
|
||||
}
|
||||
|
||||
function hasNewSingleNode(nodes, cache) {
|
||||
return (ImmSet
|
||||
.fromKeys(nodes)
|
||||
.subtract(ImmSet.fromKeys(cache))
|
||||
.every(key => nodes.getIn([key, 'degree']) === 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if edge has same endpoints in new nodes as well as in the nodeCache
|
||||
* @param {Map} edge Edge with source and target
|
||||
@@ -364,9 +371,14 @@ export function doLayout(immNodes, immEdges, opts) {
|
||||
} else {
|
||||
const graph = cache.graph;
|
||||
const nodesWithDegrees = updateNodeDegrees(immNodes, immEdges);
|
||||
layout = runLayoutEngine(graph, nodesWithDegrees, immEdges, opts);
|
||||
if (!layout) {
|
||||
return layout;
|
||||
if (hasNewSingleNode(nodesWithDegrees, nodeCache)) {
|
||||
layout = cloneLayout(cachedLayout, immNodes, immEdges);
|
||||
layout = copyLayoutProperties(layout, nodeCache, edgeCache);
|
||||
} else {
|
||||
layout = runLayoutEngine(graph, nodesWithDegrees, immEdges, opts);
|
||||
if (!layout) {
|
||||
return layout;
|
||||
}
|
||||
}
|
||||
layout = layoutSingleNodes(layout, opts);
|
||||
layout = shiftLayoutToCenter(layout, opts);
|
||||
|
||||
@@ -4,7 +4,7 @@ import d3 from 'd3';
|
||||
import _ from 'lodash';
|
||||
import Perf from 'react-addons-perf';
|
||||
import { connect } from 'react-redux';
|
||||
import { fromJS } from 'immutable';
|
||||
import { fromJS, Set as makeSet } from 'immutable';
|
||||
|
||||
import debug from 'debug';
|
||||
const log = debug('scope:debug-panel');
|
||||
@@ -160,6 +160,10 @@ class DebugToolbar extends React.Component {
|
||||
this.onChange = this.onChange.bind(this);
|
||||
this.toggleColors = this.toggleColors.bind(this);
|
||||
this.addNodes = this.addNodes.bind(this);
|
||||
this.intermittendTimer = null;
|
||||
this.intermittendNodes = makeSet();
|
||||
this.shortLivedTimer = null;
|
||||
this.shortLivedNodes = makeSet();
|
||||
this.state = {
|
||||
nodesToAdd: 30,
|
||||
showColors: false
|
||||
@@ -197,6 +201,66 @@ class DebugToolbar extends React.Component {
|
||||
}));
|
||||
}
|
||||
|
||||
setIntermittend() {
|
||||
// simulate epheremal nodes
|
||||
if (this.intermittendTimer) {
|
||||
clearInterval(this.intermittendTimer);
|
||||
this.intermittendTimer = null;
|
||||
} else {
|
||||
this.intermittendTimer = setInterval(() => {
|
||||
// add new node
|
||||
this.addNodes(1);
|
||||
|
||||
// remove random node
|
||||
const ns = this.props.nodes;
|
||||
const nodeNames = ns.keySeq().toJS();
|
||||
const randomNode = _.sample(nodeNames);
|
||||
this.asyncDispatch(receiveNodesDelta({
|
||||
remove: [randomNode]
|
||||
}));
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
setShortLived() {
|
||||
// simulate nodes with same ID popping in and out
|
||||
if (this.shortLivedTimer) {
|
||||
clearInterval(this.shortLivedTimer);
|
||||
this.shortLivedTimer = null;
|
||||
} else {
|
||||
this.shortLivedTimer = setInterval(() => {
|
||||
// filter random node
|
||||
const ns = this.props.nodes;
|
||||
const nodeNames = ns.keySeq().toJS();
|
||||
const randomNode = _.sample(nodeNames);
|
||||
if (randomNode) {
|
||||
let nextNodes = ns.setIn([randomNode, 'filtered'], true);
|
||||
this.shortLivedNodes = this.shortLivedNodes.add(randomNode);
|
||||
// bring nodes back after a bit
|
||||
if (this.shortLivedNodes.size > 5) {
|
||||
const returningNode = this.shortLivedNodes.first();
|
||||
this.shortLivedNodes = this.shortLivedNodes.rest();
|
||||
nextNodes = nextNodes.setIn([returningNode, 'filtered'], false);
|
||||
}
|
||||
this.asyncDispatch(setAppState(state => state.set('nodes', nextNodes)));
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
updateAdjacencies() {
|
||||
const ns = this.props.nodes;
|
||||
const nodeNames = ns.keySeq().toJS();
|
||||
this.asyncDispatch(receiveNodesDelta({
|
||||
add: this._addNodes(7),
|
||||
update: sample(nodeNames).map(n => ({
|
||||
id: n,
|
||||
adjacency: sample(nodeNames),
|
||||
}), nodeNames.length),
|
||||
remove: this._removeNode(),
|
||||
}));
|
||||
}
|
||||
|
||||
_addNodes(n, prefix = 'zing') {
|
||||
const ns = this.props.nodes;
|
||||
const nodeNames = ns.keySeq().toJS();
|
||||
@@ -303,6 +367,12 @@ class DebugToolbar extends React.Component {
|
||||
<button onClick={() => this.setLoading(false)}>Stop</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>Short-lived nodes</label>
|
||||
<button onClick={() => this.setShortLived()}>Toggle short-lived nodes</button>
|
||||
<button onClick={() => this.setIntermittend()}>Toggle intermittend nodes</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>Measure React perf for </label>
|
||||
<button onClick={() => startPerf(2)}>2s</button>
|
||||
|
||||
Reference in New Issue
Block a user