package com.devicehive.handler.notification; /* * #%L * DeviceHive Backend 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.AbstractSpringTest; import com.devicehive.model.DeviceNotification; import com.devicehive.model.eventbus.events.NotificationEvent; import com.devicehive.model.rpc.*; import com.devicehive.shim.api.Body; import com.devicehive.shim.api.Request; import com.devicehive.shim.api.Response; import com.devicehive.shim.api.client.RpcClient; import org.junit.Ignore; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; import static java.util.UUID.randomUUID; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; public class NotificationSubscribeInsertIntegrationTest extends AbstractSpringTest { @Autowired private RpcClient client; @Test public void shouldSubscribeToDeviceNotifications() throws Exception { String device1 = randomUUID().toString(); String device2 = randomUUID().toString(); String subscriber1 = randomUUID().toString(); String subscriber2 = randomUUID().toString(); String subscriber3 = randomUUID().toString(); NotificationSubscribeRequest sr1 = new NotificationSubscribeRequest(subscriber1, device1, null, null); Request r1 = Request.newBuilder().withBody(sr1).withSingleReply(false).build(); TestCallback c1 = new TestCallback(); client.call(r1, c1); NotificationSubscribeRequest sr2 = new NotificationSubscribeRequest(subscriber1, device2, Collections.singleton("temperature"), null); Request r2 = Request.newBuilder().withBody(sr2).withSingleReply(false).build(); TestCallback c2 = new TestCallback(); client.call(r2, c2); NotificationSubscribeRequest sr3 = new NotificationSubscribeRequest(subscriber2, device2, null, null); Request r3 = Request.newBuilder().withBody(sr3).withSingleReply(false).build(); TestCallback c3 = new TestCallback(); client.call(r3, c3); NotificationSubscribeRequest sr4 = new NotificationSubscribeRequest(subscriber2, device1, Collections.singleton("vibration"), null); Request r4 = Request.newBuilder().withBody(sr4).withSingleReply(false).build(); TestCallback c4 = new TestCallback(); client.call(r4, c4); NotificationSubscribeRequest sr5 = new NotificationSubscribeRequest(subscriber3, randomUUID().toString(), null, null); Request r5 = Request.newBuilder().withBody(sr5).withSingleReply(false).build(); TestCallback c5 = new TestCallback(); client.call(r5, c5); //wait subsribers to subscribe Stream.of(c1.subscribeFuture, c2.subscribeFuture, c3.subscribeFuture, c4.subscribeFuture, c5.subscribeFuture) .forEach(CompletableFuture::join); //devices send notifications List<CompletableFuture<Response>> futures = Stream.of(device1, device2).flatMap(device -> { List<CompletableFuture<Response>> list = Stream.of("temperature", "vibration").map(name -> { DeviceNotification notification = new DeviceNotification(); notification.setId(0); notification.setNotification(name); notification.setDeviceGuid(device); NotificationInsertRequest event = new NotificationInsertRequest(notification); CompletableFuture<Response> f = new CompletableFuture<>(); client.call(Request.newBuilder().withBody(event).build(), f::complete); return f; }).collect(Collectors.toList()); return list.stream(); }).collect(Collectors.toList()); //wait notifications delivered futures.forEach(CompletableFuture::join); assertThat(c1.notifications, hasSize(2)); c1.notifications.forEach(event -> { assertNotNull(event.getNotification()); assertEquals(event.getNotification().getDeviceGuid(), device1); assertEquals(event.getNotification().getId(), Long.valueOf(0)); }); Set<String> names = c1.notifications.stream() .map(n -> n.getNotification().getNotification()) .collect(Collectors.toSet()); assertThat(names, containsInAnyOrder("temperature", "vibration")); assertThat(c2.notifications, hasSize(1)); NotificationEvent e = c2.notifications.stream().findFirst().get(); assertNotNull(e.getNotification()); assertEquals(e.getNotification().getDeviceGuid(), device2); assertEquals(e.getNotification().getId(), Long.valueOf(0)); assertEquals(e.getNotification().getNotification(), "temperature"); assertThat(c3.notifications, hasSize(2)); c3.notifications.forEach(event -> { assertNotNull(event.getNotification()); assertEquals(event.getNotification().getDeviceGuid(), device2); assertEquals(event.getNotification().getId(), Long.valueOf(0)); }); names = c3.notifications.stream() .map(n -> n.getNotification().getNotification()) .collect(Collectors.toSet()); assertThat(names, containsInAnyOrder("temperature", "vibration")); assertThat(c4.notifications, hasSize(1)); e = c4.notifications.stream().findFirst().get(); assertNotNull(e.getNotification()); assertEquals(e.getNotification().getDeviceGuid(), device1); assertEquals(e.getNotification().getId(), Long.valueOf(0)); assertEquals(e.getNotification().getNotification(), "vibration"); assertThat(c5.notifications, is(empty())); } @Test @Ignore public void shouldUnsubscribeFromNotifications() throws Exception { String device1 = randomUUID().toString(); String subscriber1 = randomUUID().toString(); String subscriber2 = randomUUID().toString(); NotificationSubscribeRequest sr1 = new NotificationSubscribeRequest(subscriber1, device1, null, null); Request r1 = Request.newBuilder().withBody(sr1).withSingleReply(false).build(); TestCallback c1 = new TestCallback(); client.call(r1, c1); NotificationSubscribeRequest sr2 = new NotificationSubscribeRequest(subscriber2, device1, null, null); Request r2 = Request.newBuilder().withBody(sr2).withSingleReply(false).build(); TestCallback c2 = new TestCallback(); client.call(r2, c2); Stream.of(c1.subscribeFuture, c2.subscribeFuture).forEach(CompletableFuture::join); DeviceNotification notification = new DeviceNotification(); notification.setId(0); notification.setNotification("temperature"); notification.setDeviceGuid(device1); NotificationInsertRequest event = new NotificationInsertRequest(notification); CompletableFuture<Response> f1 = new CompletableFuture<>(); client.call(Request.newBuilder().withBody(event).build(), f1::complete); f1.get(15, TimeUnit.SECONDS); assertThat(c1.notifications, hasSize(1)); assertThat(c2.notifications, hasSize(1)); NotificationUnsubscribeRequest ur = new NotificationUnsubscribeRequest(sr1.getSubscriptionId(), null); Request r3 = Request.newBuilder().withBody(ur).withSingleReply(false).build(); client.call(r3, c1); c1.subscribeFuture.join(); DeviceNotification notification2 = new DeviceNotification(); notification2.setId(1); notification2.setNotification("temperature"); notification2.setDeviceGuid(device1); NotificationInsertRequest event2 = new NotificationInsertRequest(notification2); CompletableFuture<Response> f2 = new CompletableFuture<>(); client.call(Request.newBuilder().withBody(event2).build(), f2::complete); f2.join(); assertThat(c1.notifications, hasSize(1)); assertThat(c2.notifications, hasSize(2)); } public static class TestCallback implements Consumer<Response> { private CompletableFuture<Body> subscribeFuture; private Set<NotificationEvent> notifications; public TestCallback() { this.subscribeFuture = new CompletableFuture<>(); this.notifications = new HashSet<>(); } @Override public void accept(Response response) { if (response.getBody().getAction().equals(Action.NOTIFICATION_SUBSCRIBE_RESPONSE.name()) || response.getBody().getAction().equals(Action.NOTIFICATION_UNSUBSCRIBE_RESPONSE.name())) { subscribeFuture.complete(response.getBody()); } else if (response.getBody().getAction().equals(Action.NOTIFICATION_EVENT.name())) { notifications.add((NotificationEvent) response.getBody()); } else { throw new IllegalArgumentException("Unexpected response " + response); } } } }