64512d4719d2807e000c366de3dd71d8b8b41889
[bgpcep.git] / pcep / impl / src / test / java / org / opendaylight / protocol / pcep / impl / PCEPDispatcherImplTest.java
1 /*
2  * Copyright (c) 2014 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.protocol.pcep.impl;
10
11 import static java.util.Objects.requireNonNull;
12 import static org.junit.Assert.assertEquals;
13 import static org.mockito.Matchers.any;
14 import static org.mockito.Mockito.doReturn;
15 import static org.opendaylight.protocol.util.CheckUtil.waitFutureSuccess;
16
17 import io.netty.bootstrap.Bootstrap;
18 import io.netty.channel.ChannelFuture;
19 import io.netty.channel.ChannelInitializer;
20 import io.netty.channel.ChannelOption;
21 import io.netty.channel.EventLoopGroup;
22 import io.netty.channel.epoll.Epoll;
23 import io.netty.channel.epoll.EpollEventLoopGroup;
24 import io.netty.channel.nio.NioEventLoopGroup;
25 import io.netty.channel.socket.SocketChannel;
26 import io.netty.channel.socket.nio.NioSocketChannel;
27 import io.netty.util.concurrent.EventExecutor;
28 import io.netty.util.concurrent.Future;
29 import io.netty.util.concurrent.GlobalEventExecutor;
30 import java.net.InetSocketAddress;
31 import java.nio.channels.Channel;
32 import java.util.ArrayList;
33 import java.util.List;
34 import java.util.concurrent.ExecutionException;
35 import org.junit.After;
36 import org.junit.Assert;
37 import org.junit.Before;
38 import org.junit.Test;
39 import org.mockito.Mock;
40 import org.mockito.Mockito;
41 import org.mockito.MockitoAnnotations;
42 import org.opendaylight.protocol.concepts.KeyMapping;
43 import org.opendaylight.protocol.pcep.PCEPCapability;
44 import org.opendaylight.protocol.pcep.PCEPDispatcherDependencies;
45 import org.opendaylight.protocol.pcep.PCEPSession;
46 import org.opendaylight.protocol.pcep.PCEPSessionListenerFactory;
47 import org.opendaylight.protocol.pcep.PCEPSessionNegotiatorFactory;
48 import org.opendaylight.protocol.pcep.PCEPSessionProposalFactory;
49 import org.opendaylight.protocol.pcep.spi.MessageRegistry;
50 import org.opendaylight.protocol.pcep.spi.pojo.ServiceLoaderPCEPExtensionProviderContext;
51 import org.opendaylight.protocol.util.InetSocketAddressUtil;
52
53 public class PCEPDispatcherImplTest {
54     private static final short DEAD_TIMER = 120;
55     private static final short KEEP_ALIVE = 30;
56     private static final int RETRY_TIMER = 0;
57     private static final int CONNECT_TIMEOUT = 500;
58
59     private PCEPDispatcherImpl dispatcher;
60     private PCEPDispatcherImpl disp2Spy;
61
62     @Mock
63     private Channel mockChannel;
64     @Mock
65     private PCEPDispatcherDependencies dispatcherDependencies;
66     @Mock
67     private PCEPSessionListenerFactory listenerFactory;
68
69     private PCCMock pccMock;
70
71     @Before
72     public void setUp() {
73         MockitoAnnotations.initMocks(this);
74         final List<PCEPCapability> capList = new ArrayList<>();
75         final PCEPSessionProposalFactory sessionProposal = new BasePCEPSessionProposalFactory(DEAD_TIMER, KEEP_ALIVE,
76                 capList);
77         final EventLoopGroup eventLoopGroup;
78         if (Epoll.isAvailable()) {
79             eventLoopGroup = new EpollEventLoopGroup();
80         } else {
81             eventLoopGroup = new NioEventLoopGroup();
82         }
83         final MessageRegistry msgReg = ServiceLoaderPCEPExtensionProviderContext.getSingletonInstance()
84                 .getMessageHandlerRegistry();
85         this.dispatcher = new PCEPDispatcherImpl(msgReg,
86                 new DefaultPCEPSessionNegotiatorFactory(sessionProposal, 0),
87                 eventLoopGroup, eventLoopGroup);
88
89         doReturn(KeyMapping.getKeyMapping()).when(this.dispatcherDependencies).getKeys();
90         doReturn(null).when(this.dispatcherDependencies).getPeerProposal();
91
92         doReturn("mockChannel").when(this.mockChannel).toString();
93         final PCEPDispatcherImpl dispatcher2 = new PCEPDispatcherImpl(msgReg,
94                 new DefaultPCEPSessionNegotiatorFactory(sessionProposal, 0),
95                 eventLoopGroup, eventLoopGroup);
96         this.disp2Spy = Mockito.spy(dispatcher2);
97
98         this.pccMock = new PCCMock(new DefaultPCEPSessionNegotiatorFactory(sessionProposal, 0),
99                 new PCEPHandlerFactory(msgReg));
100     }
101
102     @Test
103     public void testCreateClientServer() throws InterruptedException, ExecutionException {
104         final int port = InetSocketAddressUtil.getRandomPort();
105         final InetSocketAddress serverAddr = new InetSocketAddress("0.0.0.0", port);
106         final InetSocketAddress clientAddr1 = InetSocketAddressUtil.getRandomLoopbackInetSocketAddress(port);
107         final InetSocketAddress clientAddr2 = InetSocketAddressUtil.getRandomLoopbackInetSocketAddress(port);
108
109         doReturn(serverAddr).when(this.dispatcherDependencies).getAddress();
110         doReturn(this.listenerFactory).when(this.dispatcherDependencies).getListenerFactory();
111         doReturn(new SimpleSessionListener()).when(this.listenerFactory).getSessionListener();
112         final ChannelFuture futureChannel = this.dispatcher.createServer(this.dispatcherDependencies);
113         waitFutureSuccess(futureChannel);
114         final PCEPSessionImpl session1 = this.pccMock.createClient(clientAddr1,
115                 RETRY_TIMER, CONNECT_TIMEOUT, SimpleSessionListener::new).get();
116
117         final PCEPSessionImpl session2 = this.pccMock.createClient(clientAddr2,
118                 RETRY_TIMER, CONNECT_TIMEOUT, SimpleSessionListener::new).get();
119
120         Assert.assertTrue(futureChannel.channel().isActive());
121         assertEquals(clientAddr1.getAddress().getHostAddress(), session1.getPeerPref().getIpAddress());
122         assertEquals(DEAD_TIMER, session1.getDeadTimerValue().shortValue());
123         assertEquals(KEEP_ALIVE, session1.getKeepAliveTimerValue().shortValue());
124
125         assertEquals(clientAddr2.getAddress().getHostAddress(), session2.getPeerPref().getIpAddress());
126         assertEquals(DEAD_TIMER, session2.getDeadTimerValue().shortValue());
127         assertEquals(KEEP_ALIVE, session2.getKeepAliveTimerValue().shortValue());
128
129         session1.close();
130         session2.close();
131         Assert.assertTrue(futureChannel.channel().isActive());
132     }
133
134     @Test
135     public void testCreateDuplicateClient() throws InterruptedException, ExecutionException {
136         final int port = InetSocketAddressUtil.getRandomPort();
137         final InetSocketAddress serverAddr = new InetSocketAddress("0.0.0.0", port);
138         final InetSocketAddress clientAddr = InetSocketAddressUtil.getRandomLoopbackInetSocketAddress(port);
139
140         doReturn(serverAddr).when(this.dispatcherDependencies).getAddress();
141         doReturn(this.listenerFactory).when(this.dispatcherDependencies).getListenerFactory();
142         doReturn(new SimpleSessionListener()).when(this.listenerFactory).getSessionListener();
143
144         waitFutureSuccess(this.dispatcher.createServer(this.dispatcherDependencies));
145         final Future<PCEPSessionImpl> futureClient = this.pccMock.createClient(clientAddr, RETRY_TIMER, CONNECT_TIMEOUT,
146                 SimpleSessionListener::new);
147         waitFutureSuccess(futureClient);
148         final PCEPSessionImpl session1 = futureClient.get();
149
150         try {
151             this.pccMock.createClient(clientAddr, RETRY_TIMER, CONNECT_TIMEOUT,
152                     SimpleSessionListener::new).get();
153             Assert.fail();
154         } catch (final ExecutionException e) {
155             Assert.assertTrue(e.getMessage().contains("A conflicting session for address"));
156         } finally {
157             session1.close();
158         }
159     }
160
161     @Test
162     public void testReconectClient() throws InterruptedException, ExecutionException {
163         final int port = InetSocketAddressUtil.getRandomPort();
164         final InetSocketAddress clientAddr = InetSocketAddressUtil.getRandomLoopbackInetSocketAddress(port);
165
166         doReturn(new InetSocketAddress("0.0.0.0", port)).when(this.dispatcherDependencies).getAddress();
167         doReturn(this.listenerFactory).when(this.dispatcherDependencies).getListenerFactory();
168         doReturn(new SimpleSessionListener()).when(this.listenerFactory).getSessionListener();
169         waitFutureSuccess(this.dispatcher.createServer(this.dispatcherDependencies));
170         final PCEPSessionImpl session1 = this.pccMock.createClient(clientAddr,
171                 RETRY_TIMER, CONNECT_TIMEOUT, SimpleSessionListener::new).get();
172
173         assertEquals(clientAddr.getAddress(), session1.getRemoteAddress());
174         assertEquals(DEAD_TIMER, session1.getDeadTimerValue().shortValue());
175         assertEquals(KEEP_ALIVE, session1.getKeepAliveTimerValue().shortValue());
176         waitFutureSuccess(session1.closeChannel());
177
178         final PCEPSessionImpl session2 = this.pccMock.createClient(clientAddr,
179                 RETRY_TIMER, CONNECT_TIMEOUT, SimpleSessionListener::new).get();
180
181         assertEquals(clientAddr.getAddress(), session1.getRemoteAddress());
182         assertEquals(DEAD_TIMER, session2.getDeadTimerValue().shortValue());
183         assertEquals(KEEP_ALIVE, session2.getKeepAliveTimerValue().shortValue());
184
185         session2.close();
186     }
187
188     @Test
189     public void testCustomizeBootstrap() {
190         final int port = InetSocketAddressUtil.getRandomPort();
191         final InetSocketAddress clientAddr1 = InetSocketAddressUtil.getRandomLoopbackInetSocketAddress(port);
192         final InetSocketAddress clientAddr2 = InetSocketAddressUtil.getRandomLoopbackInetSocketAddress(port);
193         final KeyMapping keys = KeyMapping.getKeyMapping(clientAddr1.getAddress(), "CLIENT1_ADDRESS");
194         keys.put(clientAddr2.getAddress(), "CLIENT2_ADDRESS".getBytes());
195
196         doReturn(new InetSocketAddress("0.0.0.0", port)).when(this.dispatcherDependencies).getAddress();
197         doReturn(this.listenerFactory).when(this.dispatcherDependencies).getListenerFactory();
198         doReturn(new SimpleSessionListener()).when(this.listenerFactory).getSessionListener();
199
200         final ChannelFuture futureChannel = this.disp2Spy.createServer(this.dispatcherDependencies);
201         waitFutureSuccess(futureChannel);
202         Mockito.verify(this.disp2Spy).createServerBootstrap(any(PCEPDispatcherImpl.ChannelPipelineInitializer.class));
203     }
204
205     @After
206     public void tearDown() {
207         this.dispatcher.close();
208         this.disp2Spy.close();
209     }
210
211     private static class PCCMock {
212         private final PCEPSessionNegotiatorFactory<PCEPSessionImpl> negotiatorFactory;
213         private final PCEPHandlerFactory factory;
214         private final EventExecutor executor;
215         private final EventLoopGroup workerGroup;
216
217         PCCMock(final PCEPSessionNegotiatorFactory<PCEPSessionImpl> negotiatorFactory,
218                 final PCEPHandlerFactory factory) {
219             this.workerGroup = new NioEventLoopGroup();
220             this.negotiatorFactory = requireNonNull(negotiatorFactory);
221             this.factory = requireNonNull(factory);
222             this.executor = requireNonNull(GlobalEventExecutor.INSTANCE);
223         }
224
225         Future<PCEPSessionImpl> createClient(final InetSocketAddress address, final int retryTimer,
226                 final int connectTimeout, final PCEPSessionListenerFactory listenerFactory) {
227             return createClient(address, retryTimer, connectTimeout, (ch, promise) -> {
228                 ch.pipeline().addLast(this.factory.getDecoders());
229                 ch.pipeline().addLast("negotiator", this.negotiatorFactory.getSessionNegotiator(
230                         () -> listenerFactory,
231                         ch,
232                         promise));
233                 ch.pipeline().addLast(this.factory.getEncoders());
234             });
235         }
236
237         Future<PCEPSessionImpl> createClient(final InetSocketAddress address, final int retryTimer,
238                 final int connectTimeout, final PCEPDispatcherImpl.ChannelPipelineInitializer initializer) {
239             final Bootstrap b = new Bootstrap();
240             final PCEPProtocolSessionPromise<PCEPSessionImpl> p = new PCEPProtocolSessionPromise<>(this.executor,
241                     address, retryTimer, connectTimeout, b);
242             b.option(ChannelOption.SO_KEEPALIVE, Boolean.TRUE).handler(new ChannelInitializer<SocketChannel>() {
243                 @Override
244                 protected void initChannel(final SocketChannel ch) {
245                     initializer.initializeChannel(ch, p);
246                 }
247             });
248
249             setWorkerGroup(b);
250             setChannelFactory(b);
251             p.connect();
252             return p;
253         }
254
255         private static void setChannelFactory(final Bootstrap b) {
256             try {
257                 b.channel(NioSocketChannel.class);
258             } catch (final IllegalStateException ignored) {
259             }
260         }
261
262         private void setWorkerGroup(final Bootstrap b) {
263             if (b.config().group() == null) {
264                 b.group(this.workerGroup);
265             }
266         }
267     }
268
269 }