From 8a3bb20bef5988a31605e81d5ec38baddf0c5039 Mon Sep 17 00:00:00 2001 From: Martin Stamm Date: Wed, 16 Feb 2022 11:36:12 +0100 Subject: [PATCH] chore(usage-statistics): add tracking for subprocess planes closes #2756 --- .../__tests__/DeploymentEventHandlerSpec.js | 120 ++++++++++++++ .../__tests__/DiagramOpenEventHandlerSpec.js | 152 ++++++++++++++++++ .../fixtures/subprocess-content.bpmn | 22 +++ .../__tests__/fixtures/subprocess-empty.bpmn | 16 ++ .../__tests__/fixtures/subprocess-nested.bpmn | 53 ++++++ .../__tests__/fixtures/subprocess-pool.bpmn | 59 +++++++ client/src/util/metrics/index.js | 10 +- client/src/util/metrics/subprocessPlanes.js | 70 ++++++++ 8 files changed, 501 insertions(+), 1 deletion(-) create mode 100644 client/src/plugins/usage-statistics/event-handlers/__tests__/fixtures/subprocess-content.bpmn create mode 100644 client/src/plugins/usage-statistics/event-handlers/__tests__/fixtures/subprocess-empty.bpmn create mode 100644 client/src/plugins/usage-statistics/event-handlers/__tests__/fixtures/subprocess-nested.bpmn create mode 100644 client/src/plugins/usage-statistics/event-handlers/__tests__/fixtures/subprocess-pool.bpmn create mode 100644 client/src/util/metrics/subprocessPlanes.js diff --git a/client/src/plugins/usage-statistics/event-handlers/__tests__/DeploymentEventHandlerSpec.js b/client/src/plugins/usage-statistics/event-handlers/__tests__/DeploymentEventHandlerSpec.js index 96df339962..94b59ca289 100644 --- a/client/src/plugins/usage-statistics/event-handlers/__tests__/DeploymentEventHandlerSpec.js +++ b/client/src/plugins/usage-statistics/event-handlers/__tests__/DeploymentEventHandlerSpec.js @@ -26,6 +26,14 @@ import serviceTasksWithParticipantsXML from './fixtures/service-tasks-with-parti import serviceTasksWithSubprocessXML from './fixtures/service-tasks-with-subprocess.bpmn'; +import subprocessEmptyXML from './fixtures/subprocess-empty.bpmn'; + +import subprocessesNestedXML from './fixtures/subprocess-nested.bpmn'; + +import subprocessesInPoolXML from './fixtures/subprocess-pool.bpmn'; + +import subprocessesWithContentXML from './fixtures/subprocess-content.bpmn'; + import userTasksXML from './fixtures/user-tasks.bpmn'; import userTasksWithParticipantsXML from './fixtures/user-tasks-with-participants.bpmn'; @@ -814,6 +822,118 @@ describe('', () => { }); + describe('subprocess planes', () => { + + describe('bpmn', () => { + + it('should send metrics with subprocess plane', async () => { + + // given + const tab = createTab({ + type: 'bpmn', + file: { + contents: subprocessesWithContentXML + } + }); + + const handleDeploymentDone = subscribe.getCall(0).args[1]; + + // when + await handleDeploymentDone({ tab }); + + const { diagramMetrics } = onSend.getCall(0).args[0]; + + // then + expect(diagramMetrics.subprocessPlanes).to.eql({ + count: 1, + nesting: 1 + }); + + }); + + + it('should send empty metrics with empty subprocess plane', async () => { + + // given + const tab = createTab({ + type: 'bpmn', + file: { + contents: subprocessEmptyXML + } + }); + + const handleDeploymentDone = subscribe.getCall(0).args[1]; + + // when + await handleDeploymentDone({ tab }); + + const { diagramMetrics } = onSend.getCall(0).args[0]; + + // then + expect(diagramMetrics.subprocessPlanes).to.eql({ + count: 0, + nesting: 0 + }); + + }); + + + it('should send metrics with nested subprocess planes', async () => { + + // given + const tab = createTab({ + type: 'bpmn', + file: { + contents: subprocessesNestedXML + } + }); + + const handleDeploymentDone = subscribe.getCall(0).args[1]; + + // when + await handleDeploymentDone({ tab }); + + const { diagramMetrics } = onSend.getCall(0).args[0]; + + // then + expect(diagramMetrics.subprocessPlanes).to.eql({ + count: 4, + nesting: 3 + }); + + }); + + + it('should send metrics with subprocess planes in pools', async () => { + + // given + const tab = createTab({ + type: 'bpmn', + file: { + contents: subprocessesInPoolXML + } + }); + + const handleDeploymentDone = subscribe.getCall(0).args[1]; + + // when + await handleDeploymentDone({ tab }); + + const { diagramMetrics } = onSend.getCall(0).args[0]; + + // then + expect(diagramMetrics.subprocessPlanes).to.eql({ + count: 4, + nesting: 3 + }); + + }); + + }); + + }); + + it('should NOT send metrics for DMN', async () => { // given diff --git a/client/src/plugins/usage-statistics/event-handlers/__tests__/DiagramOpenEventHandlerSpec.js b/client/src/plugins/usage-statistics/event-handlers/__tests__/DiagramOpenEventHandlerSpec.js index 2c3ba7ca90..e3593ebdc5 100644 --- a/client/src/plugins/usage-statistics/event-handlers/__tests__/DiagramOpenEventHandlerSpec.js +++ b/client/src/plugins/usage-statistics/event-handlers/__tests__/DiagramOpenEventHandlerSpec.js @@ -30,6 +30,14 @@ import serviceTasksWithParticipantsXML from './fixtures/service-tasks-with-parti import serviceTasksWithSubprocessXML from './fixtures/service-tasks-with-subprocess.bpmn'; +import subprocessEmptyXML from './fixtures/subprocess-empty.bpmn'; + +import subprocessesNestedXML from './fixtures/subprocess-nested.bpmn'; + +import subprocessesInPoolXML from './fixtures/subprocess-pool.bpmn'; + +import subprocessesWithContentXML from './fixtures/subprocess-content.bpmn'; + import userTasksXML from './fixtures/user-tasks.bpmn'; import userTasksWithParticipantsXML from './fixtures/user-tasks-with-participants.bpmn'; @@ -1076,6 +1084,150 @@ describe('', () => { }); + describe('subprocess planes', () => { + + describe('bpmn', () => { + + it('should send metrics with subprocess plane', async () => { + + // given + const subscribe = sinon.spy(); + const onSend = sinon.spy(); + const tab = createTab({ + type: 'bpmn', + file: { + contents: subprocessesWithContentXML + } + }); + + const config = { get: () => null }; + + // when + const diagramOpenEventHandler = new DiagramOpenEventHandler({ onSend, subscribe, config }); + + diagramOpenEventHandler.enable(); + + const bpmnCallback = subscribe.getCall(0).args[1]; + + await bpmnCallback({ tab }); + + const { diagramMetrics } = onSend.getCall(0).args[0]; + + // then + expect(diagramMetrics.subprocessPlanes).to.eql({ + count: 1, + nesting: 1 + }); + + }); + + + it('should send empty metrics with empty subprocess plane', async () => { + + // given + const subscribe = sinon.spy(); + const onSend = sinon.spy(); + const tab = createTab({ + type: 'bpmn', + file: { + contents: subprocessEmptyXML + } + }); + + const config = { get: () => null }; + + // when + const diagramOpenEventHandler = new DiagramOpenEventHandler({ onSend, subscribe, config }); + + diagramOpenEventHandler.enable(); + + const bpmnCallback = subscribe.getCall(0).args[1]; + + await bpmnCallback({ tab }); + + const { diagramMetrics } = onSend.getCall(0).args[0]; + + // then + expect(diagramMetrics.subprocessPlanes).to.eql({ + count: 0, + nesting: 0 + }); + + }); + + + it('should send metrics with nested subprocess planes', async () => { + + // given + const subscribe = sinon.spy(); + const onSend = sinon.spy(); + const tab = createTab({ + type: 'bpmn', + file: { + contents: subprocessesNestedXML + } + }); + + const config = { get: () => null }; + + // when + const diagramOpenEventHandler = new DiagramOpenEventHandler({ onSend, subscribe, config }); + + diagramOpenEventHandler.enable(); + + const bpmnCallback = subscribe.getCall(0).args[1]; + + await bpmnCallback({ tab }); + + const { diagramMetrics } = onSend.getCall(0).args[0]; + + // then + expect(diagramMetrics.subprocessPlanes).to.eql({ + count: 4, + nesting: 3 + }); + + }); + + + it('should send metrics with subprocess planes in pools', async () => { + + // given + const subscribe = sinon.spy(); + const onSend = sinon.spy(); + const tab = createTab({ + type: 'bpmn', + file: { + contents: subprocessesInPoolXML + } + }); + + const config = { get: () => null }; + + // when + const diagramOpenEventHandler = new DiagramOpenEventHandler({ onSend, subscribe, config }); + + diagramOpenEventHandler.enable(); + + const bpmnCallback = subscribe.getCall(0).args[1]; + + await bpmnCallback({ tab }); + + const { diagramMetrics } = onSend.getCall(0).args[0]; + + // then + expect(diagramMetrics.subprocessPlanes).to.eql({ + count: 4, + nesting: 3 + }); + + }); + + }); + + }); + + it('should not send metrics for DMN', async () => { // given diff --git a/client/src/plugins/usage-statistics/event-handlers/__tests__/fixtures/subprocess-content.bpmn b/client/src/plugins/usage-statistics/event-handlers/__tests__/fixtures/subprocess-content.bpmn new file mode 100644 index 0000000000..9f43e3c5c2 --- /dev/null +++ b/client/src/plugins/usage-statistics/event-handlers/__tests__/fixtures/subprocess-content.bpmn @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/src/plugins/usage-statistics/event-handlers/__tests__/fixtures/subprocess-empty.bpmn b/client/src/plugins/usage-statistics/event-handlers/__tests__/fixtures/subprocess-empty.bpmn new file mode 100644 index 0000000000..96d8dd3ada --- /dev/null +++ b/client/src/plugins/usage-statistics/event-handlers/__tests__/fixtures/subprocess-empty.bpmn @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/client/src/plugins/usage-statistics/event-handlers/__tests__/fixtures/subprocess-nested.bpmn b/client/src/plugins/usage-statistics/event-handlers/__tests__/fixtures/subprocess-nested.bpmn new file mode 100644 index 0000000000..9a53cc64a8 --- /dev/null +++ b/client/src/plugins/usage-statistics/event-handlers/__tests__/fixtures/subprocess-nested.bpmn @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/src/plugins/usage-statistics/event-handlers/__tests__/fixtures/subprocess-pool.bpmn b/client/src/plugins/usage-statistics/event-handlers/__tests__/fixtures/subprocess-pool.bpmn new file mode 100644 index 0000000000..cf671ec947 --- /dev/null +++ b/client/src/plugins/usage-statistics/event-handlers/__tests__/fixtures/subprocess-pool.bpmn @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/src/util/metrics/index.js b/client/src/util/metrics/index.js index c905e562b0..d54c497c08 100644 --- a/client/src/util/metrics/index.js +++ b/client/src/util/metrics/index.js @@ -24,6 +24,10 @@ import { getServiceTaskMetrics } from './serviceTasks'; +import { + getSubprocessPlaneMetrics +} from './subprocessPlanes'; + export default async function(file, type) { let metrics = {}; @@ -44,12 +48,16 @@ export default async function(file, type) { // (2.2) service tasks const serviceTaskMetrics = await getServiceTaskMetrics(file, type); + // (3) subprocess planes + const subprocessPlanes = await getSubprocessPlaneMetrics(file, type); + metrics = { ...metrics, tasks: { userTask: userTaskMetrics, serviceTask: serviceTaskMetrics - } + }, + subprocessPlanes }; return metrics; diff --git a/client/src/util/metrics/subprocessPlanes.js b/client/src/util/metrics/subprocessPlanes.js new file mode 100644 index 0000000000..4311093cbb --- /dev/null +++ b/client/src/util/metrics/subprocessPlanes.js @@ -0,0 +1,70 @@ +/** + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. + * + * Camunda licenses this file to you under the MIT; you may not use this file + * except in compliance with the MIT License. + */ + +import { is } from 'bpmn-js/lib/util/ModelUtil'; +import { getBpmnDefinitions } from '../parse'; + +export async function getSubprocessPlaneMetrics(file, type) { + + const { + contents + } = file; + + let metrics = { + count: 0, + nesting: 0 + }; + + const definitions = await getBpmnDefinitions(contents); + + const diagrams = definitions.diagrams; + + const subprocessDiagrams = diagrams.filter(diagram => { + const plane = diagram.plane; + + if (!plane) { + return false; + } + + const hasContent = plane.planeElement && plane.planeElement.length; + + return hasContent && is(plane.bpmnElement, 'bpmn:SubProcess'); + }); + + if (!subprocessDiagrams.length) { + return metrics; + } + + const maximumNesting = Math.max( + ...subprocessDiagrams.map(getNestingDegree) + ); + + metrics = { + count: subprocessDiagrams.length, + nesting: maximumNesting + }; + + return metrics; +} + + +// helpers /////////////////////////////// + +function getNestingDegree(diagram) { + let element = diagram.plane.bpmnElement; + let nesting = 0; + + while (element && !is(element, 'bpmn:Process')) { + element = element.$parent; + nesting++; + } + + return nesting; +} \ No newline at end of file