d2e1be0558302049a533f8b914a415ead4a375e0
[netconf.git] / plugins / netconf-client-mdsal / src / test / java / org / opendaylight / netconf / client / mdsal / impl / SchemaSetupTest.java
1 /*
2  * Copyright (c) 2024 PANTHEON.tech, s.r.o. 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.impl;
9
10 import static org.junit.jupiter.api.Assertions.assertEquals;
11 import static org.junit.jupiter.api.Assertions.assertSame;
12 import static org.mockito.ArgumentMatchers.any;
13 import static org.mockito.ArgumentMatchers.anyCollection;
14 import static org.mockito.ArgumentMatchers.eq;
15 import static org.mockito.Mockito.doAnswer;
16 import static org.mockito.Mockito.doReturn;
17 import static org.mockito.Mockito.times;
18 import static org.mockito.Mockito.verify;
19
20 import com.google.common.util.concurrent.Futures;
21 import java.net.InetSocketAddress;
22 import java.util.Collection;
23 import java.util.List;
24 import java.util.Set;
25 import org.junit.jupiter.api.Test;
26 import org.junit.jupiter.api.extension.ExtendWith;
27 import org.mockito.ArgumentCaptor;
28 import org.mockito.Mock;
29 import org.mockito.junit.jupiter.MockitoExtension;
30 import org.opendaylight.netconf.client.mdsal.AbstractTestModelTest;
31 import org.opendaylight.netconf.client.mdsal.api.NetconfSessionPreferences;
32 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev240120.connection.oper.available.capabilities.AvailableCapability.CapabilityOrigin;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev240120.connection.oper.available.capabilities.AvailableCapabilityBuilder;
35 import org.opendaylight.yangtools.yang.common.QName;
36 import org.opendaylight.yangtools.yang.model.api.source.SourceIdentifier;
37 import org.opendaylight.yangtools.yang.model.api.source.YangTextSource;
38 import org.opendaylight.yangtools.yang.model.repo.api.EffectiveModelContextFactory;
39 import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
40 import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
41 import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
42 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
43
44 @ExtendWith(MockitoExtension.class)
45 class SchemaSetupTest extends AbstractTestModelTest {
46     private static final RemoteDeviceId DEVICE_ID = new RemoteDeviceId("someDevice", new InetSocketAddress(42));
47     private static final String TEST_NAMESPACE = "test:namespace";
48     private static final String TEST_MODULE = "test-module";
49     private static final String TEST_REVISION = "2013-07-22";
50     private static final SourceIdentifier TEST_SID = new SourceIdentifier(TEST_MODULE, TEST_REVISION);
51     private static final SourceIdentifier TEST_SID2 = new SourceIdentifier(TEST_MODULE + "2", TEST_REVISION);
52     private static final QName TEST_QNAME = QName.create(TEST_NAMESPACE, TEST_REVISION, TEST_MODULE);
53     private static final QName TEST_QNAME2 = QName.create(TEST_NAMESPACE, TEST_REVISION, TEST_MODULE + "2");
54
55     @Mock
56     private EffectiveModelContextFactory contextFactory;
57     @Mock
58     private SchemaRepository schemaRepository;
59     @Mock
60     private SchemaSourceProvider<YangTextSource> sourceProvider;
61     @Mock
62     private YangTextSource source;
63
64     @Test
65     void testNetconfDeviceFlawedModelFailedResolution() throws Exception {
66         final var ex = new SchemaResolutionException("fail first", TEST_SID, new Throwable("YangTools parser fail"));
67         doAnswer(invocation -> invocation.getArgument(0, Collection.class).size() == 2
68             ? Futures.immediateFailedFuture(ex) : Futures.immediateFuture(SCHEMA_CONTEXT))
69             .when(contextFactory).createEffectiveModelContext(anyCollection());
70
71         doReturn(Futures.immediateFuture(source)).when(schemaRepository)
72             .getSchemaSource(any(), eq(YangTextSource.class));
73
74         final var setup = new SchemaSetup(schemaRepository, contextFactory, DEVICE_ID,
75             new DeviceSources(Set.of(TEST_QNAME, TEST_QNAME2), Set.of(TEST_QNAME, TEST_QNAME2), sourceProvider),
76             NetconfSessionPreferences.fromStrings(Set.of()));
77
78         final var result = Futures.getDone(setup.startResolution());
79         verify(contextFactory, times(2)).createEffectiveModelContext(anyCollection());
80         assertSame(SCHEMA_CONTEXT, result.modelContext());
81     }
82
83     @Test
84     void testNetconfDeviceMissingSource() throws Exception {
85         // Make fallback attempt to fail due to empty resolved sources
86         final var ex = new MissingSchemaSourceException(TEST_SID, "fail first");
87         doReturn(Futures.immediateFailedFuture(ex))
88                 .when(schemaRepository).getSchemaSource(TEST_SID, YangTextSource.class);
89         doReturn(Futures.immediateFuture(source)).when(schemaRepository)
90             .getSchemaSource(TEST_SID2, YangTextSource.class);
91         doReturn(Futures.immediateFuture(SCHEMA_CONTEXT)).when(contextFactory)
92             .createEffectiveModelContext(anyCollection());
93
94         final var setup = new SchemaSetup(schemaRepository, contextFactory, DEVICE_ID,
95             new DeviceSources(Set.of(TEST_QNAME, TEST_QNAME2), Set.of(TEST_QNAME, TEST_QNAME2), sourceProvider),
96             NetconfSessionPreferences.fromStrings(Set.of()));
97
98         final var result = Futures.getDone(setup.startResolution());
99         final var captor = ArgumentCaptor.forClass(Collection.class);
100         verify(contextFactory).createEffectiveModelContext(captor.capture());
101         assertEquals(List.of(TEST_SID2), captor.getValue());
102         assertSame(SCHEMA_CONTEXT, result.modelContext());
103     }
104
105     @Test
106     void testNetconfDeviceNotificationsCapabilityIsNotPresent() throws Exception {
107         doReturn(Futures.immediateFuture(source)).when(schemaRepository)
108             .getSchemaSource(any(), eq(YangTextSource.class));
109         doReturn(Futures.immediateFuture(SCHEMA_CONTEXT)).when(contextFactory)
110             .createEffectiveModelContext(anyCollection());
111
112         final var setup = new SchemaSetup(schemaRepository, contextFactory, DEVICE_ID,
113             new DeviceSources(Set.of(TEST_QNAME), Set.of(TEST_QNAME), sourceProvider),
114             NetconfSessionPreferences.fromStrings(
115                 Set.of(TEST_NAMESPACE + "?module=" + TEST_MODULE + "&amp;revision=" + TEST_REVISION)));
116
117         final var result = Futures.getDone(setup.startResolution());
118         assertEquals(Set.of(new AvailableCapabilityBuilder()
119             .setCapability("(test:namespace?revision=2013-07-22)test-module")
120             .setCapabilityOrigin(CapabilityOrigin.DeviceAdvertised)
121             .build()), result.capabilities().resolvedCapabilities());
122     }
123 }