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