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