package com.devicehive.service; /* * #%L * DeviceHive Frontend Logic * %% * Copyright (C) 2016 DataArt * %% * 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. * #L% */ import com.devicehive.base.AbstractResourceTest; import com.devicehive.base.RequestDispatcherProxy; import com.devicehive.configuration.Constants; import com.devicehive.dao.DeviceDao; import com.devicehive.model.DeviceNotification; import com.devicehive.model.JsonStringWrapper; import com.devicehive.model.SpecialNotifications; import com.devicehive.model.rpc.*; import com.devicehive.service.exception.BackendException; import com.devicehive.shim.api.Request; import com.devicehive.shim.api.Response; import com.devicehive.shim.api.server.RequestHandler; import com.devicehive.vo.DeviceVO; import org.apache.commons.lang3.RandomStringUtils; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.internal.util.reflection.Whitebox; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.DirtiesContext; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; import static org.junit.Assert.*; import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; @SuppressWarnings("unchecked") public class DeviceNotificationServiceTest extends AbstractResourceTest { @Autowired private DeviceNotificationService notificationService; @Autowired private RequestDispatcherProxy requestDispatcherProxy; @Mock private RequestHandler requestHandler; private ArgumentCaptor<Request> argument = ArgumentCaptor.forClass(Request.class); @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); requestDispatcherProxy.setRequestHandler(requestHandler); } @After public void tearDown() { Mockito.reset(requestHandler); } @Test @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) public void testFindOneWithResponse() throws Exception { final String guid = UUID.randomUUID().toString(); final long id = System.currentTimeMillis(); final String notification = "Expected notification"; final Date timestamp = new Date(); final String parameters = "{\"param1\":\"value1\",\"param2\":\"value2\"}"; final DeviceNotification deviceNotification = new DeviceNotification(); deviceNotification.setId(id); deviceNotification.setDeviceGuid(guid); deviceNotification.setNotification(notification); deviceNotification.setTimestamp(timestamp); deviceNotification.setParameters(new JsonStringWrapper(parameters)); // return response for any request when(requestHandler.handle(any(Request.class))).thenReturn(Response.newBuilder() .withBody(new NotificationSearchResponse(Collections.singletonList(deviceNotification))) .buildSuccess()); // call service method notificationService.findOne(id, guid) .thenAccept(opt -> { assertTrue(opt.isPresent()); assertEquals(guid, opt.get().getDeviceGuid()); assertEquals(timestamp, opt.get().getTimestamp()); assertEquals(parameters, opt.get().getParameters().getJsonString()); assertEquals(notification, opt.get().getNotification()); assertEquals(Long.valueOf(id), opt.get().getId()); }) .exceptionally(ex -> { fail(ex.toString()); return null; }).get(15, TimeUnit.SECONDS); verify(requestHandler, times(1)).handle(argument.capture()); assertEquals(Action.NOTIFICATION_SEARCH_REQUEST.name(), argument.getValue().getBody().getAction()); NotificationSearchRequest request = argument.getValue().getBody().cast(NotificationSearchRequest.class); assertEquals(id, request.getId().longValue()); assertEquals(guid, request.getGuid()); assertNull(request.getStatus()); assertNull(request.getNames()); assertNull(request.getTimestampStart()); assertNull(request.getTimestampEnd()); assertNull(request.getTimestampEnd()); } @Test @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) public void testFindOneWithEmptyResponse() throws Exception { final String guid = UUID.randomUUID().toString(); final long id = System.currentTimeMillis(); // return empty response for any request when(requestHandler.handle(any(Request.class))).thenReturn(Response.newBuilder() .withBody(new NotificationSearchResponse(Collections.emptyList())) .buildSuccess()); // call service method notificationService.findOne(id, guid) .thenAccept(opt -> assertFalse(opt.isPresent())) .exceptionally(ex -> { fail(ex.toString()); return null; }).get(15, TimeUnit.SECONDS); verify(requestHandler, times(1)).handle(argument.capture()); assertEquals(Action.NOTIFICATION_SEARCH_REQUEST.name(), argument.getValue().getBody().getAction()); NotificationSearchRequest request = argument.getValue().getBody().cast(NotificationSearchRequest.class); assertEquals(id, request.getId().longValue()); assertEquals(guid, request.getGuid()); assertNull(request.getStatus()); assertNull(request.getNames()); assertNull(request.getTimestampStart()); assertNull(request.getTimestampEnd()); } @Test @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) public void testFindOneWithErrorResponse() throws Exception { final String guid = UUID.randomUUID().toString(); final long id = System.currentTimeMillis(); final String expectedErrorMessage = "EXPECTED ERROR MESSAGE"; final int errorCode = 500; // return fail response for any request when(requestHandler.handle(any(Request.class))).thenReturn(Response.newBuilder() .withBody(new ErrorResponse(expectedErrorMessage)) .buildFailed(errorCode)); // call service method notificationService.findOne(id, guid) .thenAccept(opt -> fail("Must be completed exceptionally")) .exceptionally(ex -> { assertEquals(BackendException.class, ex.getCause().getClass()); assertEquals(expectedErrorMessage, ex.getCause().getMessage()); assertEquals(errorCode, ((BackendException) ex.getCause()).getErrorCode()); return null; }).get(15, TimeUnit.SECONDS); verify(requestHandler, times(1)).handle(argument.capture()); assertEquals(Action.NOTIFICATION_SEARCH_REQUEST.name(), argument.getValue().getBody().getAction()); NotificationSearchRequest request = argument.getValue().getBody().cast(NotificationSearchRequest.class); assertEquals(id, request.getId().longValue()); assertEquals(guid, request.getGuid()); assertNull(request.getStatus()); assertNull(request.getNames()); assertNull(request.getTimestampStart()); assertNull(request.getTimestampEnd()); } @Test @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) public void testFindWithEmptyResponse() throws Exception { final List<String> guids = IntStream.range(0, 5) .mapToObj(i -> UUID.randomUUID().toString()) .collect(Collectors.toList()); final Date timestampSt = new Date(); final Date timestampEnd = new Date(); final Set<String> guidsForSearch = new HashSet<>(Arrays.asList( guids.get(0), guids.get(2), guids.get(3))); // return empty response for any request when(requestHandler.handle(any(Request.class))).thenReturn(Response.newBuilder() .withBody(new NotificationSearchResponse(Collections.emptyList())) .buildSuccess()); notificationService.find(guidsForSearch, Collections.emptySet(), timestampSt, timestampEnd) .thenAccept(notifications -> assertTrue(notifications.isEmpty())) .exceptionally(ex -> { fail(ex.toString()); return null; }).get(15, TimeUnit.SECONDS); verify(requestHandler, times(3)).handle(argument.capture()); NotificationSearchRequest request = argument.getValue().getBody().cast(NotificationSearchRequest.class); assertNull(request.getId()); assertTrue(guidsForSearch.contains(request.getGuid())); assertTrue(request.getNames().isEmpty()); assertEquals(timestampSt, request.getTimestampStart()); assertEquals(timestampEnd, request.getTimestampEnd()); } @Test @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) public void testFindWithResponse() throws Exception { final List<String> guids = IntStream.range(0, 5) .mapToObj(i -> UUID.randomUUID().toString()) .collect(Collectors.toList()); final Date timestampSt = new Date(); final Date timestampEnd = new Date(); final String parameters = "{\"param1\":\"value1\",\"param2\":\"value2\"}"; final Set<String> guidsForSearch = new HashSet<>(Arrays.asList( guids.get(0), guids.get(2), guids.get(3))); // return response for any request Map<String, DeviceNotification> notificationMap = guidsForSearch.stream() .collect(Collectors.toMap(Function.identity(), guid -> { DeviceNotification notification = new DeviceNotification(); notification.setId(System.nanoTime()); notification.setDeviceGuid(guid); notification.setNotification(RandomStringUtils.randomAlphabetic(10)); notification.setTimestamp(new Date()); notification.setParameters(new JsonStringWrapper(parameters)); return notification; })); when(requestHandler.handle(any(Request.class))).then(invocation -> { Request request = invocation.getArgumentAt(0, Request.class); String guid = request.getBody().cast(NotificationSearchRequest.class).getGuid(); return Response.newBuilder() .withBody(new NotificationSearchResponse(Collections.singletonList(notificationMap.get(guid)))) .buildSuccess(); }); notificationService.find(guidsForSearch, Collections.emptySet(), timestampSt, timestampEnd) .thenAccept(notifications -> { assertEquals(3, notifications.size()); assertEquals(new HashSet<>(notificationMap.values()), new HashSet<>(notifications)); // using HashSet to ignore order }) .exceptionally(ex -> { fail(ex.toString()); return null; }).get(30, TimeUnit.SECONDS); verify(requestHandler, times(3)).handle(argument.capture()); } @Test @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) public void testSubmitDeviceNotificationShouldInsertSingleNotification() throws Exception { final DeviceVO deviceVO = new DeviceVO(); deviceVO.setId(System.nanoTime()); deviceVO.setGuid(UUID.randomUUID().toString()); final DeviceNotification deviceNotification = new DeviceNotification(); deviceNotification.setId(System.nanoTime()); deviceNotification.setTimestamp(new Date()); deviceNotification.setNotification(RandomStringUtils.randomAlphabetic(10)); deviceNotification.setDeviceGuid(deviceVO.getGuid()); when(requestHandler.handle(any(Request.class))).thenReturn(Response.newBuilder() .withBody(new NotificationInsertResponse(deviceNotification)) .buildSuccess()); notificationService.insert(deviceNotification, deviceVO) .thenAccept(notification -> assertEquals(deviceNotification, notification)) .exceptionally(ex -> { fail(ex.toString()); return null; }).get(15, TimeUnit.SECONDS); verify(requestHandler, times(1)).handle(argument.capture()); NotificationInsertRequest request = argument.getValue().getBody().cast(NotificationInsertRequest.class); assertEquals(Action.NOTIFICATION_INSERT_REQUEST.name(), request.getAction()); assertEquals(deviceNotification, request.getDeviceNotification()); } @Test @DirtiesContext(methodMode = DirtiesContext.MethodMode.BEFORE_METHOD) public void testSubmitDeviceNotificationWithRefreshEquipmentShouldInsertSingleNotification() throws Exception { // mock DeviceDao final DeviceEquipmentService equipmentServiceMock = Mockito.mock(DeviceEquipmentService.class); Whitebox.setInternalState(notificationService, "deviceEquipmentService", equipmentServiceMock); // create inputs final DeviceVO deviceVO = new DeviceVO(); deviceVO.setId(System.nanoTime()); deviceVO.setGuid(UUID.randomUUID().toString()); final DeviceNotification deviceNotification = new DeviceNotification(); deviceNotification.setId(System.nanoTime()); deviceNotification.setTimestamp(new Date()); deviceNotification.setNotification(SpecialNotifications.EQUIPMENT); deviceNotification.setDeviceGuid(deviceVO.getGuid()); // define returns when(requestHandler.handle(any(Request.class))).thenReturn(Response.newBuilder() .withBody(new NotificationInsertResponse(deviceNotification)) .buildSuccess()); // execute notificationService.insert(deviceNotification, deviceVO) .thenAccept(notification -> assertEquals(deviceNotification, notification)) .exceptionally(ex -> { fail(ex.toString()); return null; }).get(15, TimeUnit.SECONDS); // check verify(requestHandler, times(1)).handle(argument.capture()); verify(equipmentServiceMock, times(1)).refreshDeviceEquipment(eq(deviceNotification), eq(deviceVO)); NotificationInsertRequest request = argument.getValue().getBody().cast(NotificationInsertRequest.class); assertEquals(Action.NOTIFICATION_INSERT_REQUEST.name(), request.getAction()); assertEquals(deviceNotification, request.getDeviceNotification()); } }