906849fedce371c3bd5cfe21085d9baf850ca40c
[netconf.git] / apps / yanglib-mdsal-writer / src / test / java / org / opendaylight / netconf / yanglib / writer / YangLibraryWriterTest.java
1 /*
2  * Copyright (c) 2023 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.yanglib.writer;
9
10 import static org.junit.jupiter.api.Assertions.assertEquals;
11 import static org.junit.jupiter.api.Assertions.assertNotNull;
12 import static org.mockito.ArgumentMatchers.any;
13 import static org.mockito.ArgumentMatchers.eq;
14 import static org.mockito.Mockito.doReturn;
15 import static org.mockito.Mockito.never;
16 import static org.mockito.Mockito.verify;
17 import static org.mockito.Mockito.verifyNoInteractions;
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;
24
25 import java.util.Set;
26 import java.util.stream.Stream;
27 import org.junit.jupiter.api.DisplayName;
28 import org.junit.jupiter.api.Test;
29 import org.junit.jupiter.api.extension.ExtendWith;
30 import org.junit.jupiter.params.ParameterizedTest;
31 import org.junit.jupiter.params.provider.Arguments;
32 import org.junit.jupiter.params.provider.MethodSource;
33 import org.junit.jupiter.params.provider.ValueSource;
34 import org.mockito.ArgumentCaptor;
35 import org.mockito.Captor;
36 import org.mockito.Mock;
37 import org.mockito.junit.jupiter.MockitoExtension;
38 import org.opendaylight.mdsal.binding.api.DataBroker;
39 import org.opendaylight.mdsal.binding.api.TransactionChain;
40 import org.opendaylight.mdsal.binding.api.WriteTransaction;
41 import org.opendaylight.mdsal.common.api.CommitInfo;
42 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
43 import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.datastores.rev180214.Operational;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.LegacyRevisionUtils;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.ModulesState;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.ModulesStateBuilder;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.RevisionIdentifier;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.RevisionUtils;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.YangLibrary;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.YangLibraryBuilder;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.CommonLeafs;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.module.DeviationBuilder;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.set.parameters.ModuleBuilder;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.set.parameters.module.SubmoduleBuilder;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.yang.library.parameters.DatastoreBuilder;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.yang.library.parameters.ModuleSetBuilder;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.yang.library.parameters.SchemaBuilder;
60 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.YangIdentifier;
61 import org.opendaylight.yangtools.concepts.Registration;
62 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
63 import org.opendaylight.yangtools.yang.binding.util.BindingMap;
64 import org.opendaylight.yangtools.yang.common.Empty;
65
66 @ExtendWith(MockitoExtension.class)
67 class YangLibraryWriterTest {
68     private static final YangLibrarySchemaSourceUrlProvider URL_PROVIDER = (moduleSetName, moduleName, revision) ->
69             Set.of(new Uri("/url/to/" + moduleName + (revision == null ? "" : "/" + revision)));
70     private static final InstanceIdentifier<YangLibrary> YANG_LIBRARY_PATH =
71         InstanceIdentifier.create(YangLibrary.class);
72     @Deprecated
73     private static final InstanceIdentifier<ModulesState> MODULES_STATE_PATH =
74         InstanceIdentifier.create(ModulesState.class);
75     private static final boolean WITH_LEGACY = true;
76     private static final boolean NO_LEGACY = false;
77     private static final boolean WITH_URLS = true;
78     private static final boolean NO_URLS = false;
79
80     @Mock
81     private DOMSchemaService schemaService;
82     @Mock
83     private DataBroker dataBroker;
84     @Mock
85     private TransactionChain transactionChain;
86     @Mock
87     private WriteTransaction writeTransaction;
88     @Mock
89     private Registration registration;
90     @Captor
91     private ArgumentCaptor<YangLibrary> yangLibraryCaptor;
92     @Captor
93     private ArgumentCaptor<ModulesState> modulesStateCaptor;
94     private YangLibraryWriter writer;
95
96     @Test
97     @DisplayName("No update bc context has no ietf-yang-library")
98     void noUpdate() {
99         writer = new YangLibraryWriter(new FixedDOMSchemaService(parseYangResources(YangLibraryWriterTest.class,
100             "/test-module.yang", "/test-submodule.yang")), dataBroker, NO_LEGACY,
101             YangLibraryWriterSingleton.emptyProvider());
102         verifyNoInteractions(dataBroker);
103     }
104
105     @ParameterizedTest(name = "Write data -- with URLs: {0}, include legacy: {1}")
106     @MethodSource("writeContentArgs")
107     void writeContent(final boolean withUrls, final boolean writeLegacy, final YangLibrary expectedData,
108             final ModulesState expectedLegacyData) {
109         doReturn(transactionChain).when(dataBroker).createMergingTransactionChain();
110         doReturn(writeTransaction).when(transactionChain).newWriteOnlyTransaction();
111         doReturn(CommitInfo.emptyFluentFuture()).when(writeTransaction).commit();
112
113         writer = new YangLibraryWriter(new FixedDOMSchemaService(parseYangResources(YangLibraryWriterTest.class,
114             "/test-module.yang", "/test-submodule.yang", "/test-more.yang", "/ietf-yang-library@2019-01-04.yang",
115             "/ietf-datastores@2018-02-14.yang", "/ietf-yang-types.yang", "/ietf-inet-types.yang")), dataBroker,
116             writeLegacy, withUrls ? URL_PROVIDER : YangLibraryWriterSingleton.emptyProvider());
117
118         verify(writeTransaction).put(eq(OPERATIONAL), eq(YANG_LIBRARY_PATH), yangLibraryCaptor.capture());
119         assertEquals(expectedData, yangLibraryCaptor.getValue());
120         if (writeLegacy) {
121             verify(writeTransaction).put(eq(OPERATIONAL), eq(MODULES_STATE_PATH), modulesStateCaptor.capture());
122             assertEquals(expectedLegacyData, modulesStateCaptor.getValue());
123         } else {
124             verify(writeTransaction, never()).put(eq(OPERATIONAL), eq(MODULES_STATE_PATH), any());
125         }
126         verify(writeTransaction).commit();
127     }
128
129     private static Stream<Arguments> writeContentArgs() {
130         return Stream.of(
131             Arguments.of(NO_URLS, NO_LEGACY, buildYangLibrary(NO_URLS), null),
132             Arguments.of(NO_URLS, WITH_LEGACY, buildYangLibrary(NO_URLS), buildModulesState(NO_URLS)),
133             Arguments.of(WITH_URLS, NO_LEGACY, buildYangLibrary(WITH_URLS), null),
134             Arguments.of(WITH_URLS, WITH_LEGACY, buildYangLibrary(WITH_URLS), buildModulesState(WITH_URLS)));
135     }
136
137     @ParameterizedTest(name = "Clear data on close -- include legacy: {0}")
138     @ValueSource(booleans = {false, true})
139     void clearOnClose(final boolean writeLegacy) throws Exception {
140         doReturn(transactionChain).when(dataBroker).createMergingTransactionChain();
141         doReturn(writeTransaction).when(transactionChain).newWriteOnlyTransaction();
142         doReturn(Empty.immediateFuture()).when(transactionChain).future();
143         doReturn(CommitInfo.emptyFluentFuture()).when(writeTransaction).commit();
144         doReturn(registration).when(schemaService).registerSchemaContextListener(any());
145
146         assertNotNull(new YangLibraryWriter(schemaService, dataBroker, writeLegacy,
147             YangLibraryWriterSingleton.emptyProvider()).shutdown());
148         verify(writeTransaction).delete(OPERATIONAL, YANG_LIBRARY_PATH);
149         if (writeLegacy) {
150             verify(writeTransaction).delete(OPERATIONAL, MODULES_STATE_PATH);
151         } else {
152             verify(writeTransaction, never()).delete(OPERATIONAL, MODULES_STATE_PATH);
153         }
154         verify(writeTransaction).commit();
155     }
156
157     private static YangLibrary buildYangLibrary(final boolean withUrls) {
158         return new YangLibraryBuilder()
159             .setModuleSet(BindingMap.of(
160                 new ModuleSetBuilder()
161                     .setName(DEFAULT_MODULE_SET_NAME)
162                     .setModule(BindingMap.of(
163                         new ModuleBuilder().setName(new YangIdentifier("test-module_2013-07-22"))
164                             .setNamespace(new Uri("test:namespace"))
165                             .setRevision(new RevisionIdentifier("2013-07-22"))
166                             .setLocation(withUrls ? Set.of(new Uri("/url/to/test-module/2013-07-22")) : null)
167                             .setSubmodule(BindingMap.of(
168                                 new SubmoduleBuilder()
169                                     .setName(new YangIdentifier("test-submodule"))
170                                     .setRevision(RevisionUtils.emptyRevision().getRevisionIdentifier())
171                                     .setLocation(withUrls ? Set.of(new Uri("/url/to/test-submodule")) : null)
172                                     .build()))
173                             .setDeviation(Set.of(new YangIdentifier("test-more_2023-07-25")))
174                             .build(),
175                         new ModuleBuilder().setName(new YangIdentifier("test-more_2023-07-25"))
176                             .setNamespace(new Uri("test:more"))
177                             .setRevision(new RevisionIdentifier("2023-07-25"))
178                             .setLocation(withUrls ? Set.of(new Uri("/url/to/test-more/2023-07-25")) : null)
179                             .setFeature(Set.of(
180                                 new YangIdentifier("first-feature"), new YangIdentifier("second-feature")))
181                             .build(),
182                         new ModuleBuilder().setName(new YangIdentifier("ietf-yang-library_2019-01-04"))
183                             .setNamespace(new Uri("urn:ietf:params:xml:ns:yang:ietf-yang-library"))
184                             .setRevision(new RevisionIdentifier("2019-01-04"))
185                             .setLocation(withUrls ? Set.of(new Uri("/url/to/ietf-yang-library/2019-01-04")) : null)
186                             .build(),
187                         new ModuleBuilder().setName(new YangIdentifier("ietf-datastores_2018-02-14"))
188                             .setNamespace(new Uri("urn:ietf:params:xml:ns:yang:ietf-datastores"))
189                             .setRevision(new RevisionIdentifier("2018-02-14"))
190                             .setLocation(withUrls ? Set.of(new Uri("/url/to/ietf-datastores/2018-02-14")) : null)
191                             .build(),
192                         new ModuleBuilder().setName(new YangIdentifier("ietf-inet-types_2010-09-24"))
193                             .setNamespace(new Uri("urn:ietf:params:xml:ns:yang:ietf-inet-types"))
194                             .setRevision(new RevisionIdentifier("2010-09-24"))
195                             .setLocation(withUrls ? Set.of(new Uri("/url/to/ietf-inet-types/2010-09-24")) : null)
196                             .build(),
197                         new ModuleBuilder().setName(new YangIdentifier("ietf-yang-types_2010-09-24"))
198                             .setNamespace(new Uri("urn:ietf:params:xml:ns:yang:ietf-yang-types"))
199                             .setRevision(new RevisionIdentifier("2010-09-24"))
200                             .setLocation(withUrls ? Set.of(new Uri("/url/to/ietf-yang-types/2010-09-24")) : null)
201                             .build()))
202                     .build()))
203             .setSchema(BindingMap.of(new SchemaBuilder()
204                 .setName(DEFAULT_SCHEMA_NAME)
205                 .setModuleSet(Set.of(DEFAULT_MODULE_SET_NAME))
206                 .build()))
207             .setDatastore(BindingMap.of(
208                 new DatastoreBuilder().setName(Operational.VALUE)
209                     .setSchema(DEFAULT_SCHEMA_NAME)
210                     .build()))
211             .setContentId("1")
212             .build();
213     }
214
215     @Deprecated
216     private static ModulesState buildModulesState(final boolean withUrls) {
217         return new ModulesStateBuilder()
218             .setModule(BindingMap.of(
219                 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104
220                     .module.list.ModuleBuilder()
221                     .setName(new YangIdentifier("test-module_2013-07-22"))
222                     .setNamespace(new Uri("test:namespace"))
223                     .setRevision(new CommonLeafs.Revision(new RevisionIdentifier("2013-07-22")))
224                     .setSchema(withUrls ? new Uri("/url/to/test-module/2013-07-22") : null)
225                     .setSubmodule(BindingMap.of(
226                         new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104
227                             .module.list.module.SubmoduleBuilder()
228                             .setName(new YangIdentifier("test-submodule"))
229                             .setRevision(LegacyRevisionUtils.emptyRevision())
230                             .setSchema(withUrls ? new Uri("/url/to/test-submodule") : null)
231                             .build()))
232                     .setDeviation(BindingMap.of(
233                         new DeviationBuilder()
234                             .setName(new YangIdentifier("test-more_2023-07-25"))
235                             .setRevision(new CommonLeafs.Revision(new RevisionIdentifier("2023-07-25")))
236                             .build()
237                     ))
238                     .setConformanceType(Import)
239                     .build(),
240                 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104
241                     .module.list.ModuleBuilder()
242                     .setName(new YangIdentifier("test-more_2023-07-25"))
243                     .setNamespace(new Uri("test:more"))
244                     .setRevision(new CommonLeafs.Revision(new RevisionIdentifier("2023-07-25")))
245                     .setSchema(withUrls ? new Uri("/url/to/test-more/2023-07-25") : null)
246                     .setFeature(Set.of(
247                         new YangIdentifier("first-feature"), new YangIdentifier("second-feature")))
248                     .setConformanceType(Implement)
249                     .build(),
250                 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104
251                     .module.list.ModuleBuilder()
252                     .setName(new YangIdentifier("ietf-yang-library_2019-01-04"))
253                     .setNamespace(new Uri("urn:ietf:params:xml:ns:yang:ietf-yang-library"))
254                     .setRevision(new CommonLeafs.Revision(new RevisionIdentifier("2019-01-04")))
255                     .setSchema(withUrls ? new Uri("/url/to/ietf-yang-library/2019-01-04") : null)
256                     .setConformanceType(Import)
257                     .build(),
258                 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104
259                     .module.list.ModuleBuilder()
260                     .setName(new YangIdentifier("ietf-datastores_2018-02-14"))
261                     .setNamespace(new Uri("urn:ietf:params:xml:ns:yang:ietf-datastores"))
262                     .setRevision(new CommonLeafs.Revision(new RevisionIdentifier("2018-02-14")))
263                     .setSchema(withUrls ? new Uri("/url/to/ietf-datastores/2018-02-14") : null)
264                     .setConformanceType(Import)
265                     .build(),
266                 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104
267                     .module.list.ModuleBuilder()
268                     .setName(new YangIdentifier("ietf-inet-types_2010-09-24"))
269                     .setNamespace(new Uri("urn:ietf:params:xml:ns:yang:ietf-inet-types"))
270                     .setRevision(new CommonLeafs.Revision(new RevisionIdentifier("2010-09-24")))
271                     .setSchema(withUrls ? new Uri("/url/to/ietf-inet-types/2010-09-24") : null)
272                     .setConformanceType(Import)
273                     .build(),
274                 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104
275                     .module.list.ModuleBuilder()
276                     .setName(new YangIdentifier("ietf-yang-types_2010-09-24"))
277                     .setNamespace(new Uri("urn:ietf:params:xml:ns:yang:ietf-yang-types"))
278                     .setRevision(new CommonLeafs.Revision(new RevisionIdentifier("2010-09-24")))
279                     .setSchema(withUrls ? new Uri("/url/to/ietf-yang-types/2010-09-24") : null)
280                     .setConformanceType(Import)
281                     .build()))
282             .setModuleSetId("1")
283             .build();
284     }
285 }