Merge "Initial message bus implementation"
[controller.git] / opendaylight / netconf / netconf-it / src / test / java / org / opendaylight / controller / netconf / it / AbstractNetconfConfigTest.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 package org.opendaylight.controller.netconf.it;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.mockito.Matchers.any;
13 import static org.mockito.Matchers.anySetOf;
14 import static org.mockito.Matchers.anyString;
15 import static org.mockito.Mockito.doNothing;
16 import static org.mockito.Mockito.doReturn;
17 import static org.mockito.Mockito.mock;
18
19 import io.netty.channel.Channel;
20 import io.netty.channel.ChannelFuture;
21 import io.netty.channel.EventLoopGroup;
22 import io.netty.channel.local.LocalAddress;
23 import io.netty.channel.nio.NioEventLoopGroup;
24 import io.netty.util.HashedWheelTimer;
25 import io.netty.util.concurrent.GlobalEventExecutor;
26 import java.io.ByteArrayInputStream;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.net.InetSocketAddress;
30 import java.net.SocketAddress;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Collection;
34 import java.util.Collections;
35 import java.util.HashSet;
36 import java.util.List;
37 import java.util.concurrent.TimeUnit;
38 import org.apache.commons.io.IOUtils;
39 import org.junit.After;
40 import org.junit.Before;
41 import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
42 import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
43 import org.opendaylight.controller.config.spi.ModuleFactory;
44 import org.opendaylight.controller.config.yang.test.impl.DepTestImplModuleFactory;
45 import org.opendaylight.controller.config.yang.test.impl.IdentityTestModuleFactory;
46 import org.opendaylight.controller.config.yang.test.impl.MultipleDependenciesModuleFactory;
47 import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
48 import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
49 import org.opendaylight.controller.netconf.api.NetconfMessage;
50 import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
51 import org.opendaylight.controller.netconf.client.SimpleNetconfClientSessionListener;
52 import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
53 import org.opendaylight.controller.netconf.client.conf.NetconfClientConfigurationBuilder;
54 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
55 import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreService;
56 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
57 import org.opendaylight.controller.netconf.impl.NetconfServerDispatcherImpl;
58 import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
59 import org.opendaylight.controller.netconf.impl.SessionIdProvider;
60 import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
61 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl;
62 import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshotImpl;
63 import org.opendaylight.controller.netconf.impl.osgi.SessionMonitoringService;
64 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
65 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
66 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
67 import org.opendaylight.controller.netconf.notifications.BaseNetconfNotificationListener;
68 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
69 import org.opendaylight.protocol.framework.NeverReconnectStrategy;
70 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange;
71 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
72 import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
73 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
74 import org.w3c.dom.Element;
75
76 public abstract class AbstractNetconfConfigTest extends AbstractConfigTest {
77
78     public static final String LOOPBACK_ADDRESS = "127.0.0.1";
79     public static final int SERVER_CONNECTION_TIMEOUT_MILLIS = 5000;
80     private static final int RESOURCE_TIMEOUT_MINUTES = 2;
81
82     static ModuleFactory[] FACTORIES = {new TestImplModuleFactory(),
83                                         new DepTestImplModuleFactory(),
84                                         new NetconfTestImplModuleFactory(),
85                                         new IdentityTestModuleFactory(),
86                                         new MultipleDependenciesModuleFactory() };
87
88     private EventLoopGroup nettyThreadgroup;
89     private HashedWheelTimer hashedWheelTimer;
90
91     private NetconfClientDispatcherImpl clientDispatcher;
92     private Channel serverTcpChannel;
93
94     private NetconfMessage getConfig;
95     private NetconfMessage get;
96
97     /**
98      * @Before in subclasses is called after this method.
99      */
100     @Before
101     public void setUpAbstractNetconfConfigTest() throws Exception {
102         super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(mockedContext, FACTORIES));
103
104         nettyThreadgroup = new NioEventLoopGroup();
105         hashedWheelTimer = new HashedWheelTimer();
106
107         loadMessages();
108
109         setUpTestInitial();
110
111         final NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
112         factoriesListener.onAddNetconfOperationServiceFactory(new NetconfOperationServiceFactoryImpl(getYangStore()));
113
114         for (final NetconfOperationServiceFactory netconfOperationServiceFactory : getAdditionalServiceFactories()) {
115             factoriesListener.onAddNetconfOperationServiceFactory(netconfOperationServiceFactory);
116         }
117
118         serverTcpChannel = startNetconfTcpServer(factoriesListener);
119         clientDispatcher = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
120     }
121
122     /**
123      * Called before setUp method is executed, so test classes can set up resources before setUpAbstractNetconfConfigTest method is called.
124      */
125     protected void setUpTestInitial() throws Exception {}
126
127     private void loadMessages() throws Exception {
128         this.getConfig = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
129         this.get = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/get.xml");
130     }
131
132     public NetconfMessage getGetConfig() {
133         return getConfig;
134     }
135
136     public NetconfMessage getGet() {
137         return get;
138     }
139
140     private Channel startNetconfTcpServer(final NetconfOperationServiceFactoryListenerImpl factoriesListener) throws Exception {
141         final NetconfServerDispatcherImpl dispatch = createDispatcher(factoriesListener, getNetconfMonitoringService(), getNotificationProducer());
142
143         final ChannelFuture s;
144         if(getTcpServerAddress() instanceof LocalAddress) {
145             s = dispatch.createLocalServer(((LocalAddress) getTcpServerAddress()));
146         } else {
147             s = dispatch.createServer(((InetSocketAddress) getTcpServerAddress()));
148         }
149         s.await(RESOURCE_TIMEOUT_MINUTES, TimeUnit.MINUTES);
150         return s.channel();
151     }
152
153     protected DefaultCommitNotificationProducer getNotificationProducer() {
154         final DefaultCommitNotificationProducer notificationProducer = mock(DefaultCommitNotificationProducer.class);
155         doNothing().when(notificationProducer).close();
156         doNothing().when(notificationProducer).sendCommitNotification(anyString(), any(Element.class), anySetOf(String.class));
157         return notificationProducer;
158     }
159
160     protected Iterable<NetconfOperationServiceFactory> getAdditionalServiceFactories() {
161         return Collections.emptySet();
162     }
163
164     protected SessionMonitoringService getNetconfMonitoringService() throws Exception {
165         final NetconfOperationProvider netconfOperationProvider = mock(NetconfOperationProvider.class);
166         final NetconfOperationServiceSnapshotImpl snap = mock(NetconfOperationServiceSnapshotImpl.class);
167         doReturn(Collections.<NetconfOperationService>emptySet()).when(snap).getServices();
168         doReturn(snap).when(netconfOperationProvider).openSnapshot(anyString());
169         return new NetconfMonitoringServiceImpl(netconfOperationProvider);
170     }
171
172     protected abstract SocketAddress getTcpServerAddress();
173
174     public NetconfClientDispatcherImpl getClientDispatcher() {
175         return clientDispatcher;
176     }
177
178     private HardcodedYangStoreService getYangStore() throws IOException {
179         final Collection<InputStream> yangDependencies = getBasicYangs();
180         return new HardcodedYangStoreService(yangDependencies);
181     }
182
183     static Collection<InputStream> getBasicYangs() throws IOException {
184
185         final List<String> paths = Arrays.asList(
186                 "/META-INF/yang/config.yang",
187                 "/META-INF/yang/rpc-context.yang",
188                 "/META-INF/yang/config-test.yang",
189                 "/META-INF/yang/config-test-impl.yang",
190                 "/META-INF/yang/test-types.yang",
191                 "/META-INF/yang/test-groups.yang",
192                 "/META-INF/yang/ietf-inet-types.yang");
193
194         final Collection<InputStream> yangDependencies = new ArrayList<>();
195         final List<String> failedToFind = new ArrayList<>();
196         for (final String path : paths) {
197             final InputStream resourceAsStream = NetconfITTest.class.getResourceAsStream(path);
198             if (resourceAsStream == null) {
199                 failedToFind.add(path);
200             } else {
201                 yangDependencies.add(resourceAsStream);
202             }
203         }
204         assertEquals("Some yang files were not found", Collections.<String>emptyList(), failedToFind);
205         return yangDependencies;
206     }
207
208     protected NetconfServerDispatcherImpl createDispatcher(
209             final NetconfOperationServiceFactoryListenerImpl factoriesListener, final SessionMonitoringService sessionMonitoringService,
210             final DefaultCommitNotificationProducer commitNotifier) {
211         final SessionIdProvider idProvider = new SessionIdProvider();
212
213         final NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
214                 hashedWheelTimer, factoriesListener, idProvider, SERVER_CONNECTION_TIMEOUT_MILLIS, commitNotifier, sessionMonitoringService);
215
216         final NetconfServerDispatcherImpl.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcherImpl.ServerChannelInitializer(
217                 serverNegotiatorFactory);
218         return new NetconfServerDispatcherImpl(serverChannelInitializer, nettyThreadgroup, nettyThreadgroup);
219     }
220
221     protected HashedWheelTimer getHashedWheelTimer() {
222         return hashedWheelTimer;
223     }
224
225     protected EventLoopGroup getNettyThreadgroup() {
226         return nettyThreadgroup;
227     }
228
229     /**
230      * @After in subclasses is be called before this.
231      */
232     @After
233     public void cleanUpNetconf() throws Exception {
234         serverTcpChannel.close().await(RESOURCE_TIMEOUT_MINUTES, TimeUnit.MINUTES);
235         hashedWheelTimer.stop();
236         nettyThreadgroup.shutdownGracefully().await(RESOURCE_TIMEOUT_MINUTES, TimeUnit.MINUTES);
237     }
238
239     public NetconfClientConfiguration getClientConfiguration(final InetSocketAddress tcpAddress, final int timeout) {
240         final NetconfClientConfigurationBuilder b = NetconfClientConfigurationBuilder.create();
241         b.withAddress(tcpAddress);
242         b.withSessionListener(new SimpleNetconfClientSessionListener());
243         b.withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, timeout));
244         b.withConnectionTimeoutMillis(timeout);
245         return b.build();
246     }
247
248     public static final class HardcodedYangStoreService extends YangStoreService {
249         public HardcodedYangStoreService(final Collection<? extends InputStream> inputStreams) throws IOException {
250             super(new SchemaContextProvider() {
251                 @Override
252                 public SchemaContext getSchemaContext() {
253                     return getSchema(inputStreams);
254                 }
255             }, new BaseNetconfNotificationListener() {
256                 @Override
257                 public void onCapabilityChanged(final NetconfCapabilityChange capabilityChange) {
258                     // NOOP
259                 }
260             });
261         }
262
263         private static SchemaContext getSchema(final Collection<? extends InputStream> inputStreams) {
264             final ArrayList<InputStream> byteArrayInputStreams = new ArrayList<>();
265             for (final InputStream inputStream : inputStreams) {
266                 assertNotNull(inputStream);
267                 final byte[] content;
268                 try {
269                     content = IOUtils.toByteArray(inputStream);
270                 } catch (IOException e) {
271                     throw new IllegalStateException("Cannot read " + inputStream, e);
272                 }
273                 final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(content);
274                 byteArrayInputStreams.add(byteArrayInputStream);
275             }
276
277             for (final InputStream inputStream : byteArrayInputStreams) {
278                 try {
279                     inputStream.reset();
280                 } catch (final IOException e) {
281                     throw new RuntimeException(e);
282                 }
283             }
284
285             final YangParserImpl yangParser = new YangParserImpl();
286             return yangParser.resolveSchemaContext(new HashSet<>(yangParser.parseYangModelsFromStreamsMapped(byteArrayInputStreams).values()));
287         }
288     }
289 }