2 * Copyright (c) 2024 PANTHEON.tech, s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.netconf.client.mdsal.impl;
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;
20 import com.google.common.util.concurrent.Futures;
21 import java.net.InetSocketAddress;
22 import java.util.Collection;
23 import java.util.List;
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.NetconfDeviceSchemas;
32 import org.opendaylight.netconf.client.mdsal.api.NetconfSessionPreferences;
33 import org.opendaylight.netconf.client.mdsal.api.ProvidedSources;
34 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev240120.connection.oper.available.capabilities.AvailableCapability.CapabilityOrigin;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev240120.connection.oper.available.capabilities.AvailableCapabilityBuilder;
37 import org.opendaylight.yangtools.yang.common.QName;
38 import org.opendaylight.yangtools.yang.model.api.source.SourceIdentifier;
39 import org.opendaylight.yangtools.yang.model.api.source.YangTextSource;
40 import org.opendaylight.yangtools.yang.model.api.stmt.FeatureSet;
41 import org.opendaylight.yangtools.yang.model.repo.api.EffectiveModelContextFactory;
42 import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
43 import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
44 import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
45 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
47 @ExtendWith(MockitoExtension.class)
48 class SchemaSetupTest extends AbstractTestModelTest {
49 private static final RemoteDeviceId DEVICE_ID = new RemoteDeviceId("someDevice", new InetSocketAddress(42));
50 private static final String TEST_NAMESPACE = "test:namespace";
51 private static final String TEST_MODULE = "test-module";
52 private static final String TEST_REVISION = "2013-07-22";
53 private static final SourceIdentifier TEST_SID = new SourceIdentifier(TEST_MODULE, TEST_REVISION);
54 private static final SourceIdentifier TEST_SID2 = new SourceIdentifier(TEST_MODULE + "2", TEST_REVISION);
55 private static final QName TEST_QNAME = QName.create(TEST_NAMESPACE, TEST_REVISION, TEST_MODULE);
56 private static final QName TEST_QNAME2 = QName.create(TEST_NAMESPACE, TEST_REVISION, TEST_MODULE + "2");
59 private EffectiveModelContextFactory contextFactory;
61 private SchemaRepository schemaRepository;
63 private SchemaSourceProvider<YangTextSource> sourceProvider;
65 private YangTextSource source;
68 void testNetconfDeviceFlawedModelFailedResolution() throws Exception {
69 final var ex = new SchemaResolutionException("fail first", TEST_SID, new Throwable("YangTools parser fail"));
70 doAnswer(invocation -> invocation.getArgument(0, Collection.class).size() == 2
71 ? Futures.immediateFailedFuture(ex) : Futures.immediateFuture(SCHEMA_CONTEXT))
72 .when(contextFactory).createEffectiveModelContext(anyCollection());
74 doReturn(Futures.immediateFuture(source)).when(schemaRepository)
75 .getSchemaSource(any(), eq(YangTextSource.class));
77 final var setup = new SchemaSetup(schemaRepository, contextFactory, DEVICE_ID,
78 new NetconfDeviceSchemas(Set.of(TEST_QNAME, TEST_QNAME2), FeatureSet.builder().build(), Set.of(),
79 List.of(new ProvidedSources<>(YangTextSource.class, sourceProvider, Set.of(TEST_QNAME, TEST_QNAME2)))),
80 NetconfSessionPreferences.fromStrings(Set.of()));
82 final var result = Futures.getDone(setup.startResolution());
83 verify(contextFactory, times(2)).createEffectiveModelContext(anyCollection());
84 assertSame(SCHEMA_CONTEXT, result.modelContext());
88 void testNetconfDeviceMissingSource() throws Exception {
89 // Make fallback attempt to fail due to empty resolved sources
90 final var ex = new MissingSchemaSourceException(TEST_SID, "fail first");
91 doReturn(Futures.immediateFailedFuture(ex))
92 .when(schemaRepository).getSchemaSource(TEST_SID, YangTextSource.class);
93 doReturn(Futures.immediateFuture(source)).when(schemaRepository)
94 .getSchemaSource(TEST_SID2, YangTextSource.class);
95 doReturn(Futures.immediateFuture(SCHEMA_CONTEXT)).when(contextFactory)
96 .createEffectiveModelContext(anyCollection());
98 final var setup = new SchemaSetup(schemaRepository, contextFactory, DEVICE_ID,
99 new NetconfDeviceSchemas(Set.of(TEST_QNAME, TEST_QNAME2), FeatureSet.builder().build(), Set.of(),
100 List.of(new ProvidedSources<>(YangTextSource.class, sourceProvider, Set.of(TEST_QNAME, TEST_QNAME2)))),
101 NetconfSessionPreferences.fromStrings(Set.of()));
103 final var result = Futures.getDone(setup.startResolution());
104 final var captor = ArgumentCaptor.forClass(Collection.class);
105 verify(contextFactory).createEffectiveModelContext(captor.capture());
106 assertEquals(List.of(TEST_SID2), captor.getValue());
107 assertSame(SCHEMA_CONTEXT, result.modelContext());
111 void testNetconfDeviceNotificationsCapabilityIsNotPresent() throws Exception {
112 doReturn(Futures.immediateFuture(source)).when(schemaRepository)
113 .getSchemaSource(any(), eq(YangTextSource.class));
114 doReturn(Futures.immediateFuture(SCHEMA_CONTEXT)).when(contextFactory)
115 .createEffectiveModelContext(anyCollection());
117 final var setup = new SchemaSetup(schemaRepository, contextFactory, DEVICE_ID,
118 new NetconfDeviceSchemas(Set.of(TEST_QNAME), FeatureSet.builder().build(), Set.of(),
119 List.of(new ProvidedSources<>(YangTextSource.class, sourceProvider, Set.of(TEST_QNAME)))),
120 NetconfSessionPreferences.fromStrings(
121 Set.of(TEST_NAMESPACE + "?module=" + TEST_MODULE + "&revision=" + TEST_REVISION)));
123 final var result = Futures.getDone(setup.startResolution());
124 assertEquals(Set.of(new AvailableCapabilityBuilder()
125 .setCapability("(test:namespace?revision=2013-07-22)test-module")
126 .setCapabilityOrigin(CapabilityOrigin.DeviceAdvertised)
127 .build()), result.capabilities().resolvedCapabilities());