Skip to content

Commit

Permalink
Merge pull request #10 from ProcessMaker/bugfix/FOUR-1991
Browse files Browse the repository at this point in the history
Add EventBasedGateway validations
  • Loading branch information
boliviacoca authored Jun 1, 2021
2 parents df19002 + 461444b commit 487a610
Show file tree
Hide file tree
Showing 6 changed files with 412 additions and 1 deletion.
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module.exports = {
rules: {
'processmaker/custom-validation': 'error',
'processmaker/gateway-direction': 'error',
'processmaker/event-based-gateway': 'error',
'processmaker/call-activity-child-process': 'error',
'processmaker/call-activity-sequence-flow': 'error',
'processmaker/id-required': 'error',
Expand Down
90 changes: 90 additions & 0 deletions rule-tester.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/* global it, describe, beforeEach */

const assert = require('assert');

const Linter = require('bpmnlint/lib/linter');

function createResolver(rule) {
return {
resolveRule: () => Promise.resolve(rule)
};
}

function expectEqual(a, b) {
assert.deepStrictEqual(a, b);
}


function verify(ruleName, rule, testCases) {
const linterConfig = {
rules: { [ruleName]: 2 }
};

describe(`rules/${ruleName}`, function() {

let linter;

beforeEach(function() {
linter = new Linter({
resolver: createResolver(rule)
});
});


describe('should lint valid', function() {

testCases.valid.forEach(({ moddleElement }, idx) => (

it(`test case #${idx + 1}`, function() {
return (
Promise.resolve(moddleElement)
.then(moddleRoot => {
return linter.lint(moddleRoot.root, linterConfig);
})
.then(lintResults => {
expectEqual(lintResults, {});
})
);
})

));

});


describe('should lint invalid', function() {

testCases.invalid.forEach(({ moddleElement, report }, idx) => (

it(`test case #${idx}`, function() {

const expectedResult = report instanceof Array ? report : [{
...report,
category: 'error'
}];

return (
Promise.resolve(moddleElement)
.then(moddleRoot => {
return linter.lint(moddleRoot.root, linterConfig);
})
.then(lintResults => {
expectEqual(lintResults, {
[ruleName]: expectedResult
});
})
);
})

));

});

});

}


module.exports = {
verify
};
44 changes: 44 additions & 0 deletions rules/event-based-gateway.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const { isAny } = require('bpmnlint-utils');

/**
* Rule that validates gateways according to the following rules:
*
* - An Event Based Gateway can only be connected to events.
*/
module.exports = function() {
let gateway = null;

function outgoingFlowsAreValid(gateway) {
const outgoing = gateway.get('outgoing');
return outgoing.filter(sequenceFlow => {
const target = sequenceFlow.get('targetRef');
return !isAny(target, ['bpmn:IntermediateCatchEvent', 'bpmn:EndEvent']);
}).length === 0;
}

function check(gateway, reporter) {
if (!isAny(gateway, ['bpmn:EventBasedGateway'])) {
return;
}

const outgoing = gateway.get('outgoing');
const valid = outgoing.filter(sequenceFlow => {
const target = sequenceFlow.get('targetRef');
const isValidType = isAny(target, ['bpmn:IntermediateCatchEvent', 'bpmn:EndEvent']);
const onlyOneIncoming = target.get('incoming').length === 1;
if (!isValidType) {
reporter.report(target.id, 'Event Gateways target elements must be Catch Events');
}
if (!onlyOneIncoming) {
reporter.report(target.id, 'Event Gateway target elements must not have additional incoming Sequence Flows');
}
return !isValidType || !onlyOneIncoming;
}).length === 0;

if (!valid) {
reporter.report(gateway.id, 'Event Gateways target elements must be valid Catch Events');
}
}

return { check };
};
133 changes: 133 additions & 0 deletions test-diagrams/event-based-gateway.invalid.bpmn
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:pm="http://processmaker.com/BPMN/2.0/Schema.xsd" xmlns:tns="http://sourceforge.net/bpmn/definitions/_1530553328908" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://bpmn.io/schema/bpmn" exporter="ProcessMaker Modeler" exporterVersion="1.0" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL http://bpmn.sourceforge.net/schemas/BPMN20.xsd">
<bpmn:process id="ProcessId" name="ProcessName" isExecutable="true">
<bpmn:startEvent id="node_1" name="Start Event" pm:allowInterstitial="false" pm:config="{&#34;web_entry&#34;:null}">
<bpmn:outgoing>node_5</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:eventBasedGateway id="node_3" name="Event Based Gateway">
<bpmn:incoming>node_5</bpmn:incoming>
<bpmn:outgoing>node_9</bpmn:outgoing>
<bpmn:outgoing>node_11</bpmn:outgoing>
<bpmn:outgoing>node_26</bpmn:outgoing>
</bpmn:eventBasedGateway>
<bpmn:sequenceFlow id="node_5" name="" sourceRef="node_1" targetRef="node_3" />
<bpmn:intermediateCatchEvent id="node_6" name="Intermediate Timer Event">
<bpmn:incoming>node_9</bpmn:incoming>
<bpmn:incoming>node_10</bpmn:incoming>
<bpmn:outgoing>node_18</bpmn:outgoing>
<bpmn:timerEventDefinition>
<bpmn:timeDuration>PT1H</bpmn:timeDuration>
</bpmn:timerEventDefinition>
</bpmn:intermediateCatchEvent>
<bpmn:sequenceFlow id="node_9" name="" sourceRef="node_3" targetRef="node_6" />
<bpmn:endEvent id="node_19" name="Message End Event">
<bpmn:incoming>node_18</bpmn:incoming>
<bpmn:messageEventDefinition messageRef="node_19_message" />
</bpmn:endEvent>
<bpmn:sequenceFlow id="node_18" name="" sourceRef="node_6" targetRef="node_19" />
<bpmn:endEvent id="node_24" name="Signal End Event">
<bpmn:incoming>node_23</bpmn:incoming>
<bpmn:signalEventDefinition signalRef="sync_assignment" />
</bpmn:endEvent>
<bpmn:endEvent id="node_28" name="End Event" pm:screenRef="">
<bpmn:incoming>node_30</bpmn:incoming>
</bpmn:endEvent>
<bpmn:intermediateThrowEvent id="node_2" name="Intermediate Message Throw Event">
<bpmn:incoming>node_11</bpmn:incoming>
<bpmn:outgoing>node_23</bpmn:outgoing>
<bpmn:messageEventDefinition messageRef="node_2_message" />
</bpmn:intermediateThrowEvent>
<bpmn:sequenceFlow id="node_11" name="" sourceRef="node_3" targetRef="node_2" />
<bpmn:sequenceFlow id="node_23" name="" sourceRef="node_2" targetRef="node_24" />
<bpmn:intermediateThrowEvent id="node_4" name="Intermediate Message Throw Event">
<bpmn:incoming>node_26</bpmn:incoming>
<bpmn:outgoing>node_30</bpmn:outgoing>
<bpmn:messageEventDefinition messageRef="node_4_message" />
</bpmn:intermediateThrowEvent>
<bpmn:sequenceFlow id="node_26" name="" sourceRef="node_3" targetRef="node_4" />
<bpmn:sequenceFlow id="node_30" name="" sourceRef="node_4" targetRef="node_28" />
<bpmn:task id="node_7" name="Form Task" pm:screenRef="" pm:allowInterstitial="false" pm:assignment="requester" pm:assignmentLock="false" pm:allowReassignment="false" pm:config="{&#34;web_entry&#34;:null,&#34;email_notifications&#34;:{&#34;notifications&#34;:[]}}">
<bpmn:incoming>node_14</bpmn:incoming>
<bpmn:outgoing>node_10</bpmn:outgoing>
</bpmn:task>
<bpmn:sequenceFlow id="node_10" sourceRef="node_7" targetRef="node_6" />
<bpmn:startEvent id="node_12" name="Start Event" pm:allowInterstitial="false" pm:config="{&#34;web_entry&#34;:null}">
<bpmn:outgoing>node_14</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="node_14" sourceRef="node_12" targetRef="node_7" />
</bpmn:process>
<bpmn:message id="node_19_message" name="node_19_message" />
<bpmn:signal id="sync_assignment" name="sync_assignment" />
<bpmn:message id="node_2_message" name="node_2_message" />
<bpmn:message id="node_4_message" name="node_4_message" />
<bpmndi:BPMNDiagram id="BPMNDiagramId">
<bpmndi:BPMNPlane id="BPMNPlaneId" bpmnElement="ProcessId">
<bpmndi:BPMNShape id="node_1_di" bpmnElement="node_1">
<dc:Bounds x="270" y="280" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="node_3_di" bpmnElement="node_3">
<dc:Bounds x="400" y="280" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="node_5_di" bpmnElement="node_5">
<di:waypoint x="288" y="298" />
<di:waypoint x="418" y="298" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="node_6_di" bpmnElement="node_6">
<dc:Bounds x="590" y="280" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="node_9_di" bpmnElement="node_9">
<di:waypoint x="418" y="298" />
<di:waypoint x="608" y="298" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="node_19_di" bpmnElement="node_19">
<dc:Bounds x="840" y="280" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="node_18_di" bpmnElement="node_18">
<di:waypoint x="608" y="298" />
<di:waypoint x="858" y="298" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="node_24_di" bpmnElement="node_24">
<dc:Bounds x="400" y="560" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="node_28_di" bpmnElement="node_28">
<dc:Bounds x="610" y="140" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="node_2_di" bpmnElement="node_2">
<dc:Bounds x="400" y="440" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="node_11_di" bpmnElement="node_11">
<di:waypoint x="418" y="298" />
<di:waypoint x="418" y="458" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="node_23_di" bpmnElement="node_23">
<di:waypoint x="418" y="458" />
<di:waypoint x="418" y="578" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="node_4_di" bpmnElement="node_4">
<dc:Bounds x="400" y="140" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="node_26_di" bpmnElement="node_26">
<di:waypoint x="418" y="298" />
<di:waypoint x="418" y="158" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="node_30_di" bpmnElement="node_30">
<di:waypoint x="418" y="158" />
<di:waypoint x="628" y="158" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="node_7_di" bpmnElement="node_7">
<dc:Bounds x="550" y="530" width="116" height="76" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="node_10_di" bpmnElement="node_10">
<di:waypoint x="608" y="568" />
<di:waypoint x="608" y="298" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="node_12_di" bpmnElement="node_12">
<dc:Bounds x="590" y="690" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="node_14_di" bpmnElement="node_14">
<di:waypoint x="608" y="708" />
<di:waypoint x="608" y="568" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
107 changes: 107 additions & 0 deletions test-diagrams/event-based-gateway.valid.bpmn
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:pm="http://processmaker.com/BPMN/2.0/Schema.xsd" xmlns:tns="http://sourceforge.net/bpmn/definitions/_1530553328908" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://bpmn.io/schema/bpmn" exporter="ProcessMaker Modeler" exporterVersion="1.0" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL http://bpmn.sourceforge.net/schemas/BPMN20.xsd">
<bpmn:process id="ProcessId" name="ProcessName" isExecutable="true">
<bpmn:startEvent id="node_1" name="Start Event" pm:allowInterstitial="false" pm:config="{&#34;web_entry&#34;:null}">
<bpmn:outgoing>node_5</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:eventBasedGateway id="node_3" name="Event Based Gateway">
<bpmn:incoming>node_5</bpmn:incoming>
<bpmn:outgoing>node_9</bpmn:outgoing>
<bpmn:outgoing>node_11</bpmn:outgoing>
<bpmn:outgoing>node_26</bpmn:outgoing>
</bpmn:eventBasedGateway>
<bpmn:sequenceFlow id="node_5" name="" sourceRef="node_1" targetRef="node_3" />
<bpmn:intermediateCatchEvent id="node_6" name="Intermediate Timer Event">
<bpmn:incoming>node_9</bpmn:incoming>
<bpmn:outgoing>node_18</bpmn:outgoing>
<bpmn:timerEventDefinition>
<bpmn:timeDuration>PT1H</bpmn:timeDuration>
</bpmn:timerEventDefinition>
</bpmn:intermediateCatchEvent>
<bpmn:sequenceFlow id="node_9" name="" sourceRef="node_3" targetRef="node_6" />
<bpmn:intermediateCatchEvent id="node_15" name="Intermediate Message Catch Event">
<bpmn:incoming>node_11</bpmn:incoming>
<bpmn:outgoing>node_23</bpmn:outgoing>
<bpmn:messageEventDefinition messageRef="node_19_message" />
</bpmn:intermediateCatchEvent>
<bpmn:sequenceFlow id="node_11" name="" sourceRef="node_3" targetRef="node_15" />
<bpmn:endEvent id="node_19" name="Message End Event">
<bpmn:incoming>node_18</bpmn:incoming>
<bpmn:messageEventDefinition messageRef="node_19_message" />
</bpmn:endEvent>
<bpmn:sequenceFlow id="node_18" name="" sourceRef="node_6" targetRef="node_19" />
<bpmn:endEvent id="node_24" name="Signal End Event">
<bpmn:incoming>node_23</bpmn:incoming>
<bpmn:signalEventDefinition signalRef="sync_assignment" />
</bpmn:endEvent>
<bpmn:sequenceFlow id="node_23" name="" sourceRef="node_15" targetRef="node_24" />
<bpmn:intermediateCatchEvent id="node_27" name="Intermediate Signal Catch Event">
<bpmn:incoming>node_26</bpmn:incoming>
<bpmn:outgoing>node_30</bpmn:outgoing>
<bpmn:signalEventDefinition signalRef="sync_assignment" />
</bpmn:intermediateCatchEvent>
<bpmn:sequenceFlow id="node_26" name="" sourceRef="node_3" targetRef="node_27" />
<bpmn:endEvent id="node_28" name="End Event" pm:screenRef="">
<bpmn:incoming>node_30</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="node_30" name="" sourceRef="node_27" targetRef="node_28" />
</bpmn:process>
<bpmn:message id="node_19_message" name="node_19_message" />
<bpmn:signal id="sync_assignment" name="sync_assignment" />
<bpmndi:BPMNDiagram id="BPMNDiagramId">
<bpmndi:BPMNPlane id="BPMNPlaneId" bpmnElement="ProcessId">
<bpmndi:BPMNShape id="node_1_di" bpmnElement="node_1">
<dc:Bounds x="270" y="280" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="node_3_di" bpmnElement="node_3">
<dc:Bounds x="400" y="280" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="node_5_di" bpmnElement="node_5">
<di:waypoint x="288" y="298" />
<di:waypoint x="418" y="298" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="node_6_di" bpmnElement="node_6">
<dc:Bounds x="590" y="280" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="node_9_di" bpmnElement="node_9">
<di:waypoint x="418" y="298" />
<di:waypoint x="608" y="298" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="node_15_di" bpmnElement="node_15">
<dc:Bounds x="400" y="440" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="node_11_di" bpmnElement="node_11">
<di:waypoint x="418" y="298" />
<di:waypoint x="418" y="458" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="node_19_di" bpmnElement="node_19">
<dc:Bounds x="840" y="280" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="node_18_di" bpmnElement="node_18">
<di:waypoint x="608" y="298" />
<di:waypoint x="858" y="298" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="node_24_di" bpmnElement="node_24">
<dc:Bounds x="400" y="560" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="node_23_di" bpmnElement="node_23">
<di:waypoint x="418" y="458" />
<di:waypoint x="418" y="578" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="node_27_di" bpmnElement="node_27">
<dc:Bounds x="400" y="140" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="node_26_di" bpmnElement="node_26">
<di:waypoint x="418" y="298" />
<di:waypoint x="418" y="158" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="node_28_di" bpmnElement="node_28">
<dc:Bounds x="610" y="140" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="node_30_di" bpmnElement="node_30">
<di:waypoint x="418" y="158" />
<di:waypoint x="628" y="158" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>
Loading

0 comments on commit 487a610

Please sign in to comment.