From b619ffa6b79a2cd518747e8f125453bd200bcb3e Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Wed, 4 May 2022 11:46:09 +0300 Subject: [PATCH 01/26] Fix: all alarm rules are reevaluated when any attribute is deleted --- .../org/thingsboard/rule/engine/profile/DeviceState.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java index 1d139c9b8d..d0f802104f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java @@ -219,11 +219,15 @@ class DeviceState { } if (!keys.isEmpty()) { EntityKeyType keyType = getKeyTypeFromScope(scope); - keys.forEach(key -> latestValues.removeValue(new EntityKey(keyType, key))); + Set removedKeys = keys.stream().map(key -> new EntityKey(keyType, key)) + .peek(latestValues::removeValue) + .map(DataSnapshot::toConditionKey).collect(Collectors.toSet()); + SnapshotUpdate update = new SnapshotUpdate(AlarmConditionKeyType.ATTRIBUTE, removedKeys); + for (DeviceProfileAlarm alarm : deviceProfile.getAlarmSettings()) { AlarmState alarmState = alarmStates.computeIfAbsent(alarm.getId(), a -> new AlarmState(this.deviceProfile, deviceId, alarm, getOrInitPersistedAlarmState(alarm), dynamicPredicateValueCtx)); - stateChanged |= alarmState.process(ctx, msg, latestValues, null); + stateChanged |= alarmState.process(ctx, msg, latestValues, update); } } ctx.tellSuccess(msg); From 3098b2925a9f9a5e67450d8b511e3f906559c397 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Wed, 4 May 2022 11:47:41 +0300 Subject: [PATCH 02/26] Fix NPE when handling alarm delete notification for cleared alarm --- .../java/org/thingsboard/rule/engine/profile/DeviceState.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java index d0f802104f..f0bbdfb66b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java @@ -197,7 +197,8 @@ class DeviceState { private void processAlarmDeleteNotification(TbContext ctx, TbMsg msg) { Alarm alarm = JacksonUtil.fromString(msg.getData(), Alarm.class); - alarmStates.values().removeIf(alarmState -> alarmState.getCurrentAlarm().getId().equals(alarm.getId())); + alarmStates.values().removeIf(alarmState -> alarmState.getCurrentAlarm() != null + && alarmState.getCurrentAlarm().getId().equals(alarm.getId())); ctx.tellSuccess(msg); } From a5236e7547e922cd129a84ceab445bef84b55e22 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Tue, 10 May 2022 11:07:45 +0300 Subject: [PATCH 03/26] Tests for DeviceState --- .../rule/engine/profile/DeviceStateTest.java | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java new file mode 100644 index 0000000000..0f7795ab9d --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java @@ -0,0 +1,176 @@ +/** + * Copyright © 2016-2022 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.profile; + +import com.google.common.util.concurrent.Futures; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.RuleEngineAlarmService; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.server.common.data.DataConstants; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmSeverity; +import org.thingsboard.server.common.data.device.profile.AlarmCondition; +import org.thingsboard.server.common.data.device.profile.AlarmConditionFilter; +import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey; +import org.thingsboard.server.common.data.device.profile.AlarmConditionKeyType; +import org.thingsboard.server.common.data.device.profile.AlarmRule; +import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm; +import org.thingsboard.server.common.data.device.profile.DeviceProfileData; +import org.thingsboard.server.common.data.device.profile.SimpleAlarmConditionSpec; +import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.query.BooleanFilterPredicate; +import org.thingsboard.server.common.data.query.EntityKeyValueType; +import org.thingsboard.server.common.data.query.FilterPredicateValue; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.common.msg.session.SessionMsgType; +import org.thingsboard.server.dao.attributes.AttributesService; +import org.thingsboard.server.dao.device.DeviceService; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyCollection; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class DeviceStateTest { + + private TbContext ctx; + + @Before + public void beforeEach() { + ctx = mock(TbContext.class); + + when(ctx.getDeviceService()).thenReturn(mock(DeviceService.class)); + + AttributesService attributesService = mock(AttributesService.class); + when(attributesService.find(any(), any(), any(), anyCollection())).thenReturn(Futures.immediateFuture(Collections.emptyList())); + when(ctx.getAttributesService()).thenReturn(attributesService); + + RuleEngineAlarmService alarmService = mock(RuleEngineAlarmService.class); + when(alarmService.findLatestByOriginatorAndType(any(), any(), any())).thenReturn(Futures.immediateFuture(null)); + when(alarmService.createOrUpdateAlarm(any())).thenAnswer(invocationOnMock -> { + Alarm alarm = invocationOnMock.getArgument(0); + alarm.setId(new AlarmId(UUID.randomUUID())); + return alarm; + }); + when(ctx.getAlarmService()).thenReturn(alarmService); + + when(ctx.newMsg(any(), any(), any(), any(), any(), any())).thenAnswer(invocationOnMock -> { + String data = invocationOnMock.getArgument(invocationOnMock.getArguments().length - 1); + return TbMsg.newMsg(null, null, new TbMsgMetaData(), data); + }); + + } + + @Test + public void whenAttributeIsDeleted_thenUnneededAlarmRulesAreNotReevaluated() throws Exception { + + DeviceProfileAlarm alarmConfig = createAlarmConfigWithBoolAttrCondition("enabled", false); + DeviceId deviceId = new DeviceId(UUID.randomUUID()); + DeviceState deviceState = createDeviceState(deviceId, alarmConfig); + + TbMsg attributeUpdateMsg = TbMsg.newMsg(SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), + deviceId, new TbMsgMetaData(), "{ \"enabled\": false }"); + + deviceState.process(ctx, attributeUpdateMsg); + + ArgumentCaptor resultMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx).enqueueForTellNext(resultMsgCaptor.capture(), eq("Alarm Created")); + Alarm alarm = JacksonUtil.fromString(resultMsgCaptor.getValue().getData(), Alarm.class); + + deviceState.process(ctx, TbMsg.newMsg(DataConstants.ALARM_CLEAR, deviceId, new TbMsgMetaData(), JacksonUtil.toString(alarm))); + reset(ctx); + + String deletedAttributes = "{ \"attributes\": [ \"other\" ] }"; + deviceState.process(ctx, TbMsg.newMsg(DataConstants.ATTRIBUTES_DELETED, deviceId, new TbMsgMetaData(), deletedAttributes)); + verify(ctx, never()).enqueueForTellNext(any(), anyString()); + } + + @Test + public void whenDeletingClearedAlarm_thenNoError() throws Exception { + DeviceProfileAlarm alarmConfig = createAlarmConfigWithBoolAttrCondition("enabled", false); + DeviceId deviceId = new DeviceId(UUID.randomUUID()); + DeviceState deviceState = createDeviceState(deviceId, alarmConfig); + + TbMsg attributeUpdateMsg = TbMsg.newMsg(SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), + deviceId, new TbMsgMetaData(), "{ \"enabled\": false }"); + + deviceState.process(ctx, attributeUpdateMsg); + ArgumentCaptor resultMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx).enqueueForTellNext(resultMsgCaptor.capture(), eq("Alarm Created")); + Alarm alarm = JacksonUtil.fromString(resultMsgCaptor.getValue().getData(), Alarm.class); + + deviceState.process(ctx, TbMsg.newMsg(DataConstants.ALARM_CLEAR, deviceId, new TbMsgMetaData(), JacksonUtil.toString(alarm))); + + TbMsg alarmDeleteNotification = TbMsg.newMsg(DataConstants.ALARM_DELETE, deviceId, new TbMsgMetaData(), JacksonUtil.toString(alarm)); + assertDoesNotThrow(() -> { + deviceState.process(ctx, alarmDeleteNotification); + }); + } + + + private DeviceState createDeviceState(DeviceId deviceId, DeviceProfileAlarm... alarmConfigs) { + DeviceProfile deviceProfile = new DeviceProfile(); + DeviceProfileData profileData = new DeviceProfileData(); + profileData.setAlarms(List.of(alarmConfigs)); + deviceProfile.setProfileData(profileData); + + ProfileState profileState = new ProfileState(deviceProfile); + return new DeviceState(ctx, new TbDeviceProfileNodeConfiguration(), + deviceId, profileState, null); + } + + private DeviceProfileAlarm createAlarmConfigWithBoolAttrCondition(String key, boolean value) { + + AlarmConditionFilter condition = new AlarmConditionFilter(); + condition.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.ATTRIBUTE, key)); + condition.setValueType(EntityKeyValueType.BOOLEAN); + BooleanFilterPredicate predicate = new BooleanFilterPredicate(); + predicate.setOperation(BooleanFilterPredicate.BooleanOperation.EQUAL); + predicate.setValue(new FilterPredicateValue<>(value)); + condition.setPredicate(predicate); + + DeviceProfileAlarm alarmConfig = new DeviceProfileAlarm(); + alarmConfig.setId("MyAlarmID"); + alarmConfig.setAlarmType("MyAlarm"); + AlarmRule alarmRule = new AlarmRule(); + AlarmCondition alarmCondition = new AlarmCondition(); + alarmCondition.setSpec(new SimpleAlarmConditionSpec()); + alarmCondition.setCondition(List.of(condition)); + alarmRule.setCondition(alarmCondition); + alarmConfig.setCreateRules(new TreeMap<>(Map.of(AlarmSeverity.CRITICAL, alarmRule))); + + return alarmConfig; + } + +} From 7c1d0fb6463e6ccec4308be6f58a30187515485d Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Tue, 24 May 2022 12:50:45 +0300 Subject: [PATCH 04/26] Permission check for getDeviceProfileInfoById --- .../controller/DeviceProfileController.java | 2 +- .../server/controller/AbstractWebTest.java | 2 ++ .../BaseDeviceProfileControllerTest.java | 20 +++++++++++++++++++ .../server/common/data/DeviceProfileInfo.java | 5 +++++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java index 25a35e77fa..21a2c2adb1 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java @@ -109,7 +109,7 @@ public class DeviceProfileController extends BaseController { checkParameter(DEVICE_PROFILE_ID, strDeviceProfileId); try { DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(strDeviceProfileId)); - return checkNotNull(deviceProfileService.findDeviceProfileInfoById(getTenantId(), deviceProfileId)); + return new DeviceProfileInfo(checkDeviceProfileId(deviceProfileId, Operation.READ)); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java index cc561e31a8..bb16743a31 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java @@ -216,6 +216,7 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest { loginSysAdmin(); doDelete("/api/tenant/" + tenantId.getId().toString()) .andExpect(status().isOk()); + deleteDifferentTenant(); verifyNoTenantsLeft(); @@ -297,6 +298,7 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest { loginSysAdmin(); doDelete("/api/tenant/" + savedDifferentTenant.getId().getId().toString()) .andExpect(status().isOk()); + savedDifferentTenant = null; } } diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java index 6e0839b354..d9a0907bbe 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java @@ -125,6 +125,16 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController Assert.assertEquals(savedDeviceProfile, foundDeviceProfile); } + @Test + public void whenGetDeviceProfileById_thenPermissionsAreChecked() throws Exception { + DeviceProfile deviceProfile = createDeviceProfile("Device profile 1", null); + deviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); + + loginDifferentTenant(); + doGet("/api/deviceProfile/" + deviceProfile.getId()) + .andExpect(status().isForbidden()); + } + @Test public void testFindDeviceProfileInfoById() throws Exception { DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null); @@ -136,6 +146,16 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController Assert.assertEquals(savedDeviceProfile.getType(), foundDeviceProfileInfo.getType()); } + @Test + public void whenGetDeviceProfileInfoById_thenPermissionsAreChecked() throws Exception { + DeviceProfile deviceProfile = createDeviceProfile("Device profile 1", null); + deviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); + + loginDifferentTenant(); + doGet("/api/deviceProfileInfo/" + deviceProfile.getId()) + .andExpect(status().isForbidden()); + } + @Test public void testFindDefaultDeviceProfileInfo() throws Exception { DeviceProfileInfo foundDefaultDeviceProfileInfo = doGet("/api/deviceProfileInfo/default", DeviceProfileInfo.class); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java index a05950d11d..f99d5181f7 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfileInfo.java @@ -63,4 +63,9 @@ public class DeviceProfileInfo extends EntityInfo { this.transportType = transportType; } + public DeviceProfileInfo(DeviceProfile profile) { + this(profile.getId(), profile.getName(), profile.getImage(), profile.getDefaultDashboardId(), + profile.getType(), profile.getTransportType()); + } + } From 50f2aa6fecf09c61b90b794a71824968564570d4 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Wed, 8 Jun 2022 16:28:12 +0300 Subject: [PATCH 05/26] compression type added for transports yaml --- transport/coap/src/main/resources/tb-coap-transport.yml | 1 + transport/http/src/main/resources/tb-http-transport.yml | 1 + transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml | 1 + transport/mqtt/src/main/resources/tb-mqtt-transport.yml | 1 + transport/snmp/src/main/resources/tb-snmp-transport.yml | 1 + 5 files changed, 5 insertions(+) diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index 5262fbaef1..4b7b913fa9 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -149,6 +149,7 @@ queue: bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}" acks: "${TB_KAFKA_ACKS:all}" retries: "${TB_KAFKA_RETRIES:1}" + compression.type: "${TB_KAFKA_COMPRESSION_TYPE:none}" # none or gzip batch.size: "${TB_KAFKA_BATCH_SIZE:16384}" linger.ms: "${TB_KAFKA_LINGER_MS:1}" max.request.size: "${TB_KAFKA_MAX_REQUEST_SIZE:1048576}" diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index 7574687ecc..fdab6ab978 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -136,6 +136,7 @@ queue: bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}" acks: "${TB_KAFKA_ACKS:all}" retries: "${TB_KAFKA_RETRIES:1}" + compression.type: "${TB_KAFKA_COMPRESSION_TYPE:none}" # none or gzip batch.size: "${TB_KAFKA_BATCH_SIZE:16384}" linger.ms: "${TB_KAFKA_LINGER_MS:1}" max.request.size: "${TB_KAFKA_MAX_REQUEST_SIZE:1048576}" diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 19d70e0bc2..a70f2059f5 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -214,6 +214,7 @@ queue: bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}" acks: "${TB_KAFKA_ACKS:all}" retries: "${TB_KAFKA_RETRIES:1}" + compression.type: "${TB_KAFKA_COMPRESSION_TYPE:none}" # none or gzip batch.size: "${TB_KAFKA_BATCH_SIZE:16384}" linger.ms: "${TB_KAFKA_LINGER_MS:1}" max.request.size: "${TB_KAFKA_MAX_REQUEST_SIZE:1048576}" diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index 1a6f04e598..3bfbbd9145 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -166,6 +166,7 @@ queue: bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}" acks: "${TB_KAFKA_ACKS:all}" retries: "${TB_KAFKA_RETRIES:1}" + compression.type: "${TB_KAFKA_COMPRESSION_TYPE:none}" # none or gzip batch.size: "${TB_KAFKA_BATCH_SIZE:16384}" linger.ms: "${TB_KAFKA_LINGER_MS:1}" max.request.size: "${TB_KAFKA_MAX_REQUEST_SIZE:1048576}" diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index 6ff1a37442..a6e5533b15 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -112,6 +112,7 @@ queue: bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}" acks: "${TB_KAFKA_ACKS:all}" retries: "${TB_KAFKA_RETRIES:1}" + compression.type: "${TB_KAFKA_COMPRESSION_TYPE:none}" # none or gzip batch.size: "${TB_KAFKA_BATCH_SIZE:16384}" linger.ms: "${TB_KAFKA_LINGER_MS:1}" max.request.size: "${TB_KAFKA_MAX_REQUEST_SIZE:1048576}" From e190f253eb2fbf6aaeeaaa9db616b5406bc27332 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Wed, 8 Jun 2022 17:01:04 +0300 Subject: [PATCH 06/26] Fix NPE in 'copy to view' node --- .../action/TbCopyAttributesToEntityViewNode.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java index b27caf6838..7b4f1792c4 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java @@ -21,6 +21,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; import lombok.extern.slf4j.Slf4j; +import org.thingsboard.common.util.CollectionsUtil; import org.thingsboard.common.util.DonAsynchron; import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; import org.thingsboard.rule.engine.api.RuleNode; @@ -32,6 +33,7 @@ import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.objects.AttributesEntityView; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.session.SessionMsgType; @@ -140,15 +142,20 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { } private boolean attributeContainsInEntityView(String scope, String attrKey, EntityView entityView) { + AttributesEntityView attributesEntityView = entityView.getKeys().getAttributes(); + List keys = null; switch (scope) { case DataConstants.CLIENT_SCOPE: - return entityView.getKeys().getAttributes().getCs().contains(attrKey); + keys = attributesEntityView.getCs(); + break; case DataConstants.SERVER_SCOPE: - return entityView.getKeys().getAttributes().getSs().contains(attrKey); + keys = attributesEntityView.getSs(); + break; case DataConstants.SHARED_SCOPE: - return entityView.getKeys().getAttributes().getSh().contains(attrKey); + keys = attributesEntityView.getSh(); + break; } - return false; + return CollectionsUtil.contains(keys, attrKey); } @Override From feb957e261ff698aa399c507768f617835495be3 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 16 Jun 2022 12:48:11 +0300 Subject: [PATCH 07/26] refactoring: customer tests error -> different type exception --- .../controller/AbstractNotifyEntityTest.java | 39 +++++++++---------- .../BaseCustomerControllerTest.java | 20 +++++----- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java index d908ac8d2a..ec6fb2d710 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java @@ -56,15 +56,6 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { Mockito.reset(tbClusterService, auditLogService); } - protected void testNotifyEntityDeleteOneTimeMsgToEdgeServiceNever(HasName entity, EntityId entityId, EntityId originatorId, - TenantId tenantId, CustomerId customerId, UserId userId, String userName, - ActionType actionType, Object... additionalInfo) { - testNotificationMsgToEdgeServiceNever(entityId); - testLogEntityActionOneTime(entity, originatorId, tenantId, customerId, userId, userName, actionType, additionalInfo); - testPushMsgToRuleEngineOneTime(entityId, tenantId); - testBroadcastEntityStateChangeEventOneTime(entityId, tenantId); - Mockito.reset(tbClusterService, auditLogService); - } protected void testNotifyEntityNeverMsgToEdgeServiceOneTime(HasName entity, EntityId entityId, TenantId tenantId, ActionType actionType) { testSendNotificationMsgToEdgeServiceOneTime(entityId, tenantId, actionType); testLogEntityActionNever(entityId, entity); @@ -95,25 +86,31 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { UserId userId, String userName, ActionType actionType, Exception exp, Object... additionalInfo) { CustomerId customer_NULL_UUID = (CustomerId) EntityIdFactory.getByTypeAndUuid(EntityType.CUSTOMER, ModelConstants.NULL_UUID); - EntityId entity_NULL_UUID = EntityIdFactory.getByTypeAndUuid(EntityType.valueOf(entity.getClass().toString() + EntityId entity_NULL_UUID = EntityIdFactory.getByTypeAndUuid( + EntityType + .valueOf(entity.getClass() + .toString() .substring(entity.getClass().toString().lastIndexOf(".") + 1).toUpperCase(Locale.ENGLISH)), ModelConstants.NULL_UUID); testNotificationMsgToEdgeServiceNever(entity_NULL_UUID); if (additionalInfo.length > 0) { - Mockito.verify(auditLogService, times(1)).logEntityAction(Mockito.eq(tenantId), - Mockito.eq(customer_NULL_UUID), Mockito.eq(userId), Mockito.eq(userName), - Mockito.eq(entity_NULL_UUID), Mockito.any(entity.getClass()), Mockito.eq(actionType), - Mockito.argThat(argument -> - argument.getMessage().equals(exp.getMessage())), Mockito.eq(additionalInfo)); + Mockito.verify(auditLogService, times(1)) + .logEntityAction(Mockito.eq(tenantId), + Mockito.eq(customer_NULL_UUID), Mockito.eq(userId), Mockito.eq(userName), + Mockito.eq(entity_NULL_UUID), Mockito.any(entity.getClass()), Mockito.eq(actionType), + Mockito.argThat(argument -> + argument.getMessage().contains(exp.getMessage())), + Mockito.eq(additionalInfo) + ); } else { - Mockito.verify(auditLogService, times(1)).logEntityAction(Mockito.eq(tenantId), - Mockito.eq(customer_NULL_UUID), Mockito.eq(userId), Mockito.eq(userName), - Mockito.eq(entity_NULL_UUID), Mockito.any(entity.getClass()), Mockito.eq(actionType), - Mockito.argThat(argument -> - argument.getMessage().equals(exp.getMessage()))); + Mockito.verify(auditLogService, times(1)) + .logEntityAction(Mockito.eq(tenantId), + Mockito.eq(customer_NULL_UUID), Mockito.eq(userId), Mockito.eq(userName), + Mockito.eq(entity_NULL_UUID), Mockito.any(entity.getClass()), Mockito.eq(actionType), + Mockito.argThat((argument -> argument.getMessage().contains(exp.getMessage()) & argument.getClass().equals(exp.getClass()))) + ); } testPushMsgToRuleEngineNever(entity_NULL_UUID); - Mockito.reset(tbClusterService, auditLogService); } protected void testNotifyEntityNever(EntityId entityId, HasName entity) { diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java index 1f94fa4784..e65dd0d5be 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java @@ -121,7 +121,6 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest @Test public void testSaveCustomerWithViolationOfValidation() throws Exception { Customer customer = new Customer(); - String validationError = "Validation error: "; customer.setTitle(RandomStringUtils.randomAlphabetic(300)); Mockito.reset(tbClusterService, auditLogService); @@ -130,7 +129,8 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); testNotifyEntityError(customer, savedTenant.getId(), - tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(validationError + msgError)); + tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); + Mockito.reset(tbClusterService, auditLogService); customer.setTitle("Normal title"); customer.setCity(RandomStringUtils.randomAlphabetic(300)); @@ -138,7 +138,8 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); testNotifyEntityError(customer, savedTenant.getId(), - tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(validationError + msgError)); + tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); + Mockito.reset(tbClusterService, auditLogService); customer.setCity("Normal city"); customer.setCountry(RandomStringUtils.randomAlphabetic(300)); @@ -146,7 +147,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); testNotifyEntityError(customer, savedTenant.getId(), - tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(validationError + msgError)); + tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); customer.setCountry("Ukraine"); customer.setPhone(RandomStringUtils.randomAlphabetic(300)); @@ -154,7 +155,8 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); testNotifyEntityError(customer, savedTenant.getId(), - tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(validationError + msgError)); + tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); + Mockito.reset(tbClusterService, auditLogService); customer.setPhone("+3892555554512"); customer.setState(RandomStringUtils.randomAlphabetic(300)); @@ -162,7 +164,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); testNotifyEntityError(customer, savedTenant.getId(), - tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(validationError + msgError)); + tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); customer.setState("Normal state"); customer.setZip(RandomStringUtils.randomAlphabetic(300)); @@ -170,7 +172,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); testNotifyEntityError(customer, savedTenant.getId(), - tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(validationError + msgError)); + tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); } @@ -247,7 +249,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest .andExpect(statusReason(containsString(msgError))); testNotifyEntityError(customer, savedTenant.getId(), - tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError + "!")); + tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); } @Test @@ -264,7 +266,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest .andExpect(statusReason(containsString(msgError))); testNotifyEntityError(customer, savedTenant.getId(), - tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError + "!")); + tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); } @Test From 1df23e2a9a031f58827b3b11a4d1f8ef69b82033 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 16 Jun 2022 15:33:22 +0300 Subject: [PATCH 08/26] refactoring: customer tests error -> different type exception --- .../controller/AbstractNotifyEntityTest.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java index ec6fb2d710..13e76dbd3b 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java @@ -86,12 +86,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { UserId userId, String userName, ActionType actionType, Exception exp, Object... additionalInfo) { CustomerId customer_NULL_UUID = (CustomerId) EntityIdFactory.getByTypeAndUuid(EntityType.CUSTOMER, ModelConstants.NULL_UUID); - EntityId entity_NULL_UUID = EntityIdFactory.getByTypeAndUuid( - EntityType - .valueOf(entity.getClass() - .toString() - .substring(entity.getClass().toString().lastIndexOf(".") + 1).toUpperCase(Locale.ENGLISH)), - ModelConstants.NULL_UUID); + EntityId entity_NULL_UUID = createEntityId_NULL_UUID (entity); testNotificationMsgToEdgeServiceNever(entity_NULL_UUID); if (additionalInfo.length > 0) { Mockito.verify(auditLogService, times(1)) @@ -114,6 +109,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { } protected void testNotifyEntityNever(EntityId entityId, HasName entity) { + entityId = entityId == null ? createEntityId_NULL_UUID (entity) : entityId; testNotificationMsgToEdgeServiceNever(entityId); testLogEntityActionNever(entityId, entity); testPushMsgToRuleEngineNever(entityId); @@ -176,4 +172,10 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { } return result; } + + private EntityId createEntityId_NULL_UUID (HasName entity) { + return EntityIdFactory.getByTypeAndUuid(EntityType.valueOf(entity.getClass().toString() + .substring(entity.getClass().toString().lastIndexOf(".") + 1).toUpperCase(Locale.ENGLISH)), + ModelConstants.NULL_UUID); + } } From ed5696c3f942e39d58b46045027abfa95c95e25a Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 17 Jun 2022 16:01:40 +0300 Subject: [PATCH 09/26] refactoring: fix bug asset.save alarm.delete --- .../entitiy/alarm/DefaultTbAlarmService.java | 20 ++++++++++++++----- .../service/entitiy/alarm/TbAlarmService.java | 3 +++ .../entitiy/asset/DefaultTbAssetService.java | 2 +- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index 4930f54a5d..c467e0804b 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.queue.util.TbCoreComponent; @@ -54,7 +55,7 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb public void ack(Alarm alarm, SecurityUser user) throws ThingsboardException { try { long ackTs = System.currentTimeMillis(); - alarmService.ackAlarm(user.getTenantId(), alarm.getId(), ackTs).get(); + alarmService.ackAlarm(alarm.getTenantId(), alarm.getId(), ackTs).get(); alarm.setAckTs(ackTs); alarm.setStatus(alarm.getStatus().isCleared() ? AlarmStatus.CLEARED_ACK : AlarmStatus.ACTIVE_ACK); notificationEntityService.notifyCreateOrUpdateAlarm(alarm, ActionType.ALARM_ACK, user); @@ -67,7 +68,7 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb public void clear(Alarm alarm, SecurityUser user) throws ThingsboardException { try { long clearTs = System.currentTimeMillis(); - alarmService.clearAlarm(user.getTenantId(), alarm.getId(), null, clearTs).get(); + alarmService.clearAlarm(alarm.getTenantId(), alarm.getId(), null, clearTs).get(); alarm.setClearTs(clearTs); alarm.setStatus(alarm.getStatus().isAck() ? AlarmStatus.CLEARED_ACK : AlarmStatus.CLEARED_UNACK); notificationEntityService.notifyCreateOrUpdateAlarm(alarm, ActionType.ALARM_CLEAR, user); @@ -78,11 +79,20 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb @Override public Boolean delete(Alarm alarm, SecurityUser user) throws ThingsboardException { + return delete(alarm, user.getCustomerId(), user); + } + + @Override + public Boolean delete(Alarm alarm, CustomerId customerId) throws ThingsboardException { + return delete(alarm, customerId, null); + } + + private Boolean delete(Alarm alarm, CustomerId customerId, SecurityUser user) throws ThingsboardException { try { - List relatedEdgeIds = findRelatedEdgeIds(user.getTenantId(), alarm.getOriginator()); - notificationEntityService.notifyDeleteAlarm(user.getTenantId(), alarm, alarm.getOriginator(), user.getCustomerId(), + List relatedEdgeIds = findRelatedEdgeIds(alarm.getTenantId(), alarm.getOriginator()); + notificationEntityService.notifyDeleteAlarm(alarm.getTenantId(), alarm, alarm.getOriginator(), customerId, relatedEdgeIds, user, JacksonUtil.OBJECT_MAPPER.writeValueAsString(alarm)); - return alarmService.deleteAlarm(user.getTenantId(), alarm.getId()).isSuccessful(); + return alarmService.deleteAlarm(alarm.getTenantId(), alarm.getId()).isSuccessful(); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java index 7a6d7f6a81..de617a965f 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java @@ -17,6 +17,7 @@ package org.thingsboard.server.service.entitiy.alarm; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.service.security.model.SecurityUser; public interface TbAlarmService { @@ -28,4 +29,6 @@ public interface TbAlarmService { void clear(Alarm alarm, SecurityUser user) throws ThingsboardException; Boolean delete(Alarm alarm, SecurityUser user) throws ThingsboardException; + + Boolean delete(Alarm alarm, CustomerId customerId) throws ThingsboardException; } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java index 492464f147..28c8a5438e 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java @@ -46,7 +46,7 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb TenantId tenantId = asset.getTenantId(); try { Asset savedAsset = checkNotNull(assetService.saveAsset(asset)); - notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedAsset.getId(), asset, savedAsset.getCustomerId(), actionType, user); + notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedAsset.getId(), savedAsset, savedAsset.getCustomerId(), actionType, user); return savedAsset; } catch (Exception e) { notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), asset, null, actionType, user, e); From f2695138ff36e0a7f87bafb5b7c5e89f5b2db670 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 17 Jun 2022 18:36:29 +0300 Subject: [PATCH 10/26] refactoring: add method manyTime --- .../controller/AbstractNotifyEntityTest.java | 72 +++++++++++++------ .../BaseCustomerControllerTest.java | 25 ++++--- 2 files changed, 67 insertions(+), 30 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java index 13e76dbd3b..246c8d2c86 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java @@ -50,14 +50,15 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { protected void testNotifyEntityAllOneTime(HasName entity, EntityId entityId, EntityId originatorId, TenantId tenantId, CustomerId customerId, UserId userId, String userName, ActionType actionType, Object... additionalInfo) { - testSendNotificationMsgToEdgeServiceOneTime(entityId, tenantId, actionType); + testSendNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, 1); testLogEntityActionOneTime(entity, originatorId, tenantId, customerId, userId, userName, actionType, additionalInfo); - testPushMsgToRuleEngineOneTime(originatorId, tenantId); + testPushMsgToRuleEngineTime(originatorId, tenantId, 1); Mockito.reset(tbClusterService, auditLogService); } - protected void testNotifyEntityNeverMsgToEdgeServiceOneTime(HasName entity, EntityId entityId, TenantId tenantId, ActionType actionType) { - testSendNotificationMsgToEdgeServiceOneTime(entityId, tenantId, actionType); + protected void testNotifyEntityNeverMsgToEdgeServiceOneTime(HasName entity, EntityId entityId, TenantId tenantId, + ActionType actionType) { + testSendNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, 1); testLogEntityActionNever(entityId, entity); testPushMsgToRuleEngineNever(entityId); Mockito.reset(tbClusterService, auditLogService); @@ -68,7 +69,19 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { ActionType actionType, Object... additionalInfo) { testNotificationMsgToEdgeServiceNever(entityId); testLogEntityActionOneTime(entity, originatorId, tenantId, customerId, userId, userName, actionType, additionalInfo); - testPushMsgToRuleEngineOneTime(originatorId, tenantId); + testPushMsgToRuleEngineTime(originatorId, tenantId, 1); + Mockito.reset(tbClusterService, auditLogService); + } + + protected void testNotifyEntityOneManyTimeMsgToEdgeServiceNever(HasName entity, HasName originator, + TenantId tenantId, CustomerId customerId, UserId userId, String userName, + ActionType actionType, int cntTime, Object... additionalInfo) { + EntityId entityId = createEntityId_NULL_UUID(entity); + EntityId originatorId = createEntityId_NULL_UUID(originator); + testNotificationMsgToEdgeServiceNever(entityId); + testLogEntityActionManyTime(entity,originatorId, tenantId, customerId, + userId, userName, actionType, cntTime, additionalInfo); + testPushMsgToRuleEngineTime(originatorId, tenantId, cntTime); Mockito.reset(tbClusterService, auditLogService); } @@ -77,16 +90,16 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { ActionType actionType, Object... additionalInfo) { testNotificationMsgToEdgeServiceNever(entityId); testLogEntityActionOneTime(entity, originatorId, tenantId, customerId, userId, userName, actionType, additionalInfo); - testPushMsgToRuleEngineOneTime(originatorId, tenantId); - testBroadcastEntityStateChangeEventOneTime(entityId, tenantId); + testPushMsgToRuleEngineTime(originatorId, tenantId, 1); + testBroadcastEntityStateChangeEventTime(entityId, tenantId, 1); Mockito.reset(tbClusterService, auditLogService); } - protected void testNotifyEntityError(HasName entity, TenantId tenantId, - UserId userId, String userName, ActionType actionType, Exception exp, - Object... additionalInfo) { + protected void testNotifyEntityOneTimeError(HasName entity, TenantId tenantId, + UserId userId, String userName, ActionType actionType, Exception exp, + Object... additionalInfo) { CustomerId customer_NULL_UUID = (CustomerId) EntityIdFactory.getByTypeAndUuid(EntityType.CUSTOMER, ModelConstants.NULL_UUID); - EntityId entity_NULL_UUID = createEntityId_NULL_UUID (entity); + EntityId entity_NULL_UUID = createEntityId_NULL_UUID(entity); testNotificationMsgToEdgeServiceNever(entity_NULL_UUID); if (additionalInfo.length > 0) { Mockito.verify(auditLogService, times(1)) @@ -109,7 +122,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { } protected void testNotifyEntityNever(EntityId entityId, HasName entity) { - entityId = entityId == null ? createEntityId_NULL_UUID (entity) : entityId; + entityId = entityId == null ? createEntityId_NULL_UUID(entity) : entityId; testNotificationMsgToEdgeServiceNever(entityId); testLogEntityActionNever(entityId, entity); testPushMsgToRuleEngineNever(entityId); @@ -146,19 +159,38 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { } } - private void testPushMsgToRuleEngineOneTime(EntityId originatorId, TenantId tenantId) { - Mockito.verify(tbClusterService, times(1)).pushMsgToRuleEngine(Mockito.eq(tenantId), - Mockito.eq(originatorId), Mockito.any(TbMsg.class), Mockito.isNull()); + private void testLogEntityActionManyTime(HasName entity, EntityId originatorId, TenantId tenantId, CustomerId customerId, + UserId userId, String userName, ActionType actionType, int cntTime, Object... additionalInfo) { + if (additionalInfo.length == 0) { + Mockito.verify(auditLogService, times(cntTime)).logEntityAction(Mockito.eq(tenantId), Mockito.eq(customerId), + Mockito.eq(userId), Mockito.eq(userName), Mockito.any(originatorId.getClass()), + Mockito.any(entity.getClass()), Mockito.eq(actionType), Mockito.isNull()); + } else { + String additionalInfoStr = extractParameter(String.class, 0, additionalInfo); + Mockito.verify(auditLogService, times(cntTime)).logEntityAction(Mockito.eq(tenantId), Mockito.eq(customerId), + Mockito.eq(userId), Mockito.eq(userName), Mockito.any(originatorId.getClass()), + Mockito.any(entity.getClass()), Mockito.eq(actionType), Mockito.isNull(), Mockito.eq(additionalInfoStr)); + } + } + + private void testPushMsgToRuleEngineTime(EntityId originatorId, TenantId tenantId, int cntTime) { + if (cntTime ==1) { + Mockito.verify(tbClusterService, times(cntTime)).pushMsgToRuleEngine(Mockito.eq(tenantId), + Mockito.eq(originatorId), Mockito.any(TbMsg.class), Mockito.isNull()); + } else { + Mockito.verify(tbClusterService, times(cntTime)).pushMsgToRuleEngine(Mockito.eq(tenantId), + Mockito.any(originatorId.getClass()), Mockito.any(TbMsg.class), Mockito.isNull()); + } } - private void testSendNotificationMsgToEdgeServiceOneTime(EntityId entityId, TenantId tenantId, ActionType actionType) { - Mockito.verify(tbClusterService, times(1)).sendNotificationMsgToEdgeService(Mockito.eq(tenantId), + private void testSendNotificationMsgToEdgeServiceTime(EntityId entityId, TenantId tenantId, ActionType actionType, int cntTime) { + Mockito.verify(tbClusterService, times(cntTime)).sendNotificationMsgToEdgeService(Mockito.eq(tenantId), Mockito.isNull(), Mockito.eq(entityId), Mockito.isNull(), Mockito.isNull(), Mockito.eq(edgeTypeByActionType(actionType))); } - private void testBroadcastEntityStateChangeEventOneTime(EntityId entityId, TenantId tenantId) { - Mockito.verify(tbClusterService, times(1)).broadcastEntityStateChangeEvent(Mockito.eq(tenantId), + private void testBroadcastEntityStateChangeEventTime(EntityId entityId, TenantId tenantId, int cntTime) { + Mockito.verify(tbClusterService, times(cntTime)).broadcastEntityStateChangeEvent(Mockito.eq(tenantId), Mockito.any(entityId.getClass()), Mockito.any(ComponentLifecycleEvent.class)); } @@ -173,7 +205,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { return result; } - private EntityId createEntityId_NULL_UUID (HasName entity) { + private EntityId createEntityId_NULL_UUID(HasName entity) { return EntityIdFactory.getByTypeAndUuid(EntityType.valueOf(entity.getClass().toString() .substring(entity.getClass().toString().lastIndexOf(".") + 1).toUpperCase(Locale.ENGLISH)), ModelConstants.NULL_UUID); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java index e65dd0d5be..0cda90e868 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java @@ -128,7 +128,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest String msgError = "length of title must be equal or less than 255"; doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); - testNotifyEntityError(customer, savedTenant.getId(), + testNotifyEntityOneTimeError(customer, savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); Mockito.reset(tbClusterService, auditLogService); @@ -137,7 +137,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest msgError = "length of city must be equal or less than 255"; doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); - testNotifyEntityError(customer, savedTenant.getId(), + testNotifyEntityOneTimeError(customer, savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); Mockito.reset(tbClusterService, auditLogService); @@ -146,7 +146,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest msgError = "length of country must be equal or less than 255"; doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); - testNotifyEntityError(customer, savedTenant.getId(), + testNotifyEntityOneTimeError(customer, savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); customer.setCountry("Ukraine"); @@ -154,7 +154,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest msgError = "length of phone must be equal or less than 255"; doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); - testNotifyEntityError(customer, savedTenant.getId(), + testNotifyEntityOneTimeError(customer, savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); Mockito.reset(tbClusterService, auditLogService); @@ -163,7 +163,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest msgError = "length of state must be equal or less than 255"; doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); - testNotifyEntityError(customer, savedTenant.getId(), + testNotifyEntityOneTimeError(customer, savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); customer.setState("Normal state"); @@ -171,7 +171,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest msgError = "length of zip or postal code must be equal or less than 255"; doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); - testNotifyEntityError(customer, savedTenant.getId(), + testNotifyEntityOneTimeError(customer, savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); } @@ -248,7 +248,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString(msgError))); - testNotifyEntityError(customer, savedTenant.getId(), + testNotifyEntityOneTimeError(customer, savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); } @@ -265,7 +265,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString(msgError))); - testNotifyEntityError(customer, savedTenant.getId(), + testNotifyEntityOneTimeError(customer, savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); } @@ -273,8 +273,9 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest public void testFindCustomers() throws Exception { TenantId tenantId = savedTenant.getId(); - List> futures = new ArrayList<>(135); - for (int i = 0; i < 135; i++) { + int cntTime = 135; + List> futures = new ArrayList<>(cntTime); + for (int i = 0; i < cntTime; i++) { Customer customer = new Customer(); customer.setTenantId(tenantId); customer.setTitle("Customer" + i); @@ -283,6 +284,10 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest } List customers = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS); + testNotifyEntityOneManyTimeMsgToEdgeServiceNever(new Customer(), new Customer(), + tenantId, tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), + ActionType.ADDED, cntTime); + List loadedCustomers = new ArrayList<>(135); PageLink pageLink = new PageLink(23); PageData pageData = null; From cdaacb4ed0b17c093026fe14882bb1a7c74863f9 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 17 Jun 2022 19:15:03 +0300 Subject: [PATCH 11/26] refactoring: add Mockito.reset(tbClusterService, auditLogService) --- .../server/controller/BaseCustomerControllerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java index 0cda90e868..65ce87a996 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java @@ -148,6 +148,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest testNotifyEntityOneTimeError(customer, savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); + Mockito.reset(tbClusterService, auditLogService); customer.setCountry("Ukraine"); customer.setPhone(RandomStringUtils.randomAlphabetic(300)); @@ -165,6 +166,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest testNotifyEntityOneTimeError(customer, savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); + Mockito.reset(tbClusterService, auditLogService); customer.setState("Normal state"); customer.setZip(RandomStringUtils.randomAlphabetic(300)); @@ -173,7 +175,6 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest testNotifyEntityOneTimeError(customer, savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); - } @Test @@ -376,5 +377,4 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); } - } From 87e28c9fc86a9511c1f5564ec22eb2405a0fdf75 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 17 Jun 2022 19:54:27 +0300 Subject: [PATCH 12/26] refactoring: removed extra line --- .../server/controller/AbstractNotifyEntityTest.java | 6 +++--- .../server/controller/BaseCustomerControllerTest.java | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java index 246c8d2c86..fad0feea51 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java @@ -73,9 +73,9 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { Mockito.reset(tbClusterService, auditLogService); } - protected void testNotifyEntityOneManyTimeMsgToEdgeServiceNever(HasName entity, HasName originator, - TenantId tenantId, CustomerId customerId, UserId userId, String userName, - ActionType actionType, int cntTime, Object... additionalInfo) { + protected void testNotifyEntityManyTimeMsgToEdgeServiceNever(HasName entity, HasName originator, + TenantId tenantId, CustomerId customerId, UserId userId, String userName, + ActionType actionType, int cntTime, Object... additionalInfo) { EntityId entityId = createEntityId_NULL_UUID(entity); EntityId originatorId = createEntityId_NULL_UUID(originator); testNotificationMsgToEdgeServiceNever(entityId); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java index 65ce87a996..7bd3de792d 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java @@ -213,8 +213,6 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest Assert.assertNotNull(foundCustomer); Assert.assertEquals(savedCustomer, foundCustomer); - Mockito.reset(tbClusterService, auditLogService); - doDelete("/api/customer/" + savedCustomer.getId().getId().toString()) .andExpect(status().isOk()); } @@ -275,6 +273,9 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest TenantId tenantId = savedTenant.getId(); int cntTime = 135; + + Mockito.reset(tbClusterService, auditLogService); + List> futures = new ArrayList<>(cntTime); for (int i = 0; i < cntTime; i++) { Customer customer = new Customer(); @@ -285,7 +286,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest } List customers = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS); - testNotifyEntityOneManyTimeMsgToEdgeServiceNever(new Customer(), new Customer(), + testNotifyEntityManyTimeMsgToEdgeServiceNever(new Customer(), new Customer(), tenantId, tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, cntTime); From f57578c87abe72ca3612f733e6eaf7aeec194bc5 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sat, 18 Jun 2022 10:18:58 +0300 Subject: [PATCH 13/26] update license header --- .../server/service/install/update/RateLimitsUpdater.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/RateLimitsUpdater.java b/application/src/main/java/org/thingsboard/server/service/install/update/RateLimitsUpdater.java index 054f68f71d..c136f97b52 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/RateLimitsUpdater.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/RateLimitsUpdater.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2021 The Thingsboard Authors + * Copyright © 2016-2022 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 6d29ef415ed5f23ab22150847e1bf43bf9b22f84 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Sat, 18 Jun 2022 21:07:04 +0300 Subject: [PATCH 14/26] testActiveAlarmScheduleFromDynamicValuesWhenDefaultScheduleIsInactive - to ignore --- .../rule/engine/profile/TbDeviceProfileNodeTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java index d1ac360d44..569945f106 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.AdditionalAnswers; @@ -49,7 +50,6 @@ import org.thingsboard.server.common.data.device.profile.RepeatingAlarmCondition import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceProfileId; -import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.query.BooleanFilterPredicate; @@ -1090,6 +1090,7 @@ public class TbDeviceProfileNodeTest { verify(ctx, Mockito.never()).tellFailure(Mockito.any(), Mockito.any()); } + @Ignore @Test public void testActiveAlarmScheduleFromDynamicValuesWhenDefaultScheduleIsInactive() throws Exception { init(); From c7a7e487add573bc7cc6472b38bd4d7e47b7117d Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 20 Jun 2022 12:26:53 +0300 Subject: [PATCH 15/26] testActiveAlarmScheduleFromDynamicValuesWhenDefaultScheduleIsInactive - remove ignore --- .../rule/engine/profile/TbDeviceProfileNodeTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java index 569945f106..9aa53b41f7 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java @@ -19,7 +19,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.AdditionalAnswers; @@ -1090,7 +1089,6 @@ public class TbDeviceProfileNodeTest { verify(ctx, Mockito.never()).tellFailure(Mockito.any(), Mockito.any()); } - @Ignore @Test public void testActiveAlarmScheduleFromDynamicValuesWhenDefaultScheduleIsInactive() throws Exception { init(); From 3e436ee866a372dab578a4760d94a3bc7897660f Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Sat, 18 Jun 2022 10:59:05 +0300 Subject: [PATCH 16/26] js-executor: kafkaClient.producer({ createPartitioner: Partitioners.DefaultPartitioner }) as mentioned in migration notes for the major kafka.js 2.0 --- msa/js-executor/queue/kafkaTemplate.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/msa/js-executor/queue/kafkaTemplate.js b/msa/js-executor/queue/kafkaTemplate.js index 656779869d..1d1ad75318 100644 --- a/msa/js-executor/queue/kafkaTemplate.js +++ b/msa/js-executor/queue/kafkaTemplate.js @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -const {logLevel, Kafka, CompressionTypes} = require('kafkajs'); +const {logLevel, Kafka, CompressionTypes, Partitioners} = require('kafkajs'); const config = require('config'), JsInvokeMessageProcessor = require('../api/jsInvokeMessageProcessor'), @@ -159,7 +159,7 @@ async function sendMessagesAsBatch(isImmediately) { } consumer = kafkaClient.consumer({groupId: 'js-executor-group'}); - producer = kafkaClient.producer(); + producer = kafkaClient.producer({ createPartitioner: Partitioners.DefaultPartitioner }); /* //producer event instrumentation to debug From 5d06929c73fb623442a54ec017e88d6b54360b7b Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 21 Jun 2022 18:59:18 +0300 Subject: [PATCH 17/26] refactoring: tests asset --- .../DefaultTbNotificationEntityService.java | 4 + .../entitiy/asset/DefaultTbAssetService.java | 7 +- .../controller/AbstractNotifyEntityTest.java | 225 ++++++++++++------ .../controller/BaseAssetControllerTest.java | 133 ++++++++++- .../BaseCustomerControllerTest.java | 27 ++- 5 files changed, 301 insertions(+), 95 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java index c7e4f2cd0b..b2962acf97 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java @@ -351,6 +351,10 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS return EdgeEventActionType.RELATION_ADD_OR_UPDATE; case RELATION_DELETED: return EdgeEventActionType.RELATION_DELETED; + case ASSIGNED_TO_CUSTOMER: + return EdgeEventActionType.ASSIGNED_TO_CUSTOMER; + case UNASSIGNED_FROM_CUSTOMER: + return EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER; case ASSIGNED_TO_EDGE: return EdgeEventActionType.ASSIGNED_TO_EDGE; case UNASSIGNED_FROM_EDGE: diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java index 8207427716..e118346588 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java @@ -23,7 +23,6 @@ import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; -import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; @@ -35,6 +34,8 @@ import org.thingsboard.server.service.security.model.SecurityUser; import java.util.List; +import static org.thingsboard.server.service.entitiy.DefaultTbNotificationEntityService.edgeTypeByActionType; + @Service @TbCoreComponent @AllArgsConstructor @@ -80,7 +81,7 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb try { Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(tenantId, assetId, customerId)); notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, customerId, savedAsset, - actionType, EdgeEventActionType.ASSIGNED_TO_CUSTOMER, user, true, customerId.toString(), customer.getName()); + actionType, edgeTypeByActionType(actionType), user, true, customerId.toString(), customer.getName()); return savedAsset; } catch (Exception e) { @@ -99,7 +100,7 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb CustomerId customerId = customer.getId(); notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, customerId, savedAsset, - actionType, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, user, + actionType, edgeTypeByActionType(actionType), user, true, customerId.toString(), customer.getName()); return savedAsset; diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java index fad0feea51..30b03ead3a 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java @@ -16,6 +16,7 @@ package org.thingsboard.server.controller; import lombok.extern.slf4j.Slf4j; +import org.mockito.ArgumentMatcher; import org.mockito.Mockito; import org.springframework.boot.test.mock.mockito.SpyBean; import org.thingsboard.server.cluster.TbClusterService; @@ -33,6 +34,7 @@ import org.thingsboard.server.dao.audit.AuditLogService; import org.thingsboard.server.dao.model.ModelConstants; import java.util.Locale; +import java.util.Objects; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -50,9 +52,10 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { protected void testNotifyEntityAllOneTime(HasName entity, EntityId entityId, EntityId originatorId, TenantId tenantId, CustomerId customerId, UserId userId, String userName, ActionType actionType, Object... additionalInfo) { - testSendNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, 1); - testLogEntityActionOneTime(entity, originatorId, tenantId, customerId, userId, userName, actionType, additionalInfo); - testPushMsgToRuleEngineTime(originatorId, tenantId, 1); + int cntTime = 1; + testSendNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, cntTime); + logEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); + testPushMsgToRuleEngineTime(originatorId, tenantId, cntTime); Mockito.reset(tbClusterService, auditLogService); } @@ -67,20 +70,23 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { protected void testNotifyEntityOneTimeMsgToEdgeServiceNever(HasName entity, EntityId entityId, EntityId originatorId, TenantId tenantId, CustomerId customerId, UserId userId, String userName, ActionType actionType, Object... additionalInfo) { + int cntTime = 1; testNotificationMsgToEdgeServiceNever(entityId); - testLogEntityActionOneTime(entity, originatorId, tenantId, customerId, userId, userName, actionType, additionalInfo); - testPushMsgToRuleEngineTime(originatorId, tenantId, 1); + logEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); + testPushMsgToRuleEngineTime(originatorId, tenantId, cntTime); Mockito.reset(tbClusterService, auditLogService); } - protected void testNotifyEntityManyTimeMsgToEdgeServiceNever(HasName entity, HasName originator, - TenantId tenantId, CustomerId customerId, UserId userId, String userName, - ActionType actionType, int cntTime, Object... additionalInfo) { + protected void testNotifyManyEntityManyTimeMsgToEdgeServiceNever(HasName entity, HasName originator, + TenantId tenantId, CustomerId customerId, UserId userId, String userName, + ActionType actionType, int cntTime, Object... additionalInfo) { EntityId entityId = createEntityId_NULL_UUID(entity); EntityId originatorId = createEntityId_NULL_UUID(originator); testNotificationMsgToEdgeServiceNever(entityId); - testLogEntityActionManyTime(entity,originatorId, tenantId, customerId, - userId, userName, actionType, cntTime, additionalInfo); + ArgumentMatcher matcherEntityClassEquals = argument -> argument.getClass().equals(entity.getClass()); + ArgumentMatcher matcherOriginatorId = argument -> argument.getClass().equals(originatorId.getClass()); + logEntityActionAdditionalInfo(matcherEntityClassEquals, matcherOriginatorId, tenantId, customerId, userId, userName, actionType, cntTime, + additionalInfo); testPushMsgToRuleEngineTime(originatorId, tenantId, cntTime); Mockito.reset(tbClusterService, auditLogService); } @@ -88,37 +94,37 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { protected void testNotifyEntityBroadcastEntityStateChangeEventOneTimeMsgToEdgeServiceNever(HasName entity, EntityId entityId, EntityId originatorId, TenantId tenantId, CustomerId customerId, UserId userId, String userName, ActionType actionType, Object... additionalInfo) { + int cntTime = 1; testNotificationMsgToEdgeServiceNever(entityId); - testLogEntityActionOneTime(entity, originatorId, tenantId, customerId, userId, userName, actionType, additionalInfo); - testPushMsgToRuleEngineTime(originatorId, tenantId, 1); - testBroadcastEntityStateChangeEventTime(entityId, tenantId, 1); + logEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); + testPushMsgToRuleEngineTime(originatorId, tenantId, cntTime); + testBroadcastEntityStateChangeEventTime(entityId, tenantId, cntTime); Mockito.reset(tbClusterService, auditLogService); } - protected void testNotifyEntityOneTimeError(HasName entity, TenantId tenantId, - UserId userId, String userName, ActionType actionType, Exception exp, - Object... additionalInfo) { + protected void testNotifyEntityEqualsOneTimeError(HasName entity, TenantId tenantId, + UserId userId, String userName, ActionType actionType, Exception exp, + Object... additionalInfo) { CustomerId customer_NULL_UUID = (CustomerId) EntityIdFactory.getByTypeAndUuid(EntityType.CUSTOMER, ModelConstants.NULL_UUID); - EntityId entity_NULL_UUID = createEntityId_NULL_UUID(entity); - testNotificationMsgToEdgeServiceNever(entity_NULL_UUID); - if (additionalInfo.length > 0) { - Mockito.verify(auditLogService, times(1)) - .logEntityAction(Mockito.eq(tenantId), - Mockito.eq(customer_NULL_UUID), Mockito.eq(userId), Mockito.eq(userName), - Mockito.eq(entity_NULL_UUID), Mockito.any(entity.getClass()), Mockito.eq(actionType), - Mockito.argThat(argument -> - argument.getMessage().contains(exp.getMessage())), - Mockito.eq(additionalInfo) - ); - } else { - Mockito.verify(auditLogService, times(1)) - .logEntityAction(Mockito.eq(tenantId), - Mockito.eq(customer_NULL_UUID), Mockito.eq(userId), Mockito.eq(userName), - Mockito.eq(entity_NULL_UUID), Mockito.any(entity.getClass()), Mockito.eq(actionType), - Mockito.argThat((argument -> argument.getMessage().contains(exp.getMessage()) & argument.getClass().equals(exp.getClass()))) - ); - } - testPushMsgToRuleEngineNever(entity_NULL_UUID); + EntityId entity_originator_NULL_UUID = createEntityId_NULL_UUID(entity); + testNotificationMsgToEdgeServiceNever(entity_originator_NULL_UUID); + ArgumentMatcher matcherEntityEquals = argument -> argument.getClass().equals(entity.getClass()); + ArgumentMatcher matcherError = argument -> argument.getMessage().contains(exp.getMessage()); + logEntityActionErrorAdditionalInfo(matcherEntityEquals, entity_originator_NULL_UUID, tenantId, customer_NULL_UUID, userId, + userName, actionType, 1, matcherError, additionalInfo); + testPushMsgToRuleEngineNever(entity_originator_NULL_UUID); + } + + protected void testNotifyEntityIsNullOneTimeError(HasName entity, TenantId tenantId, + UserId userId, String userName, ActionType actionType, Exception exp, + Object... additionalInfo) { + CustomerId customer_NULL_UUID = (CustomerId) EntityIdFactory.getByTypeAndUuid(EntityType.CUSTOMER, ModelConstants.NULL_UUID); + EntityId entity_originator_NULL_UUID = createEntityId_NULL_UUID(entity); + testNotificationMsgToEdgeServiceNever(entity_originator_NULL_UUID); + ArgumentMatcher matcherEntityIsNull = Objects::isNull; + ArgumentMatcher matcherError = argument -> argument.getMessage().contains(exp.getMessage()) & argument.getClass().equals(exp.getClass()); + logEntityActionErrorAdditionalInfo(matcherEntityIsNull, entity_originator_NULL_UUID, tenantId, customer_NULL_UUID, userId, userName, actionType, 1, matcherError, additionalInfo); + testPushMsgToRuleEngineNever(entity_originator_NULL_UUID); } protected void testNotifyEntityNever(EntityId entityId, HasName entity) { @@ -145,47 +151,16 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { Mockito.any(entityId.getClass()), Mockito.any(), Mockito.any()); } - private void testLogEntityActionOneTime(HasName entity, EntityId originatorId, TenantId tenantId, CustomerId customerId, - UserId userId, String userName, ActionType actionType, Object... additionalInfo) { - if (additionalInfo.length == 0) { - Mockito.verify(auditLogService, times(1)).logEntityAction(Mockito.eq(tenantId), Mockito.eq(customerId), - Mockito.eq(userId), Mockito.eq(userName), Mockito.eq(originatorId), - Mockito.eq(entity), Mockito.eq(actionType), Mockito.isNull()); - } else { - String additionalInfoStr = extractParameter(String.class, 0, additionalInfo); - Mockito.verify(auditLogService, times(1)).logEntityAction(Mockito.eq(tenantId), Mockito.eq(customerId), - Mockito.eq(userId), Mockito.eq(userName), Mockito.eq(originatorId), - Mockito.eq(entity), Mockito.eq(actionType), Mockito.isNull(), Mockito.eq(additionalInfoStr)); - } - } - - private void testLogEntityActionManyTime(HasName entity, EntityId originatorId, TenantId tenantId, CustomerId customerId, - UserId userId, String userName, ActionType actionType, int cntTime, Object... additionalInfo) { - if (additionalInfo.length == 0) { - Mockito.verify(auditLogService, times(cntTime)).logEntityAction(Mockito.eq(tenantId), Mockito.eq(customerId), - Mockito.eq(userId), Mockito.eq(userName), Mockito.any(originatorId.getClass()), - Mockito.any(entity.getClass()), Mockito.eq(actionType), Mockito.isNull()); - } else { - String additionalInfoStr = extractParameter(String.class, 0, additionalInfo); - Mockito.verify(auditLogService, times(cntTime)).logEntityAction(Mockito.eq(tenantId), Mockito.eq(customerId), - Mockito.eq(userId), Mockito.eq(userName), Mockito.any(originatorId.getClass()), - Mockito.any(entity.getClass()), Mockito.eq(actionType), Mockito.isNull(), Mockito.eq(additionalInfoStr)); - } - } - private void testPushMsgToRuleEngineTime(EntityId originatorId, TenantId tenantId, int cntTime) { - if (cntTime ==1) { - Mockito.verify(tbClusterService, times(cntTime)).pushMsgToRuleEngine(Mockito.eq(tenantId), - Mockito.eq(originatorId), Mockito.any(TbMsg.class), Mockito.isNull()); - } else { - Mockito.verify(tbClusterService, times(cntTime)).pushMsgToRuleEngine(Mockito.eq(tenantId), - Mockito.any(originatorId.getClass()), Mockito.any(TbMsg.class), Mockito.isNull()); - } + ArgumentMatcher matcherOriginatorId = cntTime == 1 ? argument -> argument.equals(originatorId) : + argument -> argument.getClass().equals(originatorId.getClass()); + Mockito.verify(tbClusterService, times(cntTime)).pushMsgToRuleEngine(Mockito.eq(tenantId), + Mockito.argThat(matcherOriginatorId), Mockito.any(TbMsg.class), Mockito.isNull()); } private void testSendNotificationMsgToEdgeServiceTime(EntityId entityId, TenantId tenantId, ActionType actionType, int cntTime) { Mockito.verify(tbClusterService, times(cntTime)).sendNotificationMsgToEdgeService(Mockito.eq(tenantId), - Mockito.isNull(), Mockito.eq(entityId), Mockito.isNull(), Mockito.isNull(), + Mockito.any(), Mockito.eq(entityId), Mockito.any(), Mockito.isNull(), Mockito.eq(edgeTypeByActionType(actionType))); } @@ -194,6 +169,112 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { Mockito.any(entityId.getClass()), Mockito.any(ComponentLifecycleEvent.class)); } + private void logEntityAction(HasName entity, EntityId originatorId, TenantId tenantId, + CustomerId customerId, UserId userId, String userName, + ActionType actionType, int cntTime, Object... additionalInfo) { + ArgumentMatcher matcherEntityEquals = argument -> argument.equals(entity); + ArgumentMatcher matcherOriginatorId = argument -> argument.equals(originatorId); + logEntityActionAdditionalInfo(matcherEntityEquals, matcherOriginatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); + } + + private void logEntityActionAdditionalInfo(ArgumentMatcher matcherEntity, ArgumentMatcher matcherOriginatorId, TenantId tenantId, + CustomerId customerId, UserId userId, String userName, + ActionType actionType, int cntTime, Object... additionalInfo) { + switch (additionalInfo.length) { + case 1: + Mockito.verify(auditLogService, times(cntTime)) + .logEntityAction(Mockito.eq(tenantId), + Mockito.eq(customerId), + Mockito.eq(userId), + Mockito.eq(userName), + Mockito.argThat(matcherOriginatorId), + Mockito.argThat(matcherEntity), + Mockito.eq(actionType), + Mockito.isNull(), + Mockito.eq(extractParameter(String.class, 0, additionalInfo))); + break; + case 2: + Mockito.verify(auditLogService, times(cntTime)) + .logEntityAction(Mockito.eq(tenantId), + Mockito.eq(customerId), + Mockito.eq(userId), + Mockito.eq(userName), + Mockito.argThat(matcherOriginatorId), + Mockito.argThat(matcherEntity), + Mockito.eq(actionType), + Mockito.isNull(), + Mockito.eq(extractParameter(String.class, 0, additionalInfo)), + Mockito.eq(extractParameter(String.class, 1, additionalInfo))); + break; + case 3: + Mockito.verify(auditLogService, times(cntTime)) + .logEntityAction(Mockito.eq(tenantId), + Mockito.eq(customerId), + Mockito.eq(userId), + Mockito.eq(userName), + Mockito.argThat(matcherOriginatorId), + Mockito.argThat(matcherEntity), + Mockito.eq(actionType), + Mockito.isNull(), + Mockito.eq(extractParameter(String.class, 0, additionalInfo)), + Mockito.eq(extractParameter(String.class, 1, additionalInfo)), + Mockito.eq(extractParameter(String.class, 2, additionalInfo))); + break; + default: + Mockito.verify(auditLogService, times(cntTime)) + .logEntityAction(Mockito.eq(tenantId), + Mockito.eq(customerId), + Mockito.eq(userId), + Mockito.eq(userName), + Mockito.argThat(matcherOriginatorId), + Mockito.argThat(matcherEntity), + Mockito.eq(actionType), + Mockito.isNull()); + } + } + + private void logEntityActionErrorAdditionalInfo(ArgumentMatcher matcherEntity, EntityId originatorId, TenantId tenantId, + CustomerId customerId, UserId userId, String userName, + ActionType actionType, int cntTime, ArgumentMatcher matcherError, Object... additionalInfo) { + switch (additionalInfo.length) { + case 1: + Mockito.verify(auditLogService, times(cntTime)) + .logEntityAction(Mockito.eq(tenantId), + Mockito.eq(customerId), + Mockito.eq(userId), + Mockito.eq(userName), + Mockito.eq(originatorId), + Mockito.argThat(matcherEntity), + Mockito.eq(actionType), + Mockito.argThat(matcherError), + Mockito.eq(extractParameter(String.class, 0, additionalInfo))); + break; + case 2: + Mockito.verify(auditLogService, times(cntTime)) + .logEntityAction(Mockito.eq(tenantId), + Mockito.eq(customerId), + Mockito.eq(userId), + Mockito.eq(userName), + Mockito.eq(originatorId), + Mockito.argThat(matcherEntity), + Mockito.eq(actionType), + Mockito.argThat(matcherError), + Mockito.eq(extractParameter(String.class, 0, additionalInfo)), + Mockito.eq(extractParameter(String.class, 1, additionalInfo))); + break; + default: + Mockito.verify(auditLogService, times(cntTime)) + .logEntityAction(Mockito.eq(tenantId), + Mockito.eq(customerId), + Mockito.eq(userId), + Mockito.eq(userName), + Mockito.eq(originatorId), + Mockito.argThat(matcherEntity), + Mockito.eq(actionType), + Mockito.argThat(matcherError)); + } + } + private T extractParameter(Class clazz, int index, Object... additionalInfo) { T result = null; if (additionalInfo != null && additionalInfo.length > index) { diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java index 0861ab34c8..0f8f2d11be 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java @@ -22,17 +22,20 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.Mockito; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.service.stats.DefaultRuleEngineStatisticsService; @@ -83,8 +86,14 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { Asset asset = new Asset(); asset.setName("My asset"); asset.setType("default"); + + Mockito.reset(tbClusterService, auditLogService); + Asset savedAsset = doPost("/api/asset", asset, Asset.class); + testNotifyEntityOneTimeMsgToEdgeServiceNever(savedAsset, savedAsset.getId(), savedAsset.getId(), + savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED); + Assert.assertNotNull(savedAsset); Assert.assertNotNull(savedAsset.getId()); Assert.assertTrue(savedAsset.getCreatedTime() > 0); @@ -93,9 +102,14 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { Assert.assertEquals(NULL_UUID, savedAsset.getCustomerId().getId()); Assert.assertEquals(asset.getName(), savedAsset.getName()); + Mockito.reset(tbClusterService, auditLogService); + savedAsset.setName("My new asset"); doPost("/api/asset", savedAsset, Asset.class); + testNotifyEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(), + savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UPDATED); + Asset foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class); Assert.assertEquals(foundAsset.getName(), savedAsset.getName()); } @@ -105,13 +119,33 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { Asset asset = new Asset(); asset.setName(RandomStringUtils.randomAlphabetic(300)); asset.setType("default"); - doPost("/api/asset", asset).andExpect(statusReason(containsString("length of name must be equal or less than 255"))); + + Mockito.reset(tbClusterService, auditLogService); + + String msgError = "length of name must be equal or less than 255"; + doPost("/api/asset", asset).andExpect(statusReason(containsString(msgError))); + + + testNotifyEntityEqualsOneTimeError(asset, savedTenant.getId(), + tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); + Mockito.reset(tbClusterService, auditLogService); + asset.setName("Normal name"); asset.setType(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/asset", asset).andExpect(statusReason(containsString("length of type must be equal or less than 255"))); + msgError = "length of type must be equal or less than 255"; + doPost("/api/asset", asset).andExpect(statusReason(containsString(msgError))); + + testNotifyEntityEqualsOneTimeError(asset, savedTenant.getId(), + tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); + Mockito.reset(tbClusterService, auditLogService); + asset.setType("default"); asset.setLabel(RandomStringUtils.randomAlphabetic(300)); - doPost("/api/asset", asset).andExpect(statusReason(containsString("length of label must be equal or less than 255"))); + msgError = "length of label must be equal or less than 255"; + doPost("/api/asset", asset).andExpect(statusReason(containsString(msgError))); + + testNotifyEntityEqualsOneTimeError(asset, savedTenant.getId(), + tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); } @Test @@ -122,7 +156,13 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { Asset savedAsset = doPost("/api/asset", asset, Asset.class); loginDifferentTenant(); + + Mockito.reset(tbClusterService, auditLogService); + doPost("/api/asset", savedAsset, Asset.class, status().isForbidden()); + + testNotifyEntityNever(savedAsset.getId(), savedAsset); + deleteDifferentTenant(); } @@ -140,12 +180,21 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { @Test public void testFindAssetTypesByTenantId() throws Exception { List assets = new ArrayList<>(); - for (int i = 0; i < 3; i++) { + + Mockito.reset(tbClusterService, auditLogService); + + int cntTime = 3; + for (int i = 0; i < cntTime; i++) { Asset asset = new Asset(); asset.setName("My asset B" + i); asset.setType("typeB"); assets.add(doPost("/api/asset", asset, Asset.class)); } + + testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Asset(), new Asset(), + savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), + ActionType.ADDED, cntTime); + for (int i = 0; i < 7; i++) { Asset asset = new Asset(); asset.setName("My asset C" + i); @@ -176,9 +225,15 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { asset.setType("default"); Asset savedAsset = doPost("/api/asset", asset, Asset.class); + Mockito.reset(tbClusterService, auditLogService); + doDelete("/api/asset/" + savedAsset.getId().getId().toString()) .andExpect(status().isOk()); + testNotifyEntityOneTimeMsgToEdgeServiceNever(savedAsset, savedAsset.getId(), savedAsset.getId(), + savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), + ActionType.DELETED, savedAsset.getId().getId().toString()); + doGet("/api/asset/" + savedAsset.getId().getId().toString()) .andExpect(status().isNotFound()); } @@ -202,9 +257,16 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { view.setType("default"); EntityView savedView = doPost("/api/entityView", view, EntityView.class); + Mockito.reset(tbClusterService, auditLogService); + doDelete("/api/asset/" + savedAsset1.getId().getId().toString()) .andExpect(status().isBadRequest()); + String msgError = "Can't delete asset that has entity views"; + + testNotifyEntityIsNullOneTimeError(savedAsset1, savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), + ActionType.DELETED, new DataValidationException(msgError), savedAsset1.getId().getId().toString()); + savedView.setEntityId(savedAsset2.getId()); doPost("/api/entityView", savedView, EntityView.class); @@ -220,18 +282,32 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { public void testSaveAssetWithEmptyType() throws Exception { Asset asset = new Asset(); asset.setName("My asset"); + + Mockito.reset(tbClusterService, auditLogService); + + String msgError = "Asset type should be specified"; doPost("/api/asset", asset) .andExpect(status().isBadRequest()) - .andExpect(statusReason(containsString("Asset type should be specified"))); + .andExpect(statusReason(containsString(msgError))); + + testNotifyEntityEqualsOneTimeError(asset, savedTenant.getId(), + tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); } @Test public void testSaveAssetWithEmptyName() throws Exception { Asset asset = new Asset(); asset.setType("default"); + + Mockito.reset(tbClusterService, auditLogService); + + String msgError = "Asset name should be specified"; doPost("/api/asset", asset) .andExpect(status().isBadRequest()) - .andExpect(statusReason(containsString("Asset name should be specified"))); + .andExpect(statusReason(containsString(msgError))); + + testNotifyEntityEqualsOneTimeError(asset, savedTenant.getId(), + tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); } @Test @@ -245,17 +321,29 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { customer.setTitle("My customer"); Customer savedCustomer = doPost("/api/customer", customer, Customer.class); + Mockito.reset(tbClusterService, auditLogService); + Asset assignedAsset = doPost("/api/customer/" + savedCustomer.getId().getId().toString() + "/asset/" + savedAsset.getId().getId().toString(), Asset.class); Assert.assertEquals(savedCustomer.getId(), assignedAsset.getCustomerId()); + testNotifyEntityAllOneTime(assignedAsset, assignedAsset.getId(), assignedAsset.getId(), + savedTenant.getId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), + ActionType.ASSIGNED_TO_CUSTOMER, savedCustomer.getId().toString(), savedCustomer.getTitle()); + Asset foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class); Assert.assertEquals(savedCustomer.getId(), foundAsset.getCustomerId()); + Mockito.reset(tbClusterService, auditLogService); + Asset unassignedAsset = doDelete("/api/customer/asset/" + savedAsset.getId().getId().toString(), Asset.class); Assert.assertEquals(ModelConstants.NULL_UUID, unassignedAsset.getCustomerId().getId()); + testNotifyEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(), + savedTenant.getId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), + ActionType.UNASSIGNED_FROM_CUSTOMER, savedCustomer.getId().toString(), savedCustomer.getTitle()); + foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class); Assert.assertEquals(ModelConstants.NULL_UUID, foundAsset.getCustomerId().getId()); } @@ -267,9 +355,14 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { asset.setType("default"); Asset savedAsset = doPost("/api/asset", asset, Asset.class); + Mockito.reset(tbClusterService, auditLogService); + + String msgError = "Asset name should be specified"; doPost("/api/customer/" + Uuids.timeBased().toString() + "/asset/" + savedAsset.getId().getId().toString()) .andExpect(status().isNotFound()); + + testNotifyEntityNever(asset.getId(), asset); } @Test @@ -301,10 +394,14 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { asset.setType("default"); Asset savedAsset = doPost("/api/asset", asset, Asset.class); + Mockito.reset(tbClusterService, auditLogService); + doPost("/api/customer/" + savedCustomer.getId().getId().toString() + "/asset/" + savedAsset.getId().getId().toString()) .andExpect(status().isForbidden()); + testNotifyEntityNever(savedAsset.getId(), savedAsset); + loginSysAdmin(); doDelete("/api/tenant/" + savedTenant2.getId().getId().toString()) @@ -314,7 +411,11 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { @Test public void testFindTenantAssets() throws Exception { List assets = new ArrayList<>(); - for (int i = 0; i < 178; i++) { + int cntEntity = 178; + + Mockito.reset(tbClusterService, auditLogService); + + for (int i = 0; i < cntEntity; i++) { Asset asset = new Asset(); asset.setName("Asset" + i); asset.setType("default"); @@ -332,6 +433,10 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { } } while (pageData.hasNext()); + testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Asset(), new Asset(), + savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), + ActionType.ADDED, cntEntity); + loadedAssets.removeIf(asset -> asset.getType().equals(DefaultRuleEngineStatisticsService.TB_SERVICE_QUEUE)); Collections.sort(assets, idComparator); @@ -731,17 +836,31 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { asset.setType("default"); Asset savedAsset = doPost("/api/asset", asset, Asset.class); + Mockito.reset(tbClusterService, auditLogService); + doPost("/api/edge/" + savedEdge.getId().getId().toString() + "/asset/" + savedAsset.getId().getId().toString(), Asset.class); + testNotifyEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(), + savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ASSIGNED_TO_EDGE, + savedAsset.getId().getId().toString(), savedEdge.getId().getId().toString(), edge.getName()); + + PageData pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/assets?", new TypeReference>() {}, new PageLink(100)); Assert.assertEquals(1, pageData.getData().size()); + Mockito.reset(tbClusterService, auditLogService); + doDelete("/api/edge/" + savedEdge.getId().getId().toString() + "/asset/" + savedAsset.getId().getId().toString(), Asset.class); + + testNotifyEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(), + savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), + ActionType.UNASSIGNED_FROM_EDGE, savedAsset.getId().getId().toString(), savedEdge.getId().getId().toString(), savedEdge.getName()); + pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/assets?", new TypeReference>() {}, new PageLink(100)); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java index cc4bc84b7b..1e2349985f 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java @@ -129,7 +129,8 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest String msgError = "length of title must be equal or less than 255"; doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); - testNotifyEntityOneTimeError(customer, savedTenant.getId(), + customer.setTenantId(savedTenant.getId()); + testNotifyEntityEqualsOneTimeError(customer,savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); Mockito.reset(tbClusterService, auditLogService); @@ -138,7 +139,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest msgError = "length of city must be equal or less than 255"; doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); - testNotifyEntityOneTimeError(customer, savedTenant.getId(), + testNotifyEntityEqualsOneTimeError(customer,savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); Mockito.reset(tbClusterService, auditLogService); @@ -147,7 +148,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest msgError = "length of country must be equal or less than 255"; doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); - testNotifyEntityOneTimeError(customer, savedTenant.getId(), + testNotifyEntityEqualsOneTimeError(customer,savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); Mockito.reset(tbClusterService, auditLogService); @@ -156,7 +157,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest msgError = "length of phone must be equal or less than 255"; doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); - testNotifyEntityOneTimeError(customer, savedTenant.getId(), + testNotifyEntityEqualsOneTimeError(customer,savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); Mockito.reset(tbClusterService, auditLogService); @@ -165,7 +166,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest msgError = "length of state must be equal or less than 255"; doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); - testNotifyEntityOneTimeError(customer, savedTenant.getId(), + testNotifyEntityEqualsOneTimeError(customer,savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); Mockito.reset(tbClusterService, auditLogService); @@ -174,7 +175,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest msgError = "length of zip or postal code must be equal or less than 255"; doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); - testNotifyEntityOneTimeError(customer, savedTenant.getId(), + testNotifyEntityEqualsOneTimeError(customer,savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); } @@ -248,7 +249,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString(msgError))); - testNotifyEntityOneTimeError(customer, savedTenant.getId(), + testNotifyEntityEqualsOneTimeError(customer,savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); } @@ -265,7 +266,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString(msgError))); - testNotifyEntityOneTimeError(customer, savedTenant.getId(), + testNotifyEntityEqualsOneTimeError(customer, savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); } @@ -273,12 +274,12 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest public void testFindCustomers() throws Exception { TenantId tenantId = savedTenant.getId(); - int cntTime = 135; + int cntEntity = 135; Mockito.reset(tbClusterService, auditLogService); - List> futures = new ArrayList<>(cntTime); - for (int i = 0; i < cntTime; i++) { + List> futures = new ArrayList<>(cntEntity); + for (int i = 0; i < cntEntity; i++) { Customer customer = new Customer(); customer.setTenantId(tenantId); customer.setTitle("Customer" + i); @@ -287,9 +288,9 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest } List customers = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS); - testNotifyEntityManyTimeMsgToEdgeServiceNever(new Customer(), new Customer(), + testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Customer(), new Customer(), tenantId, tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.ADDED, cntTime); + ActionType.ADDED, cntEntity); List loadedCustomers = new ArrayList<>(135); PageLink pageLink = new PageLink(23); From 27870e9c5019f985816416e136a5f90723dbe3eb Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Fri, 17 Jun 2022 19:09:25 +0300 Subject: [PATCH 18/26] Dockerfile optimization: --no-install-recommends ; rm -rf /var/lib/apt/lists/* ; apt-get purge -y --auto-remove --- msa/tb/docker-cassandra/Dockerfile | 6 ++++-- msa/tb/docker-postgres/Dockerfile | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/msa/tb/docker-cassandra/Dockerfile b/msa/tb/docker-cassandra/Dockerfile index 9d16d46ef5..f4d00a8d37 100644 --- a/msa/tb/docker-cassandra/Dockerfile +++ b/msa/tb/docker-cassandra/Dockerfile @@ -44,15 +44,17 @@ ENV CASSANDRA_LOG=/var/log/cassandra COPY logback.xml ${pkg.name}.conf start-db.sh stop-db.sh start-tb.sh upgrade-tb.sh install-tb.sh ${pkg.name}.deb /tmp/ RUN apt-get update \ - && apt-get install -y curl nmap procps gnupg2 \ + && apt-get install -y --no-install-recommends curl nmap procps gnupg2 \ && echo "deb http://apt.postgresql.org/pub/repos/apt/ $(. /etc/os-release && echo -n $VERSION_CODENAME)-pgdg main" | tee --append /etc/apt/sources.list.d/pgdg.list > /dev/null \ && curl -L https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \ && echo 'deb http://downloads.apache.org/cassandra/debian 40x main' | tee --append /etc/apt/sources.list.d/cassandra.list > /dev/null \ && curl -L https://downloads.apache.org/cassandra/KEYS | apt-key add - \ && apt-get update \ - && apt-get install -y cassandra cassandra-tools postgresql-12 \ + && apt-get install -y --no-install-recommends cassandra cassandra-tools postgresql-${PG_MAJOR} \ + && rm -rf /var/lib/apt/lists/* \ && update-rc.d cassandra disable \ && update-rc.d postgresql disable \ + && apt-get purge -y --auto-remove \ && sed -i.old '/ulimit/d' /etc/init.d/cassandra \ && chmod a+x /tmp/*.sh \ && mv /tmp/start-tb.sh /usr/bin \ diff --git a/msa/tb/docker-postgres/Dockerfile b/msa/tb/docker-postgres/Dockerfile index 5dfdba41bd..90616c2ff0 100644 --- a/msa/tb/docker-postgres/Dockerfile +++ b/msa/tb/docker-postgres/Dockerfile @@ -36,12 +36,14 @@ ENV PGLOG=/var/log/postgres COPY logback.xml ${pkg.name}.conf start-db.sh stop-db.sh start-tb.sh upgrade-tb.sh install-tb.sh ${pkg.name}.deb /tmp/ RUN apt-get update \ - && apt-get install -y curl gnupg2 \ + && apt-get install -y --no-install-recommends curl gnupg2 \ && echo "deb http://apt.postgresql.org/pub/repos/apt/ $(. /etc/os-release && echo -n $VERSION_CODENAME)-pgdg main" | tee --append /etc/apt/sources.list.d/pgdg.list > /dev/null \ && curl -L https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \ && apt-get update \ - && apt-get install -y postgresql-12 \ + && apt-get install -y --no-install-recommends postgresql-${PG_MAJOR} \ + && rm -rf /var/lib/apt/lists/* \ && update-rc.d postgresql disable \ + && apt-get purge -y --auto-remove \ && chmod a+x /tmp/*.sh \ && mv /tmp/start-tb.sh /usr/bin \ && mv /tmp/upgrade-tb.sh /usr/bin \ From f7fcc9a7b0e92444ddc5eba8d6f5b0a30945ec40 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 22 Jun 2022 06:58:55 +0300 Subject: [PATCH 19/26] refactoring: tests error add change to matcher --- .../controller/AbstractNotifyEntityTest.java | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java index 30b03ead3a..8e2335c042 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java @@ -109,7 +109,8 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { EntityId entity_originator_NULL_UUID = createEntityId_NULL_UUID(entity); testNotificationMsgToEdgeServiceNever(entity_originator_NULL_UUID); ArgumentMatcher matcherEntityEquals = argument -> argument.getClass().equals(entity.getClass()); - ArgumentMatcher matcherError = argument -> argument.getMessage().contains(exp.getMessage()); + ArgumentMatcher matcherError = argument -> argument.getMessage().contains(exp.getMessage()) + & argument.getClass().equals(exp.getClass()); logEntityActionErrorAdditionalInfo(matcherEntityEquals, entity_originator_NULL_UUID, tenantId, customer_NULL_UUID, userId, userName, actionType, 1, matcherError, additionalInfo); testPushMsgToRuleEngineNever(entity_originator_NULL_UUID); @@ -122,8 +123,10 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { EntityId entity_originator_NULL_UUID = createEntityId_NULL_UUID(entity); testNotificationMsgToEdgeServiceNever(entity_originator_NULL_UUID); ArgumentMatcher matcherEntityIsNull = Objects::isNull; - ArgumentMatcher matcherError = argument -> argument.getMessage().contains(exp.getMessage()) & argument.getClass().equals(exp.getClass()); - logEntityActionErrorAdditionalInfo(matcherEntityIsNull, entity_originator_NULL_UUID, tenantId, customer_NULL_UUID, userId, userName, actionType, 1, matcherError, additionalInfo); + ArgumentMatcher matcherError = argument -> argument.getMessage().contains(exp.getMessage()) & + argument.getClass().equals(exp.getClass()); + logEntityActionErrorAdditionalInfo(matcherEntityIsNull, entity_originator_NULL_UUID, tenantId, customer_NULL_UUID, + userId, userName, actionType, 1, matcherError, additionalInfo); testPushMsgToRuleEngineNever(entity_originator_NULL_UUID); } @@ -174,11 +177,12 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { ActionType actionType, int cntTime, Object... additionalInfo) { ArgumentMatcher matcherEntityEquals = argument -> argument.equals(entity); ArgumentMatcher matcherOriginatorId = argument -> argument.equals(originatorId); - logEntityActionAdditionalInfo(matcherEntityEquals, matcherOriginatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); + logEntityActionAdditionalInfo(matcherEntityEquals, matcherOriginatorId, tenantId, customerId, userId, userName, + actionType, cntTime, additionalInfo); } - private void logEntityActionAdditionalInfo(ArgumentMatcher matcherEntity, ArgumentMatcher matcherOriginatorId, TenantId tenantId, - CustomerId customerId, UserId userId, String userName, + private void logEntityActionAdditionalInfo(ArgumentMatcher matcherEntity, ArgumentMatcher matcherOriginatorId, + TenantId tenantId, CustomerId customerId, UserId userId, String userName, ActionType actionType, int cntTime, Object... additionalInfo) { switch (additionalInfo.length) { case 1: @@ -234,8 +238,8 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { } private void logEntityActionErrorAdditionalInfo(ArgumentMatcher matcherEntity, EntityId originatorId, TenantId tenantId, - CustomerId customerId, UserId userId, String userName, - ActionType actionType, int cntTime, ArgumentMatcher matcherError, Object... additionalInfo) { + CustomerId customerId, UserId userId, String userName, ActionType actionType, + int cntTime, ArgumentMatcher matcherError, Object... additionalInfo) { switch (additionalInfo.length) { case 1: Mockito.verify(auditLogService, times(cntTime)) @@ -261,6 +265,19 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { Mockito.argThat(matcherError), Mockito.eq(extractParameter(String.class, 0, additionalInfo)), Mockito.eq(extractParameter(String.class, 1, additionalInfo))); + case 3: + Mockito.verify(auditLogService, times(cntTime)) + .logEntityAction(Mockito.eq(tenantId), + Mockito.eq(customerId), + Mockito.eq(userId), + Mockito.eq(userName), + Mockito.eq(originatorId), + Mockito.argThat(matcherEntity), + Mockito.eq(actionType), + Mockito.argThat(matcherError), + Mockito.eq(extractParameter(String.class, 0, additionalInfo)), + Mockito.eq(extractParameter(String.class, 1, additionalInfo)), + Mockito.eq(extractParameter(String.class, 3, additionalInfo))); break; default: Mockito.verify(auditLogService, times(cntTime)) From 1f945a695b8d482a989206e60f0160cec37e509e Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 22 Jun 2022 07:08:24 +0300 Subject: [PATCH 20/26] refactoring: tests extract line --- .../server/controller/AbstractNotifyEntityTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java index 8e2335c042..5962d46a9a 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java @@ -68,8 +68,8 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { } protected void testNotifyEntityOneTimeMsgToEdgeServiceNever(HasName entity, EntityId entityId, EntityId originatorId, - TenantId tenantId, CustomerId customerId, UserId userId, String userName, - ActionType actionType, Object... additionalInfo) { + TenantId tenantId, CustomerId customerId, UserId userId, + String userName, ActionType actionType, Object... additionalInfo) { int cntTime = 1; testNotificationMsgToEdgeServiceNever(entityId); logEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); From f84f903f954dda31a3e295c00a8ee1c53a858f38 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 22 Jun 2022 07:53:37 +0300 Subject: [PATCH 21/26] refactoring: tests change type: from TransactionAwareCacheDecorator to CaffeineCache --- .../org/thingsboard/server/cache/CacheSpecsMapTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/cache/src/test/java/org/thingsboard/server/cache/CacheSpecsMapTest.java b/common/cache/src/test/java/org/thingsboard/server/cache/CacheSpecsMapTest.java index 7e65d6a230..2d7d64e0fd 100644 --- a/common/cache/src/test/java/org/thingsboard/server/cache/CacheSpecsMapTest.java +++ b/common/cache/src/test/java/org/thingsboard/server/cache/CacheSpecsMapTest.java @@ -21,7 +21,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cache.CacheManager; -import org.springframework.cache.transaction.TransactionAwareCacheDecorator; +import org.springframework.cache.caffeine.CaffeineCache; import org.springframework.cache.transaction.TransactionAwareCacheManagerProxy; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; @@ -51,8 +51,8 @@ public class CacheSpecsMapTest { @Test public void givenCacheConfig_whenCacheManagerReady_thenVerifyExistedCachesWithTransactionAwareCacheDecorator() { - assertThat(cacheManager.getCache("relations")).isInstanceOf(TransactionAwareCacheDecorator.class); - assertThat(cacheManager.getCache("devices")).isInstanceOf(TransactionAwareCacheDecorator.class); + assertThat(cacheManager.getCache("relations")).isInstanceOf(CaffeineCache.class); + assertThat(cacheManager.getCache("devices")).isInstanceOf(CaffeineCache.class); } @Test From a977e71b8799dfda920f0a0eb7efae3a82efaffd Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 22 Jun 2022 08:08:35 +0300 Subject: [PATCH 22/26] refactoring: tests change type: from TransactionAwareCacheManagerProxy to SimpleCacheManager --- .../java/org/thingsboard/server/cache/CacheSpecsMapTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/cache/src/test/java/org/thingsboard/server/cache/CacheSpecsMapTest.java b/common/cache/src/test/java/org/thingsboard/server/cache/CacheSpecsMapTest.java index 2d7d64e0fd..b99c2f9737 100644 --- a/common/cache/src/test/java/org/thingsboard/server/cache/CacheSpecsMapTest.java +++ b/common/cache/src/test/java/org/thingsboard/server/cache/CacheSpecsMapTest.java @@ -22,7 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cache.CacheManager; import org.springframework.cache.caffeine.CaffeineCache; -import org.springframework.cache.transaction.TransactionAwareCacheManagerProxy; +import org.springframework.cache.support.SimpleCacheManager; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -46,7 +46,7 @@ public class CacheSpecsMapTest { @Test public void verifyTransactionAwareCacheManagerProxy() { - assertThat(cacheManager).isInstanceOf(TransactionAwareCacheManagerProxy.class); + assertThat(cacheManager).isInstanceOf(SimpleCacheManager.class); } @Test From f4befe9ce1336145f5f2da904137ec00ea99be73 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 22 Jun 2022 10:38:16 +0300 Subject: [PATCH 23/26] refactoring: tests change change name method --- .../server/controller/AbstractNotifyEntityTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java index 5962d46a9a..533e1cced5 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java @@ -54,7 +54,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { ActionType actionType, Object... additionalInfo) { int cntTime = 1; testSendNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, cntTime); - logEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); + testLogEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); testPushMsgToRuleEngineTime(originatorId, tenantId, cntTime); Mockito.reset(tbClusterService, auditLogService); } @@ -72,7 +72,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { String userName, ActionType actionType, Object... additionalInfo) { int cntTime = 1; testNotificationMsgToEdgeServiceNever(entityId); - logEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); + testLogEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); testPushMsgToRuleEngineTime(originatorId, tenantId, cntTime); Mockito.reset(tbClusterService, auditLogService); } @@ -96,7 +96,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { ActionType actionType, Object... additionalInfo) { int cntTime = 1; testNotificationMsgToEdgeServiceNever(entityId); - logEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); + testLogEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); testPushMsgToRuleEngineTime(originatorId, tenantId, cntTime); testBroadcastEntityStateChangeEventTime(entityId, tenantId, cntTime); Mockito.reset(tbClusterService, auditLogService); @@ -172,9 +172,9 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { Mockito.any(entityId.getClass()), Mockito.any(ComponentLifecycleEvent.class)); } - private void logEntityAction(HasName entity, EntityId originatorId, TenantId tenantId, - CustomerId customerId, UserId userId, String userName, - ActionType actionType, int cntTime, Object... additionalInfo) { + private void testLogEntityAction(HasName entity, EntityId originatorId, TenantId tenantId, + CustomerId customerId, UserId userId, String userName, + ActionType actionType, int cntTime, Object... additionalInfo) { ArgumentMatcher matcherEntityEquals = argument -> argument.equals(entity); ArgumentMatcher matcherOriginatorId = argument -> argument.equals(originatorId); logEntityActionAdditionalInfo(matcherEntityEquals, matcherOriginatorId, tenantId, customerId, userId, userName, From dbd509ed0cb0bf271909c0ae7ada8b5c5b3b11c4 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 22 Jun 2022 11:09:55 +0300 Subject: [PATCH 24/26] refactoring: tests change change name method2 --- .../controller/AbstractNotifyEntityTest.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java index 533e1cced5..f2592aa159 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java @@ -85,7 +85,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { testNotificationMsgToEdgeServiceNever(entityId); ArgumentMatcher matcherEntityClassEquals = argument -> argument.getClass().equals(entity.getClass()); ArgumentMatcher matcherOriginatorId = argument -> argument.getClass().equals(originatorId.getClass()); - logEntityActionAdditionalInfo(matcherEntityClassEquals, matcherOriginatorId, tenantId, customerId, userId, userName, actionType, cntTime, + testLogEntityActionAdditionalInfo(matcherEntityClassEquals, matcherOriginatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); testPushMsgToRuleEngineTime(originatorId, tenantId, cntTime); Mockito.reset(tbClusterService, auditLogService); @@ -111,7 +111,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { ArgumentMatcher matcherEntityEquals = argument -> argument.getClass().equals(entity.getClass()); ArgumentMatcher matcherError = argument -> argument.getMessage().contains(exp.getMessage()) & argument.getClass().equals(exp.getClass()); - logEntityActionErrorAdditionalInfo(matcherEntityEquals, entity_originator_NULL_UUID, tenantId, customer_NULL_UUID, userId, + testLogEntityActionErrorAdditionalInfo(matcherEntityEquals, entity_originator_NULL_UUID, tenantId, customer_NULL_UUID, userId, userName, actionType, 1, matcherError, additionalInfo); testPushMsgToRuleEngineNever(entity_originator_NULL_UUID); } @@ -125,7 +125,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { ArgumentMatcher matcherEntityIsNull = Objects::isNull; ArgumentMatcher matcherError = argument -> argument.getMessage().contains(exp.getMessage()) & argument.getClass().equals(exp.getClass()); - logEntityActionErrorAdditionalInfo(matcherEntityIsNull, entity_originator_NULL_UUID, tenantId, customer_NULL_UUID, + testLogEntityActionErrorAdditionalInfo(matcherEntityIsNull, entity_originator_NULL_UUID, tenantId, customer_NULL_UUID, userId, userName, actionType, 1, matcherError, additionalInfo); testPushMsgToRuleEngineNever(entity_originator_NULL_UUID); } @@ -177,13 +177,13 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { ActionType actionType, int cntTime, Object... additionalInfo) { ArgumentMatcher matcherEntityEquals = argument -> argument.equals(entity); ArgumentMatcher matcherOriginatorId = argument -> argument.equals(originatorId); - logEntityActionAdditionalInfo(matcherEntityEquals, matcherOriginatorId, tenantId, customerId, userId, userName, + testLogEntityActionAdditionalInfo(matcherEntityEquals, matcherOriginatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); } - private void logEntityActionAdditionalInfo(ArgumentMatcher matcherEntity, ArgumentMatcher matcherOriginatorId, - TenantId tenantId, CustomerId customerId, UserId userId, String userName, - ActionType actionType, int cntTime, Object... additionalInfo) { + private void testLogEntityActionAdditionalInfo(ArgumentMatcher matcherEntity, ArgumentMatcher matcherOriginatorId, + TenantId tenantId, CustomerId customerId, UserId userId, String userName, + ActionType actionType, int cntTime, Object... additionalInfo) { switch (additionalInfo.length) { case 1: Mockito.verify(auditLogService, times(cntTime)) @@ -237,9 +237,9 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { } } - private void logEntityActionErrorAdditionalInfo(ArgumentMatcher matcherEntity, EntityId originatorId, TenantId tenantId, - CustomerId customerId, UserId userId, String userName, ActionType actionType, - int cntTime, ArgumentMatcher matcherError, Object... additionalInfo) { + private void testLogEntityActionErrorAdditionalInfo(ArgumentMatcher matcherEntity, EntityId originatorId, TenantId tenantId, + CustomerId customerId, UserId userId, String userName, ActionType actionType, + int cntTime, ArgumentMatcher matcherError, Object... additionalInfo) { switch (additionalInfo.length) { case 1: Mockito.verify(auditLogService, times(cntTime)) From 1d08e319bc4136d2c920aa9dfe3479f73ed1e1b4 Mon Sep 17 00:00:00 2001 From: devaskim Date: Wed, 22 Jun 2022 14:53:43 +0500 Subject: [PATCH 25/26] Add latest value to widget's legend. --- ui-ngx/src/app/core/api/widget-subscription.ts | 15 ++++++++++++++- .../widget/legend-config.component.html | 3 +++ .../components/widget/legend-config.component.ts | 6 ++++-- .../home/components/widget/legend.component.html | 8 ++++++++ .../home/components/widget/legend.component.ts | 3 ++- ui-ngx/src/app/shared/models/widget.models.ts | 5 ++++- .../src/assets/locale/locale.constant-en_US.json | 2 ++ 7 files changed, 37 insertions(+), 5 deletions(-) diff --git a/ui-ngx/src/app/core/api/widget-subscription.ts b/ui-ngx/src/app/core/api/widget-subscription.ts index 8cbcd19918..63dbe27739 100644 --- a/ui-ngx/src/app/core/api/widget-subscription.ts +++ b/ui-ngx/src/app/core/api/widget-subscription.ts @@ -269,7 +269,8 @@ export class WidgetSubscription implements IWidgetSubscription { (this.legendConfig.showMin === true || this.legendConfig.showMax === true || this.legendConfig.showAvg === true || - this.legendConfig.showTotal === true); + this.legendConfig.showTotal === true || + this.legendConfig.showLatest === true); this.initDataSubscription().subscribe(() => { subscriptionSubject.next(this); subscriptionSubject.complete(); @@ -1283,6 +1284,7 @@ export class WidgetSubscription implements IWidgetSubscription { max: null, avg: null, total: null, + latest: null, hidden: false }; this.legendData.data.push(legendKeyData); @@ -1439,6 +1441,9 @@ export class WidgetSubscription implements IWidgetSubscription { if (this.legendConfig.showTotal) { legendKeyData.total = this.ctx.widgetUtils.formatValue(calculateTotal(data), decimals, units); } + if (this.legendConfig.showLatest) { + legendKeyData.latest = this.ctx.widgetUtils.formatValue(calculateLatest(data), decimals, units); + } this.callbacks.legendDataUpdated(this, detectChanges !== false); } @@ -1511,3 +1516,11 @@ function calculateTotal(data: DataSet): number { return null; } } + +function calculateLatest(data: DataSet): number { + if (data.length > 0) { + return Number(data[data.length - 1][1]); + } else { + return null; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.html b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.html index bf7a27d4af..6e08046a22 100644 --- a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.html @@ -50,6 +50,9 @@ {{ 'legend.show-total' | translate }} + + {{ 'legend.show-latest' | translate }} + {{ 'legend.sort-legend' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts index 588e1237e7..16e32bc866 100644 --- a/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/legend-config.component.ts @@ -66,7 +66,8 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc showMin: [null, []], showMax: [null, []], showAvg: [null, []], - showTotal: [null, []] + showTotal: [null, []], + showLatest: [null, []] }); this.legendSettingsFormDirectionChanges$ = this.legendConfigForm.get('direction').valueChanges .subscribe((direction: LegendDirection) => { @@ -124,7 +125,8 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc showMin: isDefined(legendConfig.showMin) ? legendConfig.showMin : false, showMax: isDefined(legendConfig.showMax) ? legendConfig.showMax : false, showAvg: isDefined(legendConfig.showAvg) ? legendConfig.showAvg : false, - showTotal: isDefined(legendConfig.showTotal) ? legendConfig.showTotal : false + showTotal: isDefined(legendConfig.showTotal) ? legendConfig.showTotal : false, + showLatest: isDefined(legendConfig.showLatest) ? legendConfig.showLatest : false }, {emitEvent: false}); } this.onDirectionChanged(legendConfig.direction); diff --git a/ui-ngx/src/app/modules/home/components/widget/legend.component.html b/ui-ngx/src/app/modules/home/components/widget/legend.component.html index bbead89d6b..5b30af3aac 100644 --- a/ui-ngx/src/app/modules/home/components/widget/legend.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/legend.component.html @@ -24,6 +24,7 @@ {{ 'legend.max' | translate }} {{ 'legend.avg' | translate }} {{ 'legend.total' | translate }} + {{ 'legend.latest' | translate }} @@ -39,6 +40,7 @@ {{ legendData.data[legendKey.dataIndex].max }} {{ legendData.data[legendKey.dataIndex].avg }} {{ legendData.data[legendKey.dataIndex].total }} + {{ legendData.data[legendKey.dataIndex].latest }} @@ -76,5 +78,11 @@ {{ legendData.data[legendKey.dataIndex].total }} + + {{ 'legend.latest' | translate }} + + {{ legendData.data[legendKey.dataIndex].latest }} + + diff --git a/ui-ngx/src/app/modules/home/components/widget/legend.component.ts b/ui-ngx/src/app/modules/home/components/widget/legend.component.ts index 0074280732..4548621517 100644 --- a/ui-ngx/src/app/modules/home/components/widget/legend.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/legend.component.ts @@ -43,7 +43,8 @@ export class LegendComponent implements OnInit { this.displayHeader = this.legendConfig.showMin === true || this.legendConfig.showMax === true || this.legendConfig.showAvg === true || - this.legendConfig.showTotal === true; + this.legendConfig.showTotal === true || + this.legendConfig.showLatest === true; this.isHorizontal = this.legendConfig.position === LegendPosition.bottom || this.legendConfig.position === LegendPosition.top; diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index 703cffcaee..9450efbf9c 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -227,6 +227,7 @@ export interface LegendConfig { showMax: boolean; showAvg: boolean; showTotal: boolean; + showLatest: boolean; } export function defaultLegendConfig(wType: widgetType): LegendConfig { @@ -237,7 +238,8 @@ export function defaultLegendConfig(wType: widgetType): LegendConfig { showMin: false, showMax: false, showAvg: wType === widgetType.timeseries, - showTotal: false + showTotal: false, + showLatest: false }; } @@ -323,6 +325,7 @@ export interface LegendKeyData { max: string; avg: string; total: string; + latest: string; hidden: boolean; } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index aab433c992..e0e11702ef 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2341,11 +2341,13 @@ "show-min": "Show min value", "show-avg": "Show average value", "show-total": "Show total value", + "show-latest": "Show latest value", "settings": "Legend settings", "min": "min", "max": "max", "avg": "avg", "total": "total", + "latest": "latest", "comparison-time-ago": { "previousInterval": "(previous interval)", "customInterval": "(custom interval)", From f8609ef329e37cabb8ea6c80e39cb6a7a75d9beb Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 22 Jun 2022 13:09:20 +0300 Subject: [PATCH 26/26] reole conflicts2 --- .../server/controller/AbstractNotifyEntityTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java index f2592aa159..2c7f9ae51a 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java @@ -139,7 +139,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { } private void testNotificationMsgToEdgeServiceNever(EntityId entityId) { - Mockito.verify(tbClusterService, never()).sendNotificationMsgToEdgeService(Mockito.any(), + Mockito.verify(tbClusterService, never()).sendNotificationMsgToEdge(Mockito.any(), Mockito.any(), Mockito.any(entityId.getClass()), Mockito.any(), Mockito.any(), Mockito.any()); } @@ -162,7 +162,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { } private void testSendNotificationMsgToEdgeServiceTime(EntityId entityId, TenantId tenantId, ActionType actionType, int cntTime) { - Mockito.verify(tbClusterService, times(cntTime)).sendNotificationMsgToEdgeService(Mockito.eq(tenantId), + Mockito.verify(tbClusterService, times(cntTime)).sendNotificationMsgToEdge(Mockito.eq(tenantId), Mockito.any(), Mockito.eq(entityId), Mockito.any(), Mockito.isNull(), Mockito.eq(edgeTypeByActionType(actionType))); }