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