2 * Copyright (c) 2023 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.yanglib.writer;
10 import static org.junit.jupiter.api.Assertions.assertEquals;
11 import static org.mockito.ArgumentMatchers.any;
12 import static org.mockito.ArgumentMatchers.eq;
13 import static org.mockito.Mockito.doReturn;
14 import static org.mockito.Mockito.never;
15 import static org.mockito.Mockito.verify;
16 import static org.mockito.Mockito.verifyNoInteractions;
17 import static org.opendaylight.mdsal.common.api.CommitInfo.emptyFluentFuture;
18 import static org.opendaylight.mdsal.common.api.LogicalDatastoreType.OPERATIONAL;
19 import static org.opendaylight.netconf.yanglib.writer.YangLibraryContentBuilderUtil.DEFAULT_MODULE_SET_NAME;
20 import static org.opendaylight.netconf.yanglib.writer.YangLibraryContentBuilderUtil.DEFAULT_SCHEMA_NAME;
21 import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.Module.ConformanceType.Implement;
22 import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.Module.ConformanceType.Import;
23 import static org.opendaylight.yangtools.yang.test.util.YangParserTestUtils.parseYangResources;
25 import java.util.Optional;
27 import java.util.stream.Stream;
28 import org.junit.jupiter.api.BeforeEach;
29 import org.junit.jupiter.api.DisplayName;
30 import org.junit.jupiter.api.Test;
31 import org.junit.jupiter.api.extension.ExtendWith;
32 import org.junit.jupiter.params.ParameterizedTest;
33 import org.junit.jupiter.params.provider.Arguments;
34 import org.junit.jupiter.params.provider.MethodSource;
35 import org.junit.jupiter.params.provider.ValueSource;
36 import org.mockito.ArgumentCaptor;
37 import org.mockito.Captor;
38 import org.mockito.Mock;
39 import org.mockito.junit.jupiter.MockitoExtension;
40 import org.opendaylight.mdsal.binding.api.DataBroker;
41 import org.opendaylight.mdsal.binding.api.WriteTransaction;
42 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.datastores.rev180214.Operational;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.LegacyRevisionUtils;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.ModulesState;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.ModulesStateBuilder;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.RevisionIdentifier;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.RevisionUtils;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.YangLibrary;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.YangLibraryBuilder;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.CommonLeafs;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.module.DeviationBuilder;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.set.parameters.ModuleBuilder;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.set.parameters.module.SubmoduleBuilder;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.yang.library.parameters.DatastoreBuilder;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.yang.library.parameters.ModuleSetBuilder;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.yang.library.parameters.SchemaBuilder;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.YangIdentifier;
60 import org.opendaylight.yangtools.concepts.Registration;
61 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
62 import org.opendaylight.yangtools.yang.binding.util.BindingMap;
64 @ExtendWith(MockitoExtension.class)
65 class YangLibraryWriterTest {
66 private static final YangLibrarySchemaSourceUrlProvider URL_PROVIDER = (moduleSetName, moduleName, revision) ->
67 Optional.of(new Uri("/url/to/" + moduleName + (revision == null ? "" : "/" + revision)));
68 private static final InstanceIdentifier<YangLibrary> YANG_LIBRARY_PATH =
69 InstanceIdentifier.create(YangLibrary.class);
70 private static final InstanceIdentifier<ModulesState> MODULES_STATE_PATH =
71 InstanceIdentifier.create(ModulesState.class);
72 private static final boolean WITH_LEGACY = true;
73 private static final boolean NO_LEGACY = false;
74 private static final boolean WITH_URLS = true;
75 private static final boolean NO_URLS = false;
78 private DOMSchemaService schemaService;
80 private DataBroker dataBroker;
82 private WriteTransaction writeTransaction;
84 private Registration registration;
86 private YangLibraryWriter.Configuration config;
88 private ArgumentCaptor<YangLibrary> yangLibraryCaptor;
90 private ArgumentCaptor<ModulesState> modulesStateCaptor;
91 private YangLibraryWriter writer;
95 doReturn(registration).when(schemaService).registerSchemaContextListener(any());
98 private YangLibraryWriter.Configuration setupConfig(final boolean writeLegacy) {
99 doReturn(writeLegacy).when(config).write$_$legacy();
104 @DisplayName("No update bc context has no ietf-yang-library")
106 writer = new YangLibraryWriter(schemaService, dataBroker, setupConfig(NO_LEGACY));
107 writer.onModelContextUpdated(parseYangResources(YangLibraryWriterTest.class,
108 "/test-module.yang", "/test-submodule.yang"));
109 verifyNoInteractions(dataBroker);
112 @ParameterizedTest(name = "Write data -- with URLs: {0}, include legacy: {1}")
113 @MethodSource("writeContentArgs")
114 void writeContent(final boolean withUrls, final boolean writeLegacy, final YangLibrary expectedData,
115 final ModulesState expectedLegacyData) {
116 doReturn(writeTransaction).when(dataBroker).newWriteOnlyTransaction();
117 doReturn(emptyFluentFuture()).when(writeTransaction).commit();
119 writer = new YangLibraryWriter(schemaService, dataBroker, setupConfig(writeLegacy));
121 writer.schemaSourceUrlProvider = URL_PROVIDER;
123 writer.onModelContextUpdated(parseYangResources(YangLibraryWriterTest.class,
124 "/test-module.yang", "/test-submodule.yang", "/test-more.yang", "/ietf-yang-library@2019-01-04.yang",
125 "/ietf-datastores@2018-02-14.yang", "/ietf-yang-types.yang", "/ietf-inet-types.yang"));
127 verify(writeTransaction).put(eq(OPERATIONAL), eq(YANG_LIBRARY_PATH), yangLibraryCaptor.capture());
128 assertEquals(expectedData, yangLibraryCaptor.getValue());
130 verify(writeTransaction).put(eq(OPERATIONAL), eq(MODULES_STATE_PATH), modulesStateCaptor.capture());
131 assertEquals(expectedLegacyData, modulesStateCaptor.getValue());
133 verify(writeTransaction, never()).put(eq(OPERATIONAL), eq(MODULES_STATE_PATH), any());
135 verify(writeTransaction).commit();
138 private static Stream<Arguments> writeContentArgs() {
140 Arguments.of(NO_URLS, NO_LEGACY, buildYangLibrary(NO_URLS), null),
141 Arguments.of(NO_URLS, WITH_LEGACY, buildYangLibrary(NO_URLS), buildModulesState(NO_URLS)),
142 Arguments.of(WITH_URLS, NO_LEGACY, buildYangLibrary(WITH_URLS), null),
143 Arguments.of(WITH_URLS, WITH_LEGACY, buildYangLibrary(WITH_URLS), buildModulesState(WITH_URLS)));
146 @ParameterizedTest(name = "Clear data on close -- include legacy: {0}")
147 @ValueSource(booleans = {false, true})
148 void clearOnClose(final boolean writeLegacy) throws Exception {
149 doReturn(writeTransaction).when(dataBroker).newWriteOnlyTransaction();
150 doReturn(emptyFluentFuture()).when(writeTransaction).commit();
152 new YangLibraryWriter(schemaService, dataBroker, setupConfig(writeLegacy)).close();
153 verify(writeTransaction).delete(OPERATIONAL, YANG_LIBRARY_PATH);
155 verify(writeTransaction).delete(OPERATIONAL, MODULES_STATE_PATH);
157 verify(writeTransaction, never()).delete(OPERATIONAL, MODULES_STATE_PATH);
159 verify(writeTransaction).commit();
162 private static YangLibrary buildYangLibrary(final boolean withUrls) {
163 return new YangLibraryBuilder()
164 .setModuleSet(BindingMap.of(
165 new ModuleSetBuilder()
166 .setName(DEFAULT_MODULE_SET_NAME)
167 .setModule(BindingMap.of(
168 new ModuleBuilder().setName(new YangIdentifier("test-module_2013-07-22"))
169 .setNamespace(new Uri("test:namespace"))
170 .setRevision(new RevisionIdentifier("2013-07-22"))
171 .setLocation(withUrls ? Set.of(new Uri("/url/to/test-module/2013-07-22")) : null)
172 .setSubmodule(BindingMap.of(
173 new SubmoduleBuilder()
174 .setName(new YangIdentifier("test-submodule"))
175 .setRevision(RevisionUtils.emptyRevision().getRevisionIdentifier())
176 .setLocation(withUrls ? Set.of(new Uri("/url/to/test-submodule")) : null)
178 .setDeviation(Set.of(new YangIdentifier("test-more_2023-07-25")))
180 new ModuleBuilder().setName(new YangIdentifier("test-more_2023-07-25"))
181 .setNamespace(new Uri("test:more"))
182 .setRevision(new RevisionIdentifier("2023-07-25"))
183 .setLocation(withUrls ? Set.of(new Uri("/url/to/test-more/2023-07-25")) : null)
185 new YangIdentifier("first-feature"), new YangIdentifier("second-feature")))
187 new ModuleBuilder().setName(new YangIdentifier("ietf-yang-library_2019-01-04"))
188 .setNamespace(new Uri("urn:ietf:params:xml:ns:yang:ietf-yang-library"))
189 .setRevision(new RevisionIdentifier("2019-01-04"))
190 .setLocation(withUrls ? Set.of(new Uri("/url/to/ietf-yang-library/2019-01-04")) : null)
192 new ModuleBuilder().setName(new YangIdentifier("ietf-datastores_2018-02-14"))
193 .setNamespace(new Uri("urn:ietf:params:xml:ns:yang:ietf-datastores"))
194 .setRevision(new RevisionIdentifier("2018-02-14"))
195 .setLocation(withUrls ? Set.of(new Uri("/url/to/ietf-datastores/2018-02-14")) : null)
197 new ModuleBuilder().setName(new YangIdentifier("ietf-inet-types_2010-09-24"))
198 .setNamespace(new Uri("urn:ietf:params:xml:ns:yang:ietf-inet-types"))
199 .setRevision(new RevisionIdentifier("2010-09-24"))
200 .setLocation(withUrls ? Set.of(new Uri("/url/to/ietf-inet-types/2010-09-24")) : null)
202 new ModuleBuilder().setName(new YangIdentifier("ietf-yang-types_2010-09-24"))
203 .setNamespace(new Uri("urn:ietf:params:xml:ns:yang:ietf-yang-types"))
204 .setRevision(new RevisionIdentifier("2010-09-24"))
205 .setLocation(withUrls ? Set.of(new Uri("/url/to/ietf-yang-types/2010-09-24")) : null)
208 .setSchema(BindingMap.of(new SchemaBuilder()
209 .setName(DEFAULT_SCHEMA_NAME)
210 .setModuleSet(Set.of(DEFAULT_MODULE_SET_NAME))
212 .setDatastore(BindingMap.of(
213 new DatastoreBuilder().setName(Operational.VALUE)
214 .setSchema(DEFAULT_SCHEMA_NAME)
220 private static ModulesState buildModulesState(final boolean withUrls) {
221 return new ModulesStateBuilder()
222 .setModule(BindingMap.of(
223 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104
224 .module.list.ModuleBuilder()
225 .setName(new YangIdentifier("test-module_2013-07-22"))
226 .setNamespace(new Uri("test:namespace"))
227 .setRevision(new CommonLeafs.Revision(new RevisionIdentifier("2013-07-22")))
228 .setSchema(withUrls ? new Uri("/url/to/test-module/2013-07-22") : null)
229 .setSubmodule(BindingMap.of(
230 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104
231 .module.list.module.SubmoduleBuilder()
232 .setName(new YangIdentifier("test-submodule"))
233 .setRevision(LegacyRevisionUtils.emptyRevision())
234 .setSchema(withUrls ? new Uri("/url/to/test-submodule") : null)
236 .setDeviation(BindingMap.of(
237 new DeviationBuilder()
238 .setName(new YangIdentifier("test-more_2023-07-25"))
239 .setRevision(new CommonLeafs.Revision(new RevisionIdentifier("2023-07-25")))
242 .setConformanceType(Import)
244 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104
245 .module.list.ModuleBuilder()
246 .setName(new YangIdentifier("test-more_2023-07-25"))
247 .setNamespace(new Uri("test:more"))
248 .setRevision(new CommonLeafs.Revision(new RevisionIdentifier("2023-07-25")))
249 .setSchema(withUrls ? new Uri("/url/to/test-more/2023-07-25") : null)
251 new YangIdentifier("first-feature"), new YangIdentifier("second-feature")))
252 .setConformanceType(Implement)
254 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104
255 .module.list.ModuleBuilder()
256 .setName(new YangIdentifier("ietf-yang-library_2019-01-04"))
257 .setNamespace(new Uri("urn:ietf:params:xml:ns:yang:ietf-yang-library"))
258 .setRevision(new CommonLeafs.Revision(new RevisionIdentifier("2019-01-04")))
259 .setSchema(withUrls ? new Uri("/url/to/ietf-yang-library/2019-01-04") : null)
260 .setConformanceType(Import)
262 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104
263 .module.list.ModuleBuilder()
264 .setName(new YangIdentifier("ietf-datastores_2018-02-14"))
265 .setNamespace(new Uri("urn:ietf:params:xml:ns:yang:ietf-datastores"))
266 .setRevision(new CommonLeafs.Revision(new RevisionIdentifier("2018-02-14")))
267 .setSchema(withUrls ? new Uri("/url/to/ietf-datastores/2018-02-14") : null)
268 .setConformanceType(Import)
270 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104
271 .module.list.ModuleBuilder()
272 .setName(new YangIdentifier("ietf-inet-types_2010-09-24"))
273 .setNamespace(new Uri("urn:ietf:params:xml:ns:yang:ietf-inet-types"))
274 .setRevision(new CommonLeafs.Revision(new RevisionIdentifier("2010-09-24")))
275 .setSchema(withUrls ? new Uri("/url/to/ietf-inet-types/2010-09-24") : null)
276 .setConformanceType(Import)
278 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104
279 .module.list.ModuleBuilder()
280 .setName(new YangIdentifier("ietf-yang-types_2010-09-24"))
281 .setNamespace(new Uri("urn:ietf:params:xml:ns:yang:ietf-yang-types"))
282 .setRevision(new CommonLeafs.Revision(new RevisionIdentifier("2010-09-24")))
283 .setSchema(withUrls ? new Uri("/url/to/ietf-yang-types/2010-09-24") : null)
284 .setConformanceType(Import)