[Logstash] [PipelineViewer] Preserve all nested pipeline statements during graph conversion (#19101)

* Ensure all true/false statements are nested in IfStatements.

* Simplify nested vertex diffing.

* Rename get vertices function and test it.

* Update tests, add more tests.

* Update prompted by review feedback.

* Update tests - add required props to provided objects.

* Remove unneeded function/tests.

* PR Cleanup.
This commit is contained in:
Justin Kambic 2018-05-18 09:32:52 -04:00 committed by GitHub
parent 72f0f5918b
commit 8425016e66
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 221 additions and 13 deletions

View file

@ -40,18 +40,34 @@ export class IfVertex extends Vertex {
return this.outgoingEdges.find(e => e.when === true);
}
get trueEdges() {
return this.outgoingEdges.filter(e => e.when === true);
}
get falseEdge() {
return this.outgoingEdges.find(e => e.when === false);
}
get falseEdges() {
return this.outgoingEdges.filter(e => e.when === false);
}
get trueOutgoingVertex() {
return this.trueEdge ? this.trueEdge.to : null;
}
get trueOutgoingVertices() {
return this.trueEdges.map(e => e.to);
}
get falseOutgoingVertex() {
return this.falseEdge ? this.falseEdge.to : null;
}
get falseOutgoingVertices() {
return this.falseEdges.map(e => e.to);
}
get next() {
const trueDescendants = this.trueOutgoingVertex ? this.trueOutgoingVertex.descendants().vertices : [];
const falseDescendants = this.falseOutgoingVertex ? this.falseOutgoingVertex.descendants().vertices : [];

View file

@ -49,6 +49,8 @@ describe('IfStatement class', () => {
esVertex.pipelineStage = 'output';
ifVertex.trueOutgoingVertex = esVertex;
ifVertex.trueOutgoingVertices = [ esVertex ];
ifVertex.falseOutgoingVertices = [];
});
it('creates a IfStatement from vertex props', () => {
@ -88,6 +90,9 @@ describe('IfStatement class', () => {
ifVertex.trueOutgoingVertex = esVertex;
ifVertex.falseOutgoingVertex = terminalVertex;
ifVertex.trueOutgoingVertices = [ esVertex ];
ifVertex.falseOutgoingVertices = [ terminalVertex ];
});
it('creates a IfStatement from vertex props', () => {
@ -126,6 +131,8 @@ describe('IfStatement class', () => {
esVertex.pipelineStage = 'output';
ifVertex.trueOutgoingVertex = esVertex;
ifVertex.trueOutgoingVertices = [ esVertex ];
ifVertex.falseOutgoingVertices = [];
});
it('creates a IfStatement from vertex props', () => {
@ -171,6 +178,9 @@ describe('IfStatement class', () => {
ifVertex.trueOutgoingVertex = esVertex;
ifVertex.falseOutgoingVertex = terminalVertex;
ifVertex.trueOutgoingVertices = [ esVertex ];
ifVertex.falseOutgoingVertices = [ terminalVertex ];
});
it('creates a IfStatement from vertex props', () => {

View file

@ -1579,6 +1579,185 @@ describe('Pipeline class', () => {
});
});
describe('Pipeline with if having two nested output statements', () => {
beforeEach(() => {
graph = new Graph();
graph.update({
vertices: [
{
id: "the_if",
explicit_id: false,
type: "if",
condition: "[is_rt] == \"RT\"",
stats: {}
},
{
plugin_type: "output",
type: "plugin",
config_name: "stdout",
id: "plugin_1",
meta: {
source: {
line: 124,
protocol: "str",
id: "pipeline",
column: 5
}
},
explicit_id: false,
stats: null
},
{
plugin_type: "output",
type: "plugin",
config_name: "elasticsearch",
id: "plugin_2",
meta: {
source: {
line: 117,
protocol: "str",
id: "pipeline",
column: 5
}
},
explicit_id: true,
stats: null
},
],
edges: [
{
id: "35591f523dee3465d4c38f20232c56db453a9e4258af5885bf8c79f517690bc5",
from: "the_if",
to: "plugin_1",
type: "boolean",
when: true
},
{
id: "591f523dee3465d4c38f20232c56db453a9e4258af5885bf8c79f517690bc535",
from: "the_if",
to: "plugin_2",
type: "boolean",
when: true
}
]
});
});
it('has two child statements', () => {
const pipeline = Pipeline.fromPipelineGraph(graph);
expect(pipeline.outputStatements.length).to.be(1);
const { trueStatements } = pipeline.outputStatements[0];
expect(trueStatements.length).to.be(2);
expect(trueStatements[0].id).to.be('plugin_1');
expect(trueStatements[1].id).to.be('plugin_2');
expect(pipeline.outputStatements[0].elseStatements.length).to.be(0);
});
});
describe('Pipeline with if having two nested else statements', () => {
beforeEach(() => {
graph = new Graph();
graph.update({
vertices: [
{
id: "the_if",
explicit_id: false,
type: "if",
condition: "[is_rt] == \"RT\"",
stats: {}
},
{
plugin_type: "output",
type: "plugin",
config_name: "stdout",
id: "plugin_1",
meta: {
source: {
line: 124,
protocol: "str",
id: "pipeline",
column: 5
}
},
explicit_id: false,
stats: null
},
{
plugin_type: "output",
type: "plugin",
config_name: "elasticsearch",
id: "plugin_2",
meta: {
source: {
line: 117,
protocol: "str",
id: "pipeline",
column: 5
}
},
explicit_id: true,
stats: null
},
{
plugin_type: "output",
type: "plugin",
config_name: "stdout",
id: "plugin_3",
meta: {
source: {
line: 120,
protocol: "str",
id: "pipeline",
column: 5
}
},
explicit_id: false,
stats: null
},
],
edges: [
{
id: "35591f523dee3465d4c38f20232c56db453a9e4258af5885bf8c79f517690bc5",
from: "the_if",
to: "plugin_1",
type: "boolean",
when: false
},
{
id: "591f523dee3465d4c38f20232c56db453a9e4258af5885bf8c79f517690bc535",
from: "the_if",
to: "plugin_2",
type: "boolean",
when: false
},
{
id: "637281923dee3465d4c38f20232c56db453a9e4258af5885bf8c79f517690bc5",
from: "the_if",
to: "plugin_3",
type: "boolean",
when: true
}
]
});
});
it('has two child else statements', () => {
const pipeline = Pipeline.fromPipelineGraph(graph);
expect(pipeline.outputStatements.length).to.be(1);
const {
trueStatements,
elseStatements
} = pipeline.outputStatements[0];
expect(trueStatements.length).to.be(1);
expect(trueStatements[0].id).to.be('plugin_3');
expect(elseStatements.length).to.be(2);
expect(elseStatements[0].id).to.be('plugin_1');
expect(elseStatements[1].id).to.be('plugin_2');
});
});
describe('Pipeline with nested ifs', () => {
beforeEach(() => {
graph = new Graph();

View file

@ -8,6 +8,16 @@ import { Statement } from './statement';
import { makeStatement } from './make_statement';
import { isVertexPipelineStage } from './utils';
function makeStatementsForOutgoingVertices(outgoingVertices, statements, next, pipelineStage) {
outgoingVertices.forEach(vertex => {
let currentVertex = vertex;
while(isVertexPipelineStage(currentVertex, pipelineStage) && (currentVertex !== next)) {
statements.push(makeStatement(currentVertex, pipelineStage));
currentVertex = currentVertex.next;
}
});
}
export class IfStatement extends Statement {
constructor(vertex, trueStatements, elseStatements) {
super(vertex);
@ -22,22 +32,15 @@ export class IfStatement extends Statement {
static fromPipelineGraphVertex(ifVertex, pipelineStage) {
const trueStatements = [];
const elseStatements = [];
const {
trueOutgoingVertices,
falseOutgoingVertices
} = ifVertex;
const trueVertex = ifVertex.trueOutgoingVertex;
const falseVertex = ifVertex.falseOutgoingVertex;
const next = ifVertex.next;
let currentVertex = trueVertex;
while (isVertexPipelineStage(currentVertex, pipelineStage) && (currentVertex !== next)) {
trueStatements.push(makeStatement(currentVertex, pipelineStage));
currentVertex = currentVertex.next;
}
currentVertex = falseVertex;
while (currentVertex && isVertexPipelineStage(currentVertex, pipelineStage) && (currentVertex !== next)) {
elseStatements.push(makeStatement(currentVertex, pipelineStage));
currentVertex = currentVertex.next;
}
makeStatementsForOutgoingVertices(trueOutgoingVertices, trueStatements, next, pipelineStage);
makeStatementsForOutgoingVertices(falseOutgoingVertices, elseStatements, next, pipelineStage);
return new IfStatement(
ifVertex,