/*
* Copyright (C) 2015 Orange
*
* This software is distributed under the terms and conditions of the 'GNU GENERAL PUBLIC LICENSE
* Version 2' license which can be found in the file 'LICENSE.txt' in this package distribution or
* at 'http://www.gnu.org/licenses/gpl-2.0-standalone.html'.
*/
package com.orange.cepheus.broker;
import com.orange.cepheus.broker.exception.SubscriptionException;
import com.orange.cepheus.broker.exception.SubscriptionPersistenceException;
import com.orange.cepheus.broker.model.Subscription;
import com.orange.cepheus.broker.persistence.SubscriptionsRepository;
import com.orange.ngsi.model.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.Assert;
import org.junit.Rule;
import org.junit.rules.ExpectedException;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import static com.orange.cepheus.broker.Util.createSubscribeContext;
import static com.orange.cepheus.broker.Util.createSubscribeContextTemperature;
import static org.junit.Assert.*;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.when;
import static org.mockito.Matchers.any;
/**
* Tests for Subscriptions management
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@TestPropertySource(locations="classpath:test.properties")
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class SubscriptionsTest {
@Rule
public ExpectedException thrown= ExpectedException.none();
@Autowired
public Subscriptions subscriptions;
@Autowired
SubscriptionsRepository subscriptionsRepository;
@Test
public void addSubscriptionTest() throws URISyntaxException, SubscriptionException, SubscriptionPersistenceException {
SubscribeContext subscribeContext = createSubscribeContextTemperature();
String subscriptionId = subscriptions.addSubscription(subscribeContext);
Assert.notNull(subscriptionId);
Assert.hasLength(subscriptionId);
Assert.notNull(subscriptions.getSubscription(subscriptionId));
Map<String, Subscription> subscriptions = subscriptionsRepository.getAllSubscriptions();
Assert.isTrue(subscriptions.size()==1);
Assert.notNull(subscriptions.get(subscriptionId).getExpirationDate());
}
@Test
public void addSubscriptionWithNegativeDurationTest() throws SubscriptionException, URISyntaxException, SubscriptionPersistenceException {
thrown.expect(SubscriptionException.class);
thrown.expectMessage("negative duration is not allowed");
SubscribeContext subscribeContext = createSubscribeContextTemperature();
subscribeContext.setDuration("-PT10S");
subscriptions.addSubscription(subscribeContext);
Assert.isTrue(subscriptionsRepository.getAllSubscriptions().size()==0);
}
@Test
public void addSubscriptionWithBadDurationTest() throws SubscriptionException, URISyntaxException, SubscriptionPersistenceException {
thrown.expect(SubscriptionException.class);
thrown.expectMessage("bad duration: PIPO");
SubscribeContext subscribeContext = createSubscribeContextTemperature();
subscribeContext.setDuration("PIPO");
subscriptions.addSubscription(subscribeContext);
Assert.isTrue(subscriptionsRepository.getAllSubscriptions().size()==0);
}
@Test
public void addSubscriptionWithZeroDurationTest() throws SubscriptionException, URISyntaxException, SubscriptionPersistenceException {
SubscribeContext subscribeContext = createSubscribeContextTemperature();
subscribeContext.setDuration("PT0S");
String subscriptionId = subscriptions.addSubscription(subscribeContext);
Assert.notNull(subscriptionId);
Assert.hasLength(subscriptionId);
Subscription subscription = subscriptions.getSubscription(subscriptionId);
Assert.notNull(subscription);
Assert.notNull(subscription.getExpirationDate());
Assert.notNull(subscription.getSubscriptionId());
assertEquals(subscriptionId, subscription.getSubscriptionId());
Calendar c = (Calendar) Calendar.getInstance().clone();
c.add(Calendar.MONTH, 1);
c.add(Calendar.HOUR, 24);
assertFalse(subscription.getExpirationDate().isAfter(c.toInstant()));
c.add(Calendar.HOUR, -48);
assertFalse(subscription.getExpirationDate().isBefore(c.toInstant()));
Assert.isTrue(subscriptionsRepository.getAllSubscriptions().size()==1);
}
@Test
public void addSubscriptionWithBadPatternTest() throws SubscriptionException, URISyntaxException, SubscriptionPersistenceException {
thrown.expect(SubscriptionException.class);
thrown.expectMessage("bad pattern");
SubscribeContext subscribeContext = createSubscribeContextTemperature();
subscribeContext.getEntityIdList().get(0).setId("]|,\\((");
subscribeContext.getEntityIdList().get(0).setIsPattern(true);
subscriptions.addSubscription(subscribeContext);
Assert.isTrue(subscriptionsRepository.getAllSubscriptions().size()==0);
}
@Test
public void deleteExistSubscriptions() throws URISyntaxException, SubscriptionException, SubscriptionPersistenceException {
SubscribeContext subscribeContext = createSubscribeContextTemperature();
String subscriptionId = subscriptions.addSubscription(subscribeContext);
Assert.isTrue(subscriptionsRepository.getAllSubscriptions().size()==1);
UnsubscribeContext unsubscribeContext = new UnsubscribeContext(subscriptionId);
assertTrue(subscriptions.deleteSubscription(unsubscribeContext));
Assert.isTrue(subscriptionsRepository.getAllSubscriptions().size()==0);
}
@Test
public void deleteNotExistSubscriptions() throws URISyntaxException, SubscriptionException, SubscriptionPersistenceException {
UnsubscribeContext unsubscribeContext = new UnsubscribeContext("12345");
assertFalse(subscriptions.deleteSubscription(unsubscribeContext));
}
@Test
public void purgeExpiredSubscriptionsTest() throws URISyntaxException, SubscriptionException, InterruptedException, SubscriptionPersistenceException {
SubscribeContext subscribeContext = createSubscribeContextTemperature();
subscribeContext.setDuration("PT1S"); // 1s only
String subscriptionId = subscriptions.addSubscription(subscribeContext);
Assert.isTrue(subscriptionsRepository.getAllSubscriptions().size()==1);
Thread.sleep(1500);
subscriptions.purgeExpiredSubscriptions();
assertNull(subscriptions.getSubscription(subscriptionId));
Assert.isTrue(subscriptionsRepository.getAllSubscriptions().size()==0);
}
@Test
public void testFindEntityId() throws Exception {
// Insert 3 subscriptions
for (String n : new String[]{"A", "B", "C"}) {
subscriptions.addSubscription(createSubscribeContext(n, "string", false, "http://" + n, "temp"));
}
// Find B
EntityId searchedEntityId = new EntityId("B", "string", false);
Iterator<Subscription> it = subscriptions.findSubscriptions(searchedEntityId, null);
assertTrue(it.hasNext());
assertEquals("http://B", it.next().getSubscribeContext().getReference().toString());
assertFalse(it.hasNext());
}
@Test
public void testFindEntityIds() throws Exception {
// Insert 3 subscriptions
for (String n : new String[]{"A", "B", "C"}) {
subscriptions.addSubscription(createSubscribeContext(n, "string", false, "http://" + n, "temp"));
}
// Insert 3 more
for (String n : new String[]{"A", "B", "C"}) {
subscriptions.addSubscription(createSubscribeContext(n, "string", false, "http://" + n + "2", "temp"));
}
// Find the two B
EntityId searchedEntityId = new EntityId("B", "string", false);
List<String> results = new LinkedList<>();
subscriptions.findSubscriptions(searchedEntityId, null).forEachRemaining(subscription -> results.add(subscription.getSubscribeContext().getReference().toString()));
Collections.sort(results);
assertEquals(2, results.size());
assertEquals("http://B", results.get(0));
assertEquals("http://B2", results.get(1));
}
@Test
public void testFindEntityIdPattern() throws Exception {
// Insert 3 localRegistrations
for (String n : new String[]{"A", "B", "C"}) {
subscriptions.addSubscription(createSubscribeContext(n, "string", false, "http://" + n, "temp"));
}
// Find A and B
EntityId searchedEntityId = new EntityId("A|B", "string", true);
List<String> results = new LinkedList<>();
subscriptions.findSubscriptions(searchedEntityId, null).forEachRemaining(subscription -> results.add(subscription.getSubscribeContext().getReference().toString()));
Collections.sort(results);
assertEquals(2, results.size());
assertEquals("http://A", results.get(0));
assertEquals("http://B", results.get(1));
}
@Test
public void testFindEntityIdPattern2() throws Exception {
// Insert 3 subscriptions
subscriptions.addSubscription(createSubscribeContext("A|B", "string", true, "http://" + "AB", "temp"));
for (String n : new String[]{"C", "D"}) {
subscriptions.addSubscription(createSubscribeContext(n, "string", false, "http://" + n, "temp"));
}
// Find A and B
EntityId searchedEntityId = new EntityId("A", "string", false);
List<String> results = new LinkedList<>();
subscriptions.findSubscriptions(searchedEntityId, null).forEachRemaining(subscription -> results.add(subscription.getSubscribeContext().getReference().toString()));
Collections.sort(results);
assertEquals(1, results.size());
assertEquals("http://AB", results.get(0));
}
@Test
public void testPartialAttributesMatch() throws Exception {
SubscribeContext subscribeContext = createSubscribeContext("A", "string", false, "http://A" , "");
subscribeContext.setAttributeList(Arrays.asList("temp", "humidity"));
subscriptions.addSubscription(subscribeContext);
// Find http://A matching temp
Iterator<Subscription> it = subscriptions.findSubscriptions(new EntityId("A", "string", false), new HashSet<>(Arrays.asList("temp")));
assertTrue(it.hasNext());
assertEquals("http://A", it.next().getSubscribeContext().getReference().toString());
assertFalse(it.hasNext());
// Find http://A matching humidity and temp
it = subscriptions.findSubscriptions(new EntityId("A", "string", false), new HashSet<>(Arrays.asList("humidity", "temp")));
assertTrue(it.hasNext());
assertEquals("http://A", it.next().getSubscribeContext().getReference().toString());
assertFalse(it.hasNext());
// Find http://A matching humidity
it = subscriptions.findSubscriptions(new EntityId("A", "string", false), new HashSet<>(Arrays.asList("humidity", "pressure")));
assertTrue(it.hasNext());
assertEquals("http://A", it.next().getSubscribeContext().getReference().toString());
assertFalse(it.hasNext());
}
@Test
public void testFindEntityIdNoMatch() throws Exception {
// Insert 3 subscriptions
for (String n : new String[]{"A", "B", "C"}) {
subscriptions.addSubscription(createSubscribeContext(n, "string", false, "http://" + n, "temp"));
}
EntityId searchedEntityId = new EntityId("D", "string", false);
Iterator<Subscription> it = subscriptions.findSubscriptions(searchedEntityId, null);
assertFalse(it.hasNext());
searchedEntityId = new EntityId("B", "wrongtype", false);
it = subscriptions.findSubscriptions(searchedEntityId, null);
assertFalse(it.hasNext());
}
@Test
public void testFindEntityIdExpired() throws Exception {
// Insert 3 localRegistrations with short expiration
for (String n : new String[]{"A", "B", "C"}) {
SubscribeContext subscribeContext = createSubscribeContext(n, "string", false, "http://" + n, "temp");
subscribeContext.setDuration("PT1S");
subscriptions.addSubscription(subscribeContext);
}
// Wait for expiration
Thread.sleep(1500);
EntityId searchedEntityId = new EntityId("A", "string", false);
Iterator<Subscription> it = subscriptions.findSubscriptions(searchedEntityId, null);
assertFalse(it.hasNext());
searchedEntityId = new EntityId("B", "string", false);
it = subscriptions.findSubscriptions(searchedEntityId, null);
assertFalse(it.hasNext());
searchedEntityId = new EntityId("C", "string", false);
it = subscriptions.findSubscriptions(searchedEntityId, null);
assertFalse(it.hasNext());
}
}