Merge changes I63383291,I1c9f10e9,I9cac529f,I269d373b,I7ede3ba5,I4afc1e15
[controller.git] / opendaylight / md-sal / remoterpc-routingtable / implementation / src / test / java / org / opendaylight / controller / sal / connector / remoterpc / impl / RoutingTableImplTest.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.sal.connector.remoterpc.impl;
10
11 import junit.framework.Assert;
12 import org.apache.felix.dm.Component;
13 import org.junit.After;
14 import org.junit.Before;
15 import org.junit.Test;
16 import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
17 import org.opendaylight.controller.clustering.services.IClusterServices;
18 import org.opendaylight.controller.sal.connector.api.RpcRouter;
19 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
20 import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
21 import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
22 import org.opendaylight.yangtools.yang.common.QName;
23 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
24
25 import java.net.URI;
26 import java.util.EnumSet;
27 import java.util.HashSet;
28 import java.util.LinkedHashSet;
29 import java.util.Set;
30 import java.util.concurrent.*;
31
32 import static org.mockito.Mockito.*;
33
34 public class RoutingTableImplTest {
35
36   private final URI namespace = URI.create("http://cisco.com/example");
37   private final QName QNAME = new QName(namespace, "global");
38
39   private IClusterGlobalServices clusterService;
40   private RoutingTableImpl<RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier>, String> routingTable;
41   ConcurrentMap mockGlobalRpcCache;
42   ConcurrentMap mockRpcCache;
43
44   @Before
45   public void setUp() throws Exception{
46     clusterService = mock(IClusterGlobalServices.class);
47     routingTable = new RoutingTableImpl<RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier>, String>();
48     mockGlobalRpcCache = new ConcurrentHashMap<>();
49     mockRpcCache = new ConcurrentHashMap<>();
50     createRoutingTableCache();
51   }
52
53   @After
54   public void tearDown(){
55     reset(clusterService);
56     mockGlobalRpcCache = null;
57     mockRpcCache = null;
58   }
59
60   @Test
61   public void addGlobalRoute_ValidArguments_ShouldAdd() throws Exception {
62
63     Assert.assertNotNull(mockGlobalRpcCache);
64     RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = getRouteIdentifier();
65
66     final String expectedRoute = "172.27.12.1:5000";
67     routingTable.addGlobalRoute(routeIdentifier, expectedRoute);
68
69     ConcurrentMap latestCache = routingTable.getGlobalRpcCache();
70     Assert.assertEquals(mockGlobalRpcCache, latestCache);
71     Assert.assertEquals(expectedRoute, latestCache.get(routeIdentifier));
72   }
73
74   @Test (expected = RoutingTable.DuplicateRouteException.class)
75   public void addGlobalRoute_DuplicateRoute_ShouldThrow() throws Exception{
76
77     Assert.assertNotNull(mockGlobalRpcCache);
78
79     RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = getRouteIdentifier();
80     routingTable.addGlobalRoute(routeIdentifier, new String());
81     routingTable.addGlobalRoute(routeIdentifier, new String());
82   }
83
84   @Test
85   public void getGlobalRoute_ExistingRouteId_ShouldReturnRoute() throws Exception {
86
87     Assert.assertNotNull(mockGlobalRpcCache);
88     RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = getRouteIdentifier();
89     String expectedRoute = "172.27.12.1:5000";
90
91     routingTable.addGlobalRoute(routeIdentifier, expectedRoute);
92
93     String actualRoute = (String) routingTable.getGlobalRoute(routeIdentifier);
94     Assert.assertEquals(expectedRoute, actualRoute);
95   }
96
97   @Test
98   public void getGlobalRoute_NonExistentRouteId_ShouldReturnNull() throws Exception {
99
100     Assert.assertNotNull(mockGlobalRpcCache);
101     RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = getRouteIdentifier();
102
103     String actualRoute = (String) routingTable.getGlobalRoute(routeIdentifier);
104     Assert.assertNull(actualRoute);
105   }
106
107   @Test
108   public void removeGlobalRoute_ExistingRouteId_ShouldRemove() throws Exception {
109
110     Assert.assertNotNull(mockGlobalRpcCache);
111     RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = getRouteIdentifier();
112
113     ConcurrentMap cache = routingTable.getGlobalRpcCache();
114     Assert.assertTrue(cache.size() == 0);
115     routingTable.addGlobalRoute(routeIdentifier, "172.27.12.1:5000");
116     Assert.assertTrue(cache.size() == 1);
117
118     routingTable.removeGlobalRoute(routeIdentifier);
119     Assert.assertTrue(cache.size() == 0);
120
121   }
122
123   @Test
124   public void removeGlobalRoute_NonExistentRouteId_ShouldDoNothing() throws Exception {
125
126     Assert.assertNotNull(mockGlobalRpcCache);
127     RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = getRouteIdentifier();
128
129     ConcurrentMap cache = routingTable.getGlobalRpcCache();
130     Assert.assertTrue(cache.size() == 0);
131
132     routingTable.removeGlobalRoute(routeIdentifier);
133     Assert.assertTrue(cache.size() == 0);
134
135   }
136
137   @Test
138   public void addRoute_ForNewRouteId_ShouldAddRoute() throws Exception {
139     Assert.assertTrue(mockRpcCache.size() == 0);
140
141     RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeId = getRouteIdentifier();
142
143     routingTable.addRoute(routeId, new String());
144     Assert.assertTrue(mockRpcCache.size() == 1);
145
146     Set<String> routes = routingTable.getRoutes(routeId);
147     Assert.assertEquals(1, routes.size());
148   }
149
150   @Test
151   public void addRoute_ForExistingRouteId_ShouldAppendRoute() throws Exception {
152
153     Assert.assertTrue(mockRpcCache.size() == 0);
154
155     RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeId = getRouteIdentifier();
156
157     String route_1 = "10.0.0.1:5955";
158     String route_2 = "10.0.0.2:5955";
159
160     routingTable.addRoute(routeId, route_1);
161     routingTable.addRoute(routeId, route_2);
162
163     Assert.assertTrue(mockRpcCache.size() == 1);
164
165     Set<String> routes = routingTable.getRoutes(routeId);
166     Assert.assertEquals(2, routes.size());
167     Assert.assertTrue(routes.contains(route_1));
168     Assert.assertTrue(routes.contains(route_2));
169   }
170
171   @Test
172   public void addRoute_UsingMultipleThreads_ShouldNotOverwrite(){
173     ExecutorService threadPool = Executors.newCachedThreadPool();
174
175     int numOfRoutesToAdd = 100;
176     String routePrefix_1   = "10.0.0.1:555";
177     RpcRouter.RouteIdentifier routeId = getRouteIdentifier();
178     threadPool.submit(addRoutes(numOfRoutesToAdd, routePrefix_1, routeId));
179     String routePrefix_2   = "10.0.0.1:556";
180     threadPool.submit(addRoutes(numOfRoutesToAdd, routePrefix_2, routeId));
181
182     // wait for all tasks to complete; timeout in 10 sec
183     threadPool.shutdown();
184     try {
185       threadPool.awaitTermination(10, TimeUnit.SECONDS); //
186     } catch (InterruptedException e) {
187       e.printStackTrace();
188     }
189
190     Assert.assertEquals(2*numOfRoutesToAdd, routingTable.getRoutes(routeId).size());
191   }
192
193   @Test(expected = NullPointerException.class)
194   public void addRoute_NullRouteId_shouldThrowNpe() throws Exception {
195
196     routingTable.addRoute(null, new String());
197   }
198
199   @Test(expected = NullPointerException.class)
200   public void addRoute_NullRoute_shouldThrowNpe() throws Exception{
201
202     routingTable.addRoute(getRouteIdentifier(), null);
203   }
204
205   @Test (expected = UnsupportedOperationException.class)
206   public void getRoutes_Call_ShouldReturnImmutableCopy() throws Exception{
207     Assert.assertNotNull(routingTable);
208     RpcRouter.RouteIdentifier routeId = getRouteIdentifier();
209     routingTable.addRoute(routeId, new String());
210
211     Set<String> routes = routingTable.getRoutes(routeId); //returns Immutable Set
212
213     routes.add(new String()); //can not be modified; should throw
214   }
215
216   @Test
217   public void getRoutes_With2RoutesFor1RouteId_ShouldReturnASetWithSize2() throws Exception{
218     Assert.assertNotNull(routingTable);
219     RpcRouter.RouteIdentifier routeId = getRouteIdentifier();
220     routingTable.addRoute(routeId, "10.0.0.1:5555");
221     routingTable.addRoute(routeId, "10.0.0.2:5555");
222
223     Set<String> routes = routingTable.getRoutes(routeId); //returns Immutable Set
224
225     Assert.assertEquals(2, routes.size());
226   }
227
228   @Test
229   public void getLastAddedRoute_WhenMultipleRoutesExists_ShouldReturnLatestRoute()
230     throws Exception {
231
232     Assert.assertNotNull(routingTable);
233     RpcRouter.RouteIdentifier routeId = getRouteIdentifier();
234     String route_1 = "10.0.0.1:5555";
235     String route_2 = "10.0.0.2:5555";
236     routingTable.addRoute(routeId, route_1);
237     routingTable.addRoute(routeId, route_2);
238
239     Assert.assertEquals(route_2, routingTable.getLastAddedRoute(routeId));
240   }
241
242   @Test
243   public void removeRoute_WhenMultipleRoutesExist_RemovesGivenRoute() throws Exception{
244     Assert.assertNotNull(routingTable);
245     RpcRouter.RouteIdentifier routeId = getRouteIdentifier();
246     String route_1 = "10.0.0.1:5555";
247     String route_2 = "10.0.0.2:5555";
248
249     routingTable.addRoute(routeId, route_1);
250     routingTable.addRoute(routeId, route_2);
251
252     Assert.assertEquals(2, routingTable.getRoutes(routeId).size());
253
254     routingTable.removeRoute(routeId, route_1);
255     Assert.assertEquals(1, routingTable.getRoutes(routeId).size());
256
257   }
258
259   @Test
260   public void removeRoute_WhenOnlyOneRouteExists_RemovesRouteId() throws Exception{
261     Assert.assertNotNull(routingTable);
262     RpcRouter.RouteIdentifier routeId = getRouteIdentifier();
263     String route_1 = "10.0.0.1:5555";
264
265     routingTable.addRoute(routeId, route_1);
266     Assert.assertEquals(1, routingTable.getRoutes(routeId).size());
267
268     routingTable.removeRoute(routeId, route_1);
269     ConcurrentMap cache = routingTable.getRpcCache();
270     Assert.assertFalse(cache.containsKey(routeId));
271
272   }
273
274   /*
275    * Private helper methods
276    */
277   private void createRoutingTableCache() throws Exception {
278
279     //here init
280     Component c = mock(Component.class);
281
282     when(clusterService.existCache(
283         RoutingTableImpl.GLOBALRPC_CACHE)).thenReturn(false);
284
285     when(clusterService.createCache(RoutingTableImpl.GLOBALRPC_CACHE,
286         EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).
287         thenReturn(mockGlobalRpcCache);
288
289     when(clusterService.existCache(
290         RoutingTableImpl.RPC_CACHE)).thenReturn(false);
291
292     when(clusterService.createCache(RoutingTableImpl.RPC_CACHE,
293         EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL))).
294         thenReturn(mockRpcCache);
295
296     doNothing().when(clusterService).tbegin();
297     doNothing().when(clusterService).tcommit();
298
299     routingTable.setClusterGlobalServices(this.clusterService);
300     routingTable.init(c);
301
302     Assert.assertEquals(mockGlobalRpcCache, routingTable.getGlobalRpcCache());
303     Assert.assertEquals(mockRpcCache, routingTable.getRpcCache());
304   }
305
306   private RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> getRouteIdentifier(){
307     RpcRouter.RouteIdentifier<QName, QName, InstanceIdentifier> routeIdentifier = mock(RpcRouter.RouteIdentifier.class);
308     InstanceIdentifier identifier = mock(InstanceIdentifier.class);
309     when(routeIdentifier.getType()).thenReturn(QNAME);
310     when(routeIdentifier.getRoute()).thenReturn(identifier);
311
312     return routeIdentifier;
313   }
314
315   private Runnable addRoutes(final int numRoutes, final String routePrefix, final RpcRouter.RouteIdentifier routeId){
316     return new Runnable() {
317       @Override
318       public void run() {
319         for (int i=0;i<numRoutes;i++){
320           String route = routePrefix + i;
321           try {
322             routingTable.addRoute(routeId, route);
323           } catch (Exception e) {
324             e.printStackTrace();
325           }
326         }
327       }
328     };
329   }
330 }