/** * Copyright © 2016-2017 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.server.actors; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.*; import com.google.common.util.concurrent.Futures; import org.thingsboard.server.actors.service.DefaultActorService; import org.thingsboard.server.common.data.id.*; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.plugin.ComponentDescriptor; import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.session.*; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.event.EventService; import org.thingsboard.server.gen.discovery.ServerInstanceProtos; import org.thingsboard.server.service.cluster.discovery.DiscoveryService; import org.thingsboard.server.service.cluster.discovery.ServerInstance; import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; import org.thingsboard.server.service.component.ComponentDiscoveryService; import org.thingsboard.server.common.transport.auth.DeviceAuthResult; import org.thingsboard.server.common.transport.auth.DeviceAuthService; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.plugin.PluginMetaData; import org.thingsboard.server.common.data.rule.RuleMetaData; import org.thingsboard.server.common.data.security.DeviceCredentialsFilter; import org.thingsboard.server.common.data.security.DeviceTokenCredentials; import org.thingsboard.server.common.msg.core.BasicTelemetryUploadRequest; import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.plugin.PluginService; import org.thingsboard.server.dao.rule.RuleService; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.extensions.core.plugin.telemetry.TelemetryStoragePlugin; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; import org.springframework.test.util.ReflectionTestUtils; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; public class DefaultActorServiceTest { private static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID); private static final String PLUGIN_ID = "9fb2e951-e298-4acb-913a-db69af8a15f4"; private static final String FILTERS_CONFIGURATION = "[{\"clazz\":\"org.thingsboard.server.extensions.core.filter.MsgTypeFilter\", \"name\":\"TelemetryFilter\", \"configuration\": {\"messageTypes\":[\"POST_TELEMETRY\",\"POST_ATTRIBUTES\",\"GET_ATTRIBUTES\"]}}]"; private static final String ACTION_CONFIGURATION = "{\"pluginToken\":\"telemetry\", \"clazz\":\"org.thingsboard.server.extensions.core.action.telemetry.TelemetryPluginAction\", \"name\":\"TelemetryMsgConverterAction\", \"configuration\":{}}"; private static final String PLUGIN_CONFIGURATION = "{}"; private DefaultActorService actorService; private ActorSystemContext actorContext; private PluginService pluginService; private RuleService ruleService; private DeviceAuthService deviceAuthService; private DeviceService deviceService; private TimeseriesService tsService; private TenantService tenantService; private ClusterRpcService rpcService; private DiscoveryService discoveryService; private ClusterRoutingService routingService; private AttributesService attributesService; private ComponentDiscoveryService componentService; private EventService eventService; private ServerInstance serverInstance; private RuleMetaData ruleMock; private PluginMetaData pluginMock; private RuleId ruleId = new RuleId(UUID.randomUUID()); private PluginId pluginId = new PluginId(UUID.fromString(PLUGIN_ID)); private TenantId tenantId = new TenantId(UUID.randomUUID()); @Before public void before() throws Exception { actorService = new DefaultActorService(); actorContext = new ActorSystemContext(); tenantService = mock(TenantService.class); pluginService = mock(PluginService.class); ruleService = mock(RuleService.class); deviceAuthService = mock(DeviceAuthService.class); deviceService = mock(DeviceService.class); tsService = mock(TimeseriesService.class); rpcService = mock(ClusterRpcService.class); discoveryService = mock(DiscoveryService.class); routingService = mock(ClusterRoutingService.class); attributesService = mock(AttributesService.class); componentService = mock(ComponentDiscoveryService.class); eventService = mock(EventService.class); serverInstance = new ServerInstance(ServerInstanceProtos.ServerInfo.newBuilder().setHost("localhost").setPort(8080).build()); ReflectionTestUtils.setField(actorService, "actorContext", actorContext); ReflectionTestUtils.setField(actorService, "rpcService", rpcService); ReflectionTestUtils.setField(actorService, "discoveryService", discoveryService); ReflectionTestUtils.setField(actorContext, "syncSessionTimeout", 10000L); ReflectionTestUtils.setField(actorContext, "pluginActorTerminationDelay", 10000L); ReflectionTestUtils.setField(actorContext, "pluginErrorPersistFrequency", 10000L); ReflectionTestUtils.setField(actorContext, "ruleActorTerminationDelay", 10000L); ReflectionTestUtils.setField(actorContext, "ruleErrorPersistFrequency", 10000L); ReflectionTestUtils.setField(actorContext, "pluginProcessingTimeout", 60000L); ReflectionTestUtils.setField(actorContext, "tenantService", tenantService); ReflectionTestUtils.setField(actorContext, "pluginService", pluginService); ReflectionTestUtils.setField(actorContext, "ruleService", ruleService); ReflectionTestUtils.setField(actorContext, "deviceAuthService", deviceAuthService); ReflectionTestUtils.setField(actorContext, "deviceService", deviceService); ReflectionTestUtils.setField(actorContext, "tsService", tsService); ReflectionTestUtils.setField(actorContext, "rpcService", rpcService); ReflectionTestUtils.setField(actorContext, "discoveryService", discoveryService); ReflectionTestUtils.setField(actorContext, "tsService", tsService); ReflectionTestUtils.setField(actorContext, "routingService", routingService); ReflectionTestUtils.setField(actorContext, "attributesService", attributesService); ReflectionTestUtils.setField(actorContext, "componentService", componentService); ReflectionTestUtils.setField(actorContext, "eventService", eventService); when(routingService.resolve(any())).thenReturn(Optional.empty()); when(discoveryService.getCurrentServer()).thenReturn(serverInstance); ruleMock = mock(RuleMetaData.class); when(ruleMock.getId()).thenReturn(ruleId); when(ruleMock.getState()).thenReturn(ComponentLifecycleState.ACTIVE); when(ruleMock.getPluginToken()).thenReturn("telemetry"); TextPageData<RuleMetaData> systemRules = new TextPageData<>(Collections.emptyList(), null, false); TextPageData<RuleMetaData> tenantRules = new TextPageData<>(Collections.singletonList(ruleMock), null, false); when(ruleService.findSystemRules(any())).thenReturn(systemRules); when(ruleService.findTenantRules(any(), any())).thenReturn(tenantRules); when(ruleService.findRuleById(ruleId)).thenReturn(ruleMock); pluginMock = mock(PluginMetaData.class); when(pluginMock.getTenantId()).thenReturn(SYSTEM_TENANT); when(pluginMock.getId()).thenReturn(pluginId); when(pluginMock.getState()).thenReturn(ComponentLifecycleState.ACTIVE); TextPageData<PluginMetaData> systemPlugins = new TextPageData<>(Collections.singletonList(pluginMock), null, false); TextPageData<PluginMetaData> tenantPlugins = new TextPageData<>(Collections.emptyList(), null, false); when(pluginService.findSystemPlugins(any())).thenReturn(systemPlugins); when(pluginService.findTenantPlugins(any(), any())).thenReturn(tenantPlugins); when(pluginService.findPluginByApiToken("telemetry")).thenReturn(pluginMock); when(pluginService.findPluginById(pluginId)).thenReturn(pluginMock); TextPageData<Tenant> tenants = new TextPageData<>(Collections.emptyList(), null, false); when(tenantService.findTenants(any())).thenReturn(tenants); } private void initActorSystem() { actorService.initActorSystem(); } @After public void after() { actorService.stopActorSystem(); } @Test public void testBasicPostWithSyncSession() throws Exception { SessionContext ssnCtx = mock(SessionContext.class); KvEntry entry1 = new StringDataEntry("key1", "value1"); KvEntry entry2 = new StringDataEntry("key2", "value2"); BasicTelemetryUploadRequest telemetry = new BasicTelemetryUploadRequest(); long ts = 42; telemetry.add(ts, entry1); telemetry.add(ts, entry2); BasicAdaptorToSessionActorMsg msg = new BasicAdaptorToSessionActorMsg(ssnCtx, telemetry); DeviceId deviceId = new DeviceId(UUID.randomUUID()); DeviceCredentialsFilter filter = new DeviceTokenCredentials("token1"); Device device = mock(Device.class); when(device.getId()).thenReturn(deviceId); when(device.getTenantId()).thenReturn(tenantId); when(ssnCtx.getSessionId()).thenReturn(new DummySessionID("session1")); when(ssnCtx.getSessionType()).thenReturn(SessionType.SYNC); when(deviceAuthService.process(filter)).thenReturn(DeviceAuthResult.of(deviceId)); when(deviceService.findDeviceById(deviceId)).thenReturn(device); ObjectMapper ruleMapper = new ObjectMapper(); when(ruleMock.getFilters()).thenReturn(ruleMapper.readTree(FILTERS_CONFIGURATION)); when(ruleMock.getAction()).thenReturn(ruleMapper.readTree(ACTION_CONFIGURATION)); ComponentDescriptor filterComp = new ComponentDescriptor(); filterComp.setClazz("org.thingsboard.server.extensions.core.filter.MsgTypeFilter"); filterComp.setType(ComponentType.FILTER); when(componentService.getComponent("org.thingsboard.server.extensions.core.filter.MsgTypeFilter")) .thenReturn(Optional.of(filterComp)); ComponentDescriptor actionComp = new ComponentDescriptor(); actionComp.setClazz("org.thingsboard.server.extensions.core.action.telemetry.TelemetryPluginAction"); actionComp.setType(ComponentType.ACTION); when(componentService.getComponent("org.thingsboard.server.extensions.core.action.telemetry.TelemetryPluginAction")) .thenReturn(Optional.of(actionComp)); ObjectMapper pluginMapper = new ObjectMapper(); JsonNode pluginAdditionalInfo = pluginMapper.readTree(PLUGIN_CONFIGURATION); when(pluginMock.getConfiguration()).thenReturn(pluginAdditionalInfo); when(pluginMock.getClazz()).thenReturn(TelemetryStoragePlugin.class.getName()); when(attributesService.findAll(deviceId, DataConstants.CLIENT_SCOPE)).thenReturn(Futures.immediateFuture(Collections.emptyList())); when(attributesService.findAll(deviceId, DataConstants.SHARED_SCOPE)).thenReturn(Futures.immediateFuture(Collections.emptyList())); when(attributesService.findAll(deviceId, DataConstants.SERVER_SCOPE)).thenReturn(Futures.immediateFuture(Collections.emptyList())); initActorSystem(); Thread.sleep(1000); actorService.process(new BasicToDeviceActorSessionMsg(device, msg)); // Check that device data was saved to DB; List<TsKvEntry> expected = new ArrayList<>(); expected.add(new BasicTsKvEntry(ts, entry1)); expected.add(new BasicTsKvEntry(ts, entry2)); verify(tsService, Mockito.timeout(5000)).save(DataConstants.DEVICE, deviceId, expected); } }