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