121a826f793ebd0312ab34ed5fb5459e89bc120b
[controller.git] / opendaylight / netconf / netconf-impl / src / test / java / org / opendaylight / controller / netconf / impl / ConcurrentClientsTest.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.netconf.impl;
10
11 import com.google.common.base.Optional;
12 import com.google.common.collect.Sets;
13 import io.netty.channel.ChannelFuture;
14 import io.netty.util.HashedWheelTimer;
15 import org.apache.commons.io.IOUtils;
16 import org.junit.After;
17 import org.junit.Before;
18 import org.junit.Test;
19 import org.mockito.Mock;
20 import org.mockito.MockitoAnnotations;
21 import org.opendaylight.controller.config.util.ConfigRegistryJMXClient;
22 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
23 import org.opendaylight.controller.config.yang.store.api.YangStoreService;
24 import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
25 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
26 import org.opendaylight.controller.netconf.api.NetconfMessage;
27 import org.opendaylight.controller.netconf.api.NetconfOperationRouter;
28 import org.opendaylight.controller.netconf.client.NetconfClient;
29 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
30 import org.opendaylight.controller.netconf.mapping.api.Capability;
31 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
32 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
33 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationFilter;
34 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
35 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
36 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
37 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40 import org.w3c.dom.Document;
41
42 import javax.management.ObjectName;
43 import javax.net.ssl.SSLContext;
44 import java.io.DataOutputStream;
45 import java.io.InputStream;
46 import java.io.InputStreamReader;
47 import java.lang.management.ManagementFactory;
48 import java.net.InetSocketAddress;
49 import java.net.Socket;
50 import java.util.ArrayList;
51 import java.util.Collections;
52 import java.util.List;
53 import java.util.Set;
54 import java.util.concurrent.TimeUnit;
55
56 import static com.google.common.base.Preconditions.checkNotNull;
57 import static org.junit.Assert.assertTrue;
58 import static org.mockito.Matchers.any;
59 import static org.mockito.Mockito.doReturn;
60 import static org.mockito.Mockito.mock;
61
62 public class ConcurrentClientsTest {
63
64     private static final int CONCURRENCY = 16;
65     @Mock
66     private YangStoreService yangStoreService;
67     @Mock
68     private ConfigRegistryJMXClient jmxClient;
69
70     private final InetSocketAddress netconfAddress = new InetSocketAddress("127.0.0.1", 8303);
71
72     static final Logger logger = LoggerFactory.getLogger(ConcurrentClientsTest.class);
73
74     private DefaultCommitNotificationProducer commitNot;
75     private NetconfServerDispatcher dispatch;
76
77     @Before
78     public void setUp() throws Exception {
79         { // init mocks
80             MockitoAnnotations.initMocks(this);
81             final YangStoreSnapshot yStore = mock(YangStoreSnapshot.class);
82             doReturn(yStore).when(this.yangStoreService).getYangStoreSnapshot();
83             doReturn(Collections.emptyMap()).when(yStore).getModuleMXBeanEntryMap();
84             doReturn(Collections.emptyMap()).when(yStore).getModuleMap();
85
86             final ConfigTransactionJMXClient mockedTCl = mock(ConfigTransactionJMXClient.class);
87             doReturn(mockedTCl).when(this.jmxClient).getConfigTransactionClient(any(ObjectName.class));
88
89             doReturn(Collections.emptySet()).when(jmxClient).lookupConfigBeans();
90         }
91
92         NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
93         factoriesListener.onAddNetconfOperationServiceFactory(mockOpF());
94
95         SessionIdProvider idProvider = new SessionIdProvider();
96         NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
97                 new HashedWheelTimer(5000, TimeUnit.MILLISECONDS), factoriesListener, idProvider);
98
99         commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
100
101         NetconfServerSessionListenerFactory listenerFactory = new NetconfServerSessionListenerFactory(
102                 factoriesListener, commitNot, idProvider);
103         dispatch = new NetconfServerDispatcher(Optional.<SSLContext> absent(), serverNegotiatorFactory, listenerFactory);
104
105         ChannelFuture s = dispatch.createServer(netconfAddress);
106         s.await();
107     }
108
109     private NetconfOperationServiceFactory mockOpF() {
110         return new NetconfOperationServiceFactory() {
111             @Override
112             public NetconfOperationService createService(long netconfSessionId, String netconfSessionIdForReporting) {
113                 return new NetconfOperationService() {
114                     @Override
115                     public Set<Capability> getCapabilities() {
116                         return Collections.emptySet();
117                     }
118
119                     @Override
120                     public Set<NetconfOperation> getNetconfOperations() {
121                         return Sets.<NetconfOperation> newHashSet(new NetconfOperation() {
122                             @Override
123                             public HandlingPriority canHandle(Document message) {
124                                 return HandlingPriority.getHandlingPriority(Integer.MAX_VALUE);
125                             }
126
127                             @Override
128                             public Document handle(Document message, NetconfOperationRouter operationRouter)
129                                     throws NetconfDocumentedException {
130                                 try {
131                                     return XmlUtil.readXmlToDocument("<test/>");
132                                 } catch (Exception e) {
133                                     throw new RuntimeException(e);
134                                 }
135                             }
136                         });
137                     }
138
139                     @Override
140                     public Set<NetconfOperationFilter> getFilters() {
141                         return Collections.emptySet();
142                     }
143
144                     @Override
145                     public void close() {
146                     }
147                 };
148             }
149         };
150     }
151
152     @After
153     public void cleanUp() throws Exception {
154         commitNot.close();
155         dispatch.close();
156     }
157
158     @Test
159     public void multipleClients() throws Exception {
160         List<TestingThread> threads = new ArrayList<>();
161
162         final int attempts = 5;
163         for (int i = 0; i < CONCURRENCY; i++) {
164             TestingThread thread = new TestingThread(String.valueOf(i), attempts);
165             threads.add(thread);
166             thread.start();
167         }
168
169         for (TestingThread thread : threads) {
170             thread.join();
171             assertTrue(thread.success);
172         }
173     }
174
175     @Test
176     public void synchronizationTest() throws Exception {
177         new BlockingThread("foo").run2();
178     }
179
180     @Test
181     public void multipleBlockingClients() throws Exception {
182         List<BlockingThread> threads = new ArrayList<>();
183         for (int i = 0; i < CONCURRENCY; i++) {
184             BlockingThread thread = new BlockingThread(String.valueOf(i));
185             threads.add(thread);
186             thread.start();
187         }
188
189         for (BlockingThread thread : threads) {
190             thread.join();
191             assertTrue(thread.success);
192         }
193     }
194
195     class BlockingThread extends Thread {
196         Boolean success;
197
198         public BlockingThread(String name) {
199             super("client-" + name);
200         }
201
202         @Override
203         public void run() {
204             try {
205                 run2();
206                 success = true;
207             } catch (Exception e) {
208                 success = false;
209                 throw new RuntimeException(e);
210             }
211         }
212
213         private void run2() throws Exception {
214             InputStream clientHello = checkNotNull(XmlFileLoader
215                     .getResourceAsStream("netconfMessages/client_hello.xml"));
216             InputStream getConfig = checkNotNull(XmlFileLoader.getResourceAsStream("netconfMessages/getConfig.xml"));
217
218             Socket clientSocket = new Socket(netconfAddress.getHostString(), netconfAddress.getPort());
219             DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
220             InputStreamReader inFromServer = new InputStreamReader(clientSocket.getInputStream());
221
222             StringBuffer sb = new StringBuffer();
223             while (sb.toString().endsWith("]]>]]>") == false) {
224                 sb.append((char) inFromServer.read());
225             }
226             logger.info(sb.toString());
227
228             outToServer.write(IOUtils.toByteArray(clientHello));
229             outToServer.write("]]>]]>".getBytes());
230             outToServer.flush();
231             // Thread.sleep(100);
232             outToServer.write(IOUtils.toByteArray(getConfig));
233             outToServer.write("]]>]]>".getBytes());
234             outToServer.flush();
235             Thread.sleep(100);
236             sb = new StringBuffer();
237             while (sb.toString().endsWith("]]>]]>") == false) {
238                 sb.append((char) inFromServer.read());
239             }
240             logger.info(sb.toString());
241             clientSocket.close();
242         }
243     }
244
245     class TestingThread extends Thread {
246
247         private final String clientId;
248         private final int attempts;
249         private Boolean success;
250
251         TestingThread(String clientId, int attempts) {
252             this.clientId = clientId;
253             this.attempts = attempts;
254             setName("client-" + clientId);
255         }
256
257         @Override
258         public void run() {
259             try {
260                 final NetconfClient netconfClient = new NetconfClient(clientId, netconfAddress);
261                 long sessionId = netconfClient.getSessionId();
262                 logger.info("Client with sessionid {} hello exchanged", sessionId);
263
264                 final NetconfMessage getMessage = XmlFileLoader
265                         .xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
266                 NetconfMessage result = netconfClient.sendMessage(getMessage);
267                 logger.info("Client with sessionid {} got result {}", sessionId, result);
268                 netconfClient.close();
269                 logger.info("Client with session id {} ended", sessionId);
270                 success = true;
271             } catch (final Exception e) {
272                 success = false;
273                 throw new RuntimeException(e);
274             }
275         }
276     }
277 }