From 5a2940a5e6a663285e85b5357b854ec861d8d8c5 Mon Sep 17 00:00:00 2001 From: Ruben Vargas Palma Date: Wed, 4 Nov 2020 15:21:51 -0600 Subject: [PATCH] Prevent DAG crashes because of empty service name string (#656) * Prevent DAG crashes because of empty service name string Signed-off-by: Ruben Vargas * Adding tests for empty service names Signed-off-by: Ruben Vargas Signed-off-by: vvvprabhakar --- .../src/components/DependencyGraph/DAG.js | 31 +++++++---- .../components/DependencyGraph/DAG.test.js | 53 +++++++++++++++++-- 2 files changed, 69 insertions(+), 15 deletions(-) diff --git a/packages/jaeger-ui/src/components/DependencyGraph/DAG.js b/packages/jaeger-ui/src/components/DependencyGraph/DAG.js index 37862cb5c4..b5b0296e65 100644 --- a/packages/jaeger-ui/src/components/DependencyGraph/DAG.js +++ b/packages/jaeger-ui/src/components/DependencyGraph/DAG.js @@ -35,26 +35,34 @@ export default class DAG extends React.Component { serviceCalls: [], }; + constructor(props) { + super(props); + this.cytoscapeRef = React.createRef(); + } + componentDidMount() { const { serviceCalls } = this.props; const nodeMap = {}; const nodes = []; const edges = []; serviceCalls.forEach(d => { - if (!nodeMap[d.parent]) { - nodes.push({ data: { id: d.parent } }); - nodeMap[d.parent] = true; + if (d.parent.trim().length !== 0 && d.child.trim().length !== 0) { + if (!nodeMap[d.parent]) { + nodes.push({ data: { id: d.parent } }); + nodeMap[d.parent] = true; + } + if (!nodeMap[d.child]) { + nodes.push({ data: { id: d.child } }); + nodeMap[d.child] = true; + } + edges.push({ + data: { source: d.parent, target: d.child, label: `${d.callCount}` }, + }); } - if (!nodeMap[d.child]) { - nodes.push({ data: { id: d.child } }); - nodeMap[d.child] = true; - } - edges.push({ - data: { source: d.parent, target: d.child, label: `${d.callCount}` }, - }); }); + cytoscape({ - container: document.getElementById('cy'), + container: this.cytoscapeRef.current, boxSelectionEnabled: false, autounselectify: true, layout: { @@ -102,6 +110,7 @@ export default class DAG extends React.Component { left: 0, top: 0, }} + ref={this.cytoscapeRef} /> ); } diff --git a/packages/jaeger-ui/src/components/DependencyGraph/DAG.test.js b/packages/jaeger-ui/src/components/DependencyGraph/DAG.test.js index 60eb6c4aa2..7839acf364 100644 --- a/packages/jaeger-ui/src/components/DependencyGraph/DAG.test.js +++ b/packages/jaeger-ui/src/components/DependencyGraph/DAG.test.js @@ -12,14 +12,48 @@ // See the License for the specific language governing permissions and // limitations under the License. -/* eslint-disable import/first */ -jest.mock('cytoscape'); - import React from 'react'; import { mount } from 'enzyme'; - import DAG from './DAG'; +// mock canvas API (we don't care about canvas results) + +window.HTMLCanvasElement.prototype.getContext = function() { + return { + fillRect() {}, + clearRect() {}, + getImageData(x, y, w, h) { + return { + data: new Array(w * h * 4), + }; + }, + putImageData() {}, + createImageData() { + return []; + }, + setTransform() {}, + drawImage() {}, + save() {}, + fillText() {}, + restore() {}, + beginPath() {}, + moveTo() {}, + lineTo() {}, + closePath() {}, + stroke() {}, + translate() {}, + scale() {}, + rotate() {}, + arc() {}, + fill() {}, + measureText() { + return { width: 0 }; + }, + transform() {}, + rect() {}, + clip() {}, + }; +}; describe('', () => { it('does not explode', () => { const serviceCalls = [ @@ -31,4 +65,15 @@ describe('', () => { ]; expect(mount()).toBeDefined(); }); + + it('does not explode with empty strings or string with only spaces', () => { + const serviceCalls = [ + { + callCount: 1, + child: '', + parent: ' ', + }, + ]; + expect(mount()).toBeDefined(); + }); });