Split up MessageTransformer
[netconf.git] / netconf / sal-netconf-connector / src / test / java / org / opendaylight / netconf / sal / connect / netconf / NetconfDeviceTest.java
1 /*
2  * Copyright (c) 2014, 2015 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.netconf.sal.connect.netconf;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.junit.Assert.assertTrue;
13 import static org.mockito.ArgumentMatchers.any;
14 import static org.mockito.ArgumentMatchers.anyCollection;
15 import static org.mockito.ArgumentMatchers.eq;
16 import static org.mockito.Mockito.after;
17 import static org.mockito.Mockito.doAnswer;
18 import static org.mockito.Mockito.doNothing;
19 import static org.mockito.Mockito.doReturn;
20 import static org.mockito.Mockito.mock;
21 import static org.mockito.Mockito.spy;
22 import static org.mockito.Mockito.timeout;
23 import static org.mockito.Mockito.times;
24 import static org.mockito.Mockito.verify;
25
26 import com.google.common.collect.ImmutableMultimap;
27 import com.google.common.collect.Iterables;
28 import com.google.common.collect.Lists;
29 import com.google.common.collect.Sets;
30 import com.google.common.util.concurrent.Futures;
31 import com.google.common.util.concurrent.ListeningExecutorService;
32 import com.google.common.util.concurrent.MoreExecutors;
33 import com.google.common.util.concurrent.SettableFuture;
34 import java.io.IOException;
35 import java.net.InetSocketAddress;
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.Collection;
39 import java.util.Collections;
40 import java.util.HashMap;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Set;
44 import java.util.concurrent.Executors;
45 import org.junit.Test;
46 import org.mockito.ArgumentCaptor;
47 import org.opendaylight.mdsal.dom.api.DOMNotification;
48 import org.opendaylight.mdsal.dom.api.DOMRpcResult;
49 import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
50 import org.opendaylight.netconf.api.NetconfMessage;
51 import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
52 import org.opendaylight.netconf.api.xml.XmlUtil;
53 import org.opendaylight.netconf.sal.connect.api.NetconfDeviceSchemasResolver;
54 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
55 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices;
56 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
57 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
58 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
59 import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
60 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability.CapabilityOrigin;
63 import org.opendaylight.yangtools.yang.common.QName;
64 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
65 import org.opendaylight.yangtools.yang.model.api.Module;
66 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
67 import org.opendaylight.yangtools.yang.model.repo.api.EffectiveModelContextFactory;
68 import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
69 import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
70 import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
71 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
72 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
73 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
74 import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
75 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
76 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
77 import org.xml.sax.SAXException;
78
79 public class NetconfDeviceTest extends AbstractTestModelTest {
80
81     private static final NetconfMessage NOTIFICATION;
82
83     private static final ContainerNode COMPOSITE_NODE = mockClass(ContainerNode.class);
84
85     static {
86         try {
87             NOTIFICATION = new NetconfMessage(XmlUtil
88                     .readXmlToDocument(NetconfDeviceTest.class.getResourceAsStream("/notification-payload.xml")));
89         } catch (SAXException | IOException e) {
90             throw new ExceptionInInitializerError(e);
91         }
92     }
93
94     private static final DOMRpcResult RPC_RESULT = new DefaultDOMRpcResult(COMPOSITE_NODE);
95
96     public static final String TEST_NAMESPACE = "test:namespace";
97     public static final String TEST_MODULE = "test-module";
98     public static final String TEST_REVISION = "2013-07-22";
99     public static final SourceIdentifier TEST_SID = new SourceIdentifier(TEST_MODULE, TEST_REVISION);
100     public static final String TEST_CAPABILITY =
101             TEST_NAMESPACE + "?module=" + TEST_MODULE + "&revision=" + TEST_REVISION;
102
103     public static final SourceIdentifier TEST_SID2 = new SourceIdentifier(TEST_MODULE + "2", TEST_REVISION);
104     public static final String TEST_CAPABILITY2 =
105             TEST_NAMESPACE + "?module=" + TEST_MODULE + "2" + "&revision=" + TEST_REVISION;
106
107     private static final NetconfDeviceSchemasResolver STATE_SCHEMAS_RESOLVER =
108         (deviceRpc, remoteSessionCapabilities, id, schemaContext) -> NetconfStateSchemas.EMPTY;
109
110
111     @Test
112     public void testNetconfDeviceFlawedModelFailedResolution() throws Exception {
113         final RemoteDeviceHandler facade = getFacade();
114         final NetconfDeviceCommunicator listener = getListener();
115
116         final EffectiveModelContextFactory schemaFactory = getSchemaFactory();
117         final SchemaRepository schemaRepository = getSchemaRepository();
118
119         final SchemaResolutionException schemaResolutionException =
120                 new SchemaResolutionException("fail first", TEST_SID, new Throwable("YangTools parser fail"));
121         doAnswer(invocation -> {
122             if (((Collection<?>) invocation.getArguments()[0]).size() == 2) {
123                 return Futures.immediateFailedFuture(schemaResolutionException);
124             } else {
125                 return Futures.immediateFuture(SCHEMA_CONTEXT);
126             }
127         }).when(schemaFactory).createEffectiveModelContext(anyCollection());
128
129         final NetconfDeviceSchemasResolver stateSchemasResolver = (deviceRpc, remoteSessionCapabilities, id,
130                 schemaContext) -> {
131             final Module first = Iterables.getFirst(SCHEMA_CONTEXT.getModules(), null);
132             final QName qName = QName.create(first.getQNameModule(), first.getName());
133             final NetconfStateSchemas.RemoteYangSchema source1 = new NetconfStateSchemas.RemoteYangSchema(qName);
134             final NetconfStateSchemas.RemoteYangSchema source2 =
135                     new NetconfStateSchemas.RemoteYangSchema(QName.create(first.getQNameModule(), "test-module2"));
136             return new NetconfStateSchemas(Sets.newHashSet(source1, source2));
137         };
138
139         final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = new NetconfDevice
140                 .SchemaResourcesDTO(getSchemaRegistry(), schemaRepository, schemaFactory, stateSchemasResolver);
141
142         final NetconfDevice device = new NetconfDeviceBuilder()
143                 .setReconnectOnSchemasChange(true)
144                 .setSchemaResourcesDTO(schemaResourcesDTO)
145                 .setGlobalProcessingExecutor(getExecutor())
146                 .setId(getId())
147                 .setSalFacade(facade)
148                 .setBaseSchemas(BASE_SCHEMAS)
149                 .build();
150         // Monitoring supported
151         final NetconfSessionPreferences sessionCaps =
152                 getSessionCaps(true, Lists.newArrayList(TEST_CAPABILITY, TEST_CAPABILITY2));
153         device.onRemoteSessionUp(sessionCaps, listener);
154
155         verify(facade, timeout(5000)).onDeviceConnected(any(NetconfDeviceSchema.class),
156             any(NetconfSessionPreferences.class), any(RemoteDeviceServices.class));
157         verify(schemaFactory, times(2)).createEffectiveModelContext(anyCollection());
158     }
159
160     @Test
161     public void testNetconfDeviceFailFirstSchemaFailSecondEmpty() throws Exception {
162         final ArrayList<String> capList = Lists.newArrayList(TEST_CAPABILITY);
163
164         final RemoteDeviceHandler facade = getFacade();
165         final NetconfDeviceCommunicator listener = getListener();
166
167         final EffectiveModelContextFactory schemaFactory = getSchemaFactory();
168         final SchemaRepository schemaRepository = getSchemaRepository();
169
170         // Make fallback attempt to fail due to empty resolved sources
171         final SchemaResolutionException schemaResolutionException = new SchemaResolutionException("fail first",
172                 List.of(), ImmutableMultimap.of());
173         doReturn(Futures.immediateFailedFuture(schemaResolutionException))
174                 .when(schemaFactory).createEffectiveModelContext(anyCollection());
175
176         final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = new NetconfDevice
177                 .SchemaResourcesDTO(getSchemaRegistry(), schemaRepository, schemaFactory, STATE_SCHEMAS_RESOLVER);
178         final NetconfDevice device = new NetconfDeviceBuilder()
179                 .setReconnectOnSchemasChange(true)
180                 .setSchemaResourcesDTO(schemaResourcesDTO)
181                 .setGlobalProcessingExecutor(getExecutor())
182                 .setId(getId())
183                 .setSalFacade(facade)
184                 .setBaseSchemas(BASE_SCHEMAS)
185                 .build();
186
187         // Monitoring not supported
188         final NetconfSessionPreferences sessionCaps = getSessionCaps(false, capList);
189         device.onRemoteSessionUp(sessionCaps, listener);
190
191         verify(facade, timeout(5000)).onDeviceDisconnected();
192         verify(listener, timeout(5000)).close();
193         verify(schemaFactory, times(1)).createEffectiveModelContext(anyCollection());
194     }
195
196     @Test
197     public void testNetconfDeviceMissingSource() throws Exception {
198         final RemoteDeviceHandler facade = getFacade();
199         final NetconfDeviceCommunicator listener = getListener();
200
201         final EffectiveModelContextFactory schemaFactory = getSchemaFactory();
202         final SchemaRepository schemaRepository = getSchemaRepository();
203
204         // Make fallback attempt to fail due to empty resolved sources
205         final MissingSchemaSourceException schemaResolutionException =
206                 new MissingSchemaSourceException("fail first", TEST_SID);
207         doReturn(Futures.immediateFailedFuture(schemaResolutionException))
208                 .when(schemaRepository).getSchemaSource(eq(TEST_SID), eq(YangTextSchemaSource.class));
209         doAnswer(invocation -> {
210             if (((Collection<?>) invocation.getArguments()[0]).size() == 2) {
211                 return Futures.immediateFailedFuture(schemaResolutionException);
212             } else {
213                 return Futures.immediateFuture(SCHEMA_CONTEXT);
214             }
215         }).when(schemaFactory).createEffectiveModelContext(anyCollection());
216
217         final NetconfDeviceSchemasResolver stateSchemasResolver = (deviceRpc, remoteSessionCapabilities, id,
218             schemaContext) -> {
219             final Module first = Iterables.getFirst(SCHEMA_CONTEXT.getModules(), null);
220             final QName qName = QName.create(first.getQNameModule(), first.getName());
221             final NetconfStateSchemas.RemoteYangSchema source1 = new NetconfStateSchemas.RemoteYangSchema(qName);
222             final NetconfStateSchemas.RemoteYangSchema source2 =
223                     new NetconfStateSchemas.RemoteYangSchema(QName.create(first.getQNameModule(), "test-module2"));
224             return new NetconfStateSchemas(Sets.newHashSet(source1, source2));
225         };
226
227         final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = new NetconfDevice
228                 .SchemaResourcesDTO(getSchemaRegistry(), schemaRepository, schemaFactory, stateSchemasResolver);
229
230         final NetconfDevice device = new NetconfDeviceBuilder()
231                 .setReconnectOnSchemasChange(true)
232                 .setSchemaResourcesDTO(schemaResourcesDTO)
233                 .setGlobalProcessingExecutor(getExecutor())
234                 .setBaseSchemas(BASE_SCHEMAS)
235                 .setId(getId())
236                 .setSalFacade(facade)
237                 .build();
238         // Monitoring supported
239         final NetconfSessionPreferences sessionCaps =
240                 getSessionCaps(true, List.of(TEST_CAPABILITY, TEST_CAPABILITY2));
241         device.onRemoteSessionUp(sessionCaps, listener);
242
243         verify(facade, timeout(5000)).onDeviceConnected(any(NetconfDeviceSchema.class),
244             any(NetconfSessionPreferences.class), any(RemoteDeviceServices.class));
245         verify(schemaFactory, times(1)).createEffectiveModelContext(anyCollection());
246     }
247
248     private static SchemaSourceRegistry getSchemaRegistry() {
249         final SchemaSourceRegistry mock = mock(SchemaSourceRegistry.class);
250         final SchemaSourceRegistration<?> mockReg = mock(SchemaSourceRegistration.class);
251         doNothing().when(mockReg).close();
252         doReturn(mockReg).when(mock).registerSchemaSource(
253                 any(org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider.class),
254                 any(PotentialSchemaSource.class));
255         return mock;
256     }
257
258     private static SchemaRepository getSchemaRepository() {
259         final SchemaRepository mock = mock(SchemaRepository.class);
260         final SchemaSourceRepresentation mockRep = mock(SchemaSourceRepresentation.class);
261         doReturn(Futures.immediateFuture(mockRep))
262                 .when(mock).getSchemaSource(any(SourceIdentifier.class), eq(YangTextSchemaSource.class));
263         return mock;
264     }
265
266     @Test
267     public void testNotificationBeforeSchema() throws Exception {
268         final RemoteDeviceHandler facade = getFacade();
269         final NetconfDeviceCommunicator listener = getListener();
270         final EffectiveModelContextFactory schemaContextProviderFactory = mock(EffectiveModelContextFactory.class);
271         final SettableFuture<SchemaContext> schemaFuture = SettableFuture.create();
272         doReturn(schemaFuture).when(schemaContextProviderFactory).createEffectiveModelContext(any(Collection.class));
273         final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO =
274                 new NetconfDevice.SchemaResourcesDTO(getSchemaRegistry(), getSchemaRepository(),
275                         schemaContextProviderFactory, STATE_SCHEMAS_RESOLVER);
276         final NetconfDevice device = new NetconfDeviceBuilder()
277                 .setReconnectOnSchemasChange(true)
278                 .setSchemaResourcesDTO(schemaResourcesDTO)
279                 .setGlobalProcessingExecutor(getExecutor())
280                 .setId(getId())
281                 .setSalFacade(facade)
282                 .setBaseSchemas(BASE_SCHEMAS)
283                 .build();
284
285         final NetconfSessionPreferences sessionCaps = getSessionCaps(true,
286                 Lists.newArrayList(TEST_CAPABILITY));
287         device.onRemoteSessionUp(sessionCaps, listener);
288
289         device.onNotification(NOTIFICATION);
290         device.onNotification(NOTIFICATION);
291         verify(facade, times(0)).onNotification(any(DOMNotification.class));
292
293         verify(facade, times(0)).onNotification(any(DOMNotification.class));
294         schemaFuture.set(NetconfToNotificationTest.getNotificationSchemaContext(getClass(), false));
295         verify(facade, timeout(10000).times(2)).onNotification(any(DOMNotification.class));
296
297         device.onNotification(NOTIFICATION);
298         verify(facade, timeout(10000).times(3)).onNotification(any(DOMNotification.class));
299     }
300
301     @Test
302     public void testNetconfDeviceReconnect() throws Exception {
303         final RemoteDeviceHandler facade = getFacade();
304         final NetconfDeviceCommunicator listener = getListener();
305
306         final EffectiveModelContextFactory schemaContextProviderFactory = getSchemaFactory();
307
308         final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = new NetconfDevice.SchemaResourcesDTO(
309                 getSchemaRegistry(), getSchemaRepository(), schemaContextProviderFactory, STATE_SCHEMAS_RESOLVER);
310         final NetconfDevice device = new NetconfDeviceBuilder()
311                 .setReconnectOnSchemasChange(true)
312                 .setSchemaResourcesDTO(schemaResourcesDTO)
313                 .setGlobalProcessingExecutor(getExecutor())
314                 .setId(getId())
315                 .setSalFacade(facade)
316                 .setBaseSchemas(BASE_SCHEMAS)
317                 .build();
318         final NetconfSessionPreferences sessionCaps = getSessionCaps(true,
319                 Lists.newArrayList(TEST_NAMESPACE + "?module=" + TEST_MODULE + "&amp;revision=" + TEST_REVISION));
320         device.onRemoteSessionUp(sessionCaps, listener);
321
322         verify(schemaContextProviderFactory, timeout(5000)).createEffectiveModelContext(any(Collection.class));
323         verify(facade, timeout(5000)).onDeviceConnected(
324                 any(NetconfDeviceSchema.class), any(NetconfSessionPreferences.class), any(RemoteDeviceServices.class));
325
326         device.onRemoteSessionDown();
327         verify(facade, timeout(5000)).onDeviceDisconnected();
328
329         device.onRemoteSessionUp(sessionCaps, listener);
330
331         verify(schemaContextProviderFactory, timeout(5000).times(2)).createEffectiveModelContext(any(Collection.class));
332         verify(facade, timeout(5000).times(2)).onDeviceConnected(
333                 any(NetconfDeviceSchema.class), any(NetconfSessionPreferences.class), any(RemoteDeviceServices.class));
334     }
335
336     @Test
337     public void testNetconfDeviceDisconnectListenerCallCancellation() throws Exception {
338         final RemoteDeviceHandler facade = getFacade();
339         final NetconfDeviceCommunicator listener = getListener();
340         final EffectiveModelContextFactory schemaContextProviderFactory = mock(EffectiveModelContextFactory.class);
341         final SettableFuture<SchemaContext> schemaFuture = SettableFuture.create();
342         doReturn(schemaFuture).when(schemaContextProviderFactory).createEffectiveModelContext(any(Collection.class));
343         final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO
344                 = new NetconfDevice.SchemaResourcesDTO(getSchemaRegistry(), getSchemaRepository(),
345                 schemaContextProviderFactory, STATE_SCHEMAS_RESOLVER);
346         final NetconfDevice device = new NetconfDeviceBuilder()
347                 .setReconnectOnSchemasChange(true)
348                 .setSchemaResourcesDTO(schemaResourcesDTO)
349                 .setGlobalProcessingExecutor(getExecutor())
350                 .setId(getId())
351                 .setSalFacade(facade)
352                 .setBaseSchemas(BASE_SCHEMAS)
353                 .build();
354         final NetconfSessionPreferences sessionCaps = getSessionCaps(true,
355                 Lists.newArrayList(TEST_NAMESPACE + "?module=" + TEST_MODULE + "&amp;revision=" + TEST_REVISION));
356         //session up, start schema resolution
357         device.onRemoteSessionUp(sessionCaps, listener);
358         //session closed
359         device.onRemoteSessionDown();
360         verify(facade, timeout(5000)).onDeviceDisconnected();
361         //complete schema setup
362         schemaFuture.set(SCHEMA_CONTEXT);
363         //facade.onDeviceDisconnected() was called, so facade.onDeviceConnected() shouldn't be called anymore
364         verify(facade, after(1000).never()).onDeviceConnected(any(), any(), any(RemoteDeviceServices.class));
365     }
366
367     @Test
368     public void testNetconfDeviceAvailableCapabilitiesBuilding() throws Exception {
369         final RemoteDeviceHandler facade = getFacade();
370         final NetconfDeviceCommunicator listener = getListener();
371
372         final EffectiveModelContextFactory schemaContextProviderFactory = getSchemaFactory();
373
374         final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = new NetconfDevice.SchemaResourcesDTO(
375                 getSchemaRegistry(), getSchemaRepository(), schemaContextProviderFactory, STATE_SCHEMAS_RESOLVER);
376         final NetconfDevice device = new NetconfDeviceBuilder()
377                 .setReconnectOnSchemasChange(true)
378                 .setSchemaResourcesDTO(schemaResourcesDTO)
379                 .setGlobalProcessingExecutor(getExecutor())
380                 .setId(getId())
381                 .setSalFacade(facade)
382                 .setBaseSchemas(BASE_SCHEMAS)
383                 .build();
384         final NetconfDevice netconfSpy = spy(device);
385
386         final NetconfSessionPreferences sessionCaps = getSessionCaps(true,
387                 Lists.newArrayList(TEST_NAMESPACE + "?module=" + TEST_MODULE + "&amp;revision=" + TEST_REVISION));
388         final Map<QName, CapabilityOrigin> moduleBasedCaps = new HashMap<>();
389         moduleBasedCaps.putAll(sessionCaps.moduleBasedCaps());
390         moduleBasedCaps
391                 .put(QName.create("(test:qname:side:loading)test"), CapabilityOrigin.UserDefined);
392
393         netconfSpy.onRemoteSessionUp(sessionCaps.replaceModuleCaps(moduleBasedCaps), listener);
394
395         final ArgumentCaptor<NetconfDeviceSchema> argument =  ArgumentCaptor.forClass(NetconfDeviceSchema.class);
396         verify(facade, timeout(5000)).onDeviceConnected(argument.capture(), any(NetconfSessionPreferences.class),
397             any(RemoteDeviceServices.class));
398         argument.getValue().capabilities().resolvedCapabilities()
399                 .forEach(entry -> assertEquals("Builded 'AvailableCapability' schemas should match input capabilities.",
400                         moduleBasedCaps.get(
401                                 QName.create(entry.getCapability())).getName(), entry.getCapabilityOrigin().getName()));
402     }
403
404     @Test
405     public void testNetconfDeviceNotificationsModelNotPresentWithCapability() throws Exception {
406         final RemoteDeviceHandler facade = getFacade();
407         final NetconfDeviceCommunicator listener = getListener();
408         final EffectiveModelContextFactory schemaContextProviderFactory = getSchemaFactory();
409
410         final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = new NetconfDevice.SchemaResourcesDTO(
411                 getSchemaRegistry(), getSchemaRepository(), schemaContextProviderFactory, STATE_SCHEMAS_RESOLVER);
412         final NetconfDevice device = new NetconfDeviceBuilder()
413                 .setSchemaResourcesDTO(schemaResourcesDTO)
414                 .setGlobalProcessingExecutor(getExecutor())
415                 .setId(getId())
416                 .setSalFacade(facade)
417                 .setBaseSchemas(BASE_SCHEMAS)
418                 .build();
419         final NetconfDevice netconfSpy = spy(device);
420
421         final NetconfSessionPreferences sessionCaps = getSessionCaps(false,
422                 Lists.newArrayList(XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_CAPABILITY_NOTIFICATION_1_0));
423
424         netconfSpy.onRemoteSessionUp(sessionCaps, listener);
425
426         final ArgumentCaptor<NetconfDeviceSchema> argument = ArgumentCaptor.forClass(NetconfDeviceSchema.class);
427         verify(facade, timeout(5000)).onDeviceConnected(argument.capture(), any(NetconfSessionPreferences.class),
428                 any(RemoteDeviceServices.class));
429
430         List<String> notificationModulesName = Arrays.asList(
431                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714
432                         .$YangModuleInfoImpl.getInstance().getName().toString(),
433                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715
434                         .$YangModuleInfoImpl.getInstance().getName().toString());
435
436         final Set<AvailableCapability> resolvedCapabilities = argument.getValue().capabilities().resolvedCapabilities();
437
438         assertEquals(2, resolvedCapabilities.size());
439         assertTrue(resolvedCapabilities.stream().anyMatch(entry -> notificationModulesName
440                 .contains(entry.getCapability())));
441     }
442
443     @Test
444     public void testNetconfDeviceNotificationsCapabilityIsNotPresent() throws Exception {
445         final RemoteDeviceHandler facade = getFacade();
446         final NetconfDeviceCommunicator listener = getListener();
447         final EffectiveModelContextFactory schemaContextProviderFactory = getSchemaFactory();
448
449         final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = new NetconfDevice.SchemaResourcesDTO(
450                 getSchemaRegistry(), getSchemaRepository(), schemaContextProviderFactory, STATE_SCHEMAS_RESOLVER);
451         final NetconfDevice device = new NetconfDeviceBuilder()
452                 .setSchemaResourcesDTO(schemaResourcesDTO)
453                 .setGlobalProcessingExecutor(getExecutor())
454                 .setId(getId())
455                 .setSalFacade(facade)
456                 .setBaseSchemas(BASE_SCHEMAS)
457                 .build();
458         final NetconfDevice netconfSpy = spy(device);
459
460         final NetconfSessionPreferences sessionCaps = getSessionCaps(false,
461                 Lists.newArrayList(TEST_NAMESPACE + "?module=" + TEST_MODULE + "&amp;revision=" + TEST_REVISION));
462
463         netconfSpy.onRemoteSessionUp(sessionCaps, listener);
464
465         final ArgumentCaptor<NetconfDeviceSchema> argument = ArgumentCaptor.forClass(NetconfDeviceSchema.class);
466         verify(facade, timeout(5000)).onDeviceConnected(argument.capture(), any(NetconfSessionPreferences.class),
467                 any(RemoteDeviceServices.class));
468         final NetconfDeviceCapabilities netconfDeviceCaps = argument.getValue().capabilities();
469
470         List<String> notificationModulesName = List.of(
471                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714
472                         .$YangModuleInfoImpl.getInstance().getName().toString(),
473                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715
474                         .$YangModuleInfoImpl.getInstance().getName().toString());
475
476         assertFalse(netconfDeviceCaps.resolvedCapabilities().stream()
477             .anyMatch(entry -> notificationModulesName.contains(entry.getCapability())));
478     }
479
480     @Test
481     public void testNetconfDeviceNotificationsModelIsPresent() throws Exception {
482         final RemoteDeviceHandler facade = getFacade();
483         final NetconfDeviceCommunicator listener = getListener();
484         final EffectiveModelContextFactory schemaContextProviderFactory = getSchemaFactory();
485
486         final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = new NetconfDevice.SchemaResourcesDTO(
487                 getSchemaRegistry(), getSchemaRepository(), schemaContextProviderFactory, STATE_SCHEMAS_RESOLVER);
488         final NetconfDevice device = new NetconfDeviceBuilder()
489                 .setSchemaResourcesDTO(schemaResourcesDTO)
490                 .setGlobalProcessingExecutor(getExecutor())
491                 .setId(getId())
492                 .setSalFacade(facade)
493                 .setBaseSchemas(BASE_SCHEMAS)
494                 .build();
495         final NetconfDevice netconfSpy = spy(device);
496
497         final NetconfSessionPreferences sessionCaps = getSessionCaps(false, Collections.emptyList());
498
499         final Map<QName, CapabilityOrigin> moduleBasedCaps = new HashMap<>();
500         moduleBasedCaps.put(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714
501                         .$YangModuleInfoImpl.getInstance().getName(),
502                 CapabilityOrigin.DeviceAdvertised);
503         moduleBasedCaps.put(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715
504                         .$YangModuleInfoImpl.getInstance().getName(),
505                 CapabilityOrigin.DeviceAdvertised);
506
507
508         netconfSpy.onRemoteSessionUp(sessionCaps.replaceModuleCaps(moduleBasedCaps), listener);
509
510         final ArgumentCaptor<NetconfDeviceSchema> argument = ArgumentCaptor.forClass(NetconfDeviceSchema.class);
511         verify(facade, timeout(5000)).onDeviceConnected(argument.capture(), any(NetconfSessionPreferences.class),
512                 any(RemoteDeviceServices.class));
513         final Set<AvailableCapability> resolvedCapabilities = argument.getValue().capabilities().resolvedCapabilities();
514
515         List<String> notificationModulesName = List.of(
516                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714
517                         .$YangModuleInfoImpl.getInstance().getName().toString(),
518                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715
519                         .$YangModuleInfoImpl.getInstance().getName().toString());
520
521         assertEquals(2, resolvedCapabilities.size());
522         assertTrue(resolvedCapabilities.stream().anyMatch(entry -> notificationModulesName
523                 .contains(entry.getCapability())));
524     }
525
526     private static EffectiveModelContextFactory getSchemaFactory() throws Exception {
527         final EffectiveModelContextFactory schemaFactory = mockClass(EffectiveModelContextFactory.class);
528         doReturn(Futures.immediateFuture(SCHEMA_CONTEXT))
529                 .when(schemaFactory).createEffectiveModelContext(any(Collection.class));
530         return schemaFactory;
531     }
532
533     private static RemoteDeviceHandler getFacade() throws Exception {
534         final RemoteDeviceHandler remoteDeviceHandler = mockCloseableClass(RemoteDeviceHandler.class);
535         doNothing().when(remoteDeviceHandler).onDeviceConnected(
536                 any(NetconfDeviceSchema.class), any(NetconfSessionPreferences.class), any(RemoteDeviceServices.class));
537         doNothing().when(remoteDeviceHandler).onDeviceDisconnected();
538         doNothing().when(remoteDeviceHandler).onNotification(any(DOMNotification.class));
539         return remoteDeviceHandler;
540     }
541
542     private static <T extends AutoCloseable> T mockCloseableClass(final Class<T> remoteDeviceHandlerClass)
543             throws Exception {
544         final T mock = mockClass(remoteDeviceHandlerClass);
545         doNothing().when(mock).close();
546         return mock;
547     }
548
549     private static <T> T mockClass(final Class<T> remoteDeviceHandlerClass) {
550         final T mock = mock(remoteDeviceHandlerClass);
551         doReturn(remoteDeviceHandlerClass.getSimpleName()).when(mock).toString();
552         return mock;
553     }
554
555     public RemoteDeviceId getId() {
556         return new RemoteDeviceId("test-D", InetSocketAddress.createUnresolved("localhost", 22));
557     }
558
559     public ListeningExecutorService getExecutor() {
560         return MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
561     }
562
563     public NetconfSessionPreferences getSessionCaps(final boolean addMonitor,
564                                                     final Collection<String> additionalCapabilities) {
565         final ArrayList<String> capabilities = Lists.newArrayList(
566                 XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0,
567                 XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_1);
568
569         if (addMonitor) {
570             capabilities.add(NetconfMessageTransformUtil.IETF_NETCONF_MONITORING.getNamespace().toString());
571         }
572
573         capabilities.addAll(additionalCapabilities);
574
575         return NetconfSessionPreferences.fromStrings(
576                 capabilities);
577     }
578
579     public NetconfDeviceCommunicator getListener() throws Exception {
580         final NetconfDeviceCommunicator remoteDeviceCommunicator = mockCloseableClass(NetconfDeviceCommunicator.class);
581 //        doReturn(Futures.immediateFuture(rpcResult))
582 //                .when(remoteDeviceCommunicator).sendRequest(any(NetconfMessage.class), any(QName.class));
583         return remoteDeviceCommunicator;
584     }
585 }