Migrate netconf users of submit() to commit()
[netconf.git] / netconf / sal-netconf-connector / src / test / java / org / opendaylight / netconf / sal / connect / netconf / sal / NetconfDeviceTopologyAdapterTest.java
1 /*
2  * Copyright (c) 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.sal;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.mockito.Matchers.any;
12 import static org.mockito.Mockito.doNothing;
13 import static org.mockito.Mockito.doReturn;
14 import static org.mockito.Mockito.times;
15 import static org.mockito.Mockito.verify;
16 import static org.opendaylight.mdsal.common.api.CommitInfo.emptyFluentFuture;
17
18 import com.google.common.base.Optional;
19 import com.google.common.util.concurrent.MoreExecutors;
20 import java.net.InetSocketAddress;
21 import java.util.EnumMap;
22 import java.util.concurrent.TimeUnit;
23 import javassist.ClassPool;
24 import org.junit.Before;
25 import org.junit.Test;
26 import org.mockito.Mock;
27 import org.mockito.MockitoAnnotations;
28 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
29 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
30 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
31 import org.opendaylight.controller.md.sal.binding.impl.BindingDOMDataBrokerAdapter;
32 import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
33 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
34 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
35 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
36 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
37 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
38 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
39 import org.opendaylight.controller.md.sal.dom.broker.impl.SerializedDOMDataBroker;
40 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStoreFactory;
41 import org.opendaylight.controller.sal.core.spi.data.DOMStore;
42 import org.opendaylight.mdsal.binding.dom.codec.gen.impl.DataObjectSerializerGenerator;
43 import org.opendaylight.mdsal.binding.dom.codec.gen.impl.StreamWriterGenerator;
44 import org.opendaylight.mdsal.binding.dom.codec.impl.BindingNormalizedNodeCodecRegistry;
45 import org.opendaylight.mdsal.binding.generator.impl.GeneratedClassLoadingStrategy;
46 import org.opendaylight.mdsal.binding.generator.impl.ModuleInfoBackedContext;
47 import org.opendaylight.mdsal.binding.generator.util.BindingRuntimeContext;
48 import org.opendaylight.mdsal.binding.generator.util.JavassistUtils;
49 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
50 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
51 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus;
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
56 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
57 import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
58 import org.opendaylight.yangtools.concepts.ListenerRegistration;
59 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
60 import org.opendaylight.yangtools.yang.common.QName;
61 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
62 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
63 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder;
64 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
65 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
66 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
67
68 public class NetconfDeviceTopologyAdapterTest {
69
70     private final RemoteDeviceId id = new RemoteDeviceId("test", new InetSocketAddress("localhost", 22));
71
72     @Mock
73     private DataBroker broker;
74     @Mock
75     private WriteTransaction writeTx;
76     @Mock
77     private BindingTransactionChain txChain;
78     @Mock
79     private NetconfNode data;
80
81     private final String txIdent = "test transaction";
82
83     private SchemaContext schemaContext = null;
84     private final String sessionIdForReporting = "netconf-test-session1";
85
86     private BindingTransactionChain transactionChain;
87
88     private DataBroker dataBroker;
89
90     private DOMDataBroker domDataBroker;
91
92     @Before
93     public void setUp() throws Exception {
94         MockitoAnnotations.initMocks(this);
95         doReturn(txChain).when(broker).createTransactionChain(any(TransactionChainListener.class));
96         doReturn(writeTx).when(txChain).newWriteOnlyTransaction();
97         doNothing().when(writeTx)
98                 .put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(NetconfNode.class));
99         doNothing().when(writeTx)
100                 .merge(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(NetconfNode.class));
101
102         doReturn(txIdent).when(writeTx).getIdentifier();
103
104         this.schemaContext = YangParserTestUtils.parseYangResources(NetconfDeviceTopologyAdapterTest.class,
105             "/schemas/network-topology@2013-10-21.yang", "/schemas/ietf-inet-types@2013-07-15.yang",
106             "/schemas/yang-ext.yang", "/schemas/netconf-node-topology.yang",
107             "/schemas/network-topology-augment-test@2016-08-08.yang");
108         schemaContext.getModules();
109         final DOMSchemaService schemaService = createSchemaService();
110
111         final DOMStore operStore = InMemoryDOMDataStoreFactory.create("DOM-OPER", schemaService);
112         final DOMStore configStore = InMemoryDOMDataStoreFactory.create("DOM-CFG", schemaService);
113
114         final EnumMap<LogicalDatastoreType, DOMStore> datastores = new EnumMap<>(LogicalDatastoreType.class);
115         datastores.put(LogicalDatastoreType.CONFIGURATION, configStore);
116         datastores.put(LogicalDatastoreType.OPERATIONAL, operStore);
117
118         domDataBroker = new SerializedDOMDataBroker(datastores, MoreExecutors.newDirectExecutorService());
119
120         final ClassPool pool = ClassPool.getDefault();
121         final DataObjectSerializerGenerator generator = StreamWriterGenerator.create(JavassistUtils.forClassPool(pool));
122         final BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(generator);
123         final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
124         codecRegistry.onBindingRuntimeContextUpdated(
125                 BindingRuntimeContext.create(moduleInfoBackedContext, schemaContext));
126
127         final GeneratedClassLoadingStrategy loading = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
128         final BindingToNormalizedNodeCodec bindingToNormalized =
129                 new BindingToNormalizedNodeCodec(loading, codecRegistry);
130         bindingToNormalized.onGlobalContextUpdated(schemaContext);
131         dataBroker = new BindingDOMDataBrokerAdapter(domDataBroker, bindingToNormalized);
132
133         transactionChain = dataBroker.createTransactionChain(new TransactionChainListener() {
134             @Override
135             public void onTransactionChainFailed(final TransactionChain<?, ?> chain,
136                     final AsyncTransaction<?, ?> transaction, final Throwable cause) {
137
138             }
139
140             @Override
141             public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
142
143             }
144         });
145
146     }
147
148     @Test
149     public void testFailedDevice() throws Exception {
150
151         doReturn(emptyFluentFuture()).when(writeTx).commit();
152         NetconfDeviceTopologyAdapter adapter = new NetconfDeviceTopologyAdapter(id, txChain);
153         adapter.setDeviceAsFailed(null);
154
155         verify(txChain, times(2)).newWriteOnlyTransaction();
156         verify(writeTx, times(1))
157                 .put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(NetconfNode.class));
158         adapter.close();
159
160         adapter = new NetconfDeviceTopologyAdapter(id, transactionChain); //not a mock
161         adapter.setDeviceAsFailed(null);
162
163         Optional<NetconfNode> netconfNode = dataBroker.newReadWriteTransaction().read(LogicalDatastoreType.OPERATIONAL,
164                 id.getTopologyBindingPath().augmentation(NetconfNode.class)).checkedGet(5, TimeUnit.SECONDS);
165
166         assertEquals("Netconf node should be presented.", true, netconfNode.isPresent());
167         assertEquals("Connection status should be failed.",
168                 NetconfNodeConnectionStatus.ConnectionStatus.UnableToConnect.getName(),
169                 netconfNode.get().getConnectionStatus().getName());
170
171     }
172
173     @Test
174     public void testDeviceUpdate() throws Exception {
175         doReturn(emptyFluentFuture()).when(writeTx).commit();
176
177         NetconfDeviceTopologyAdapter adapter = new NetconfDeviceTopologyAdapter(id, txChain);
178         adapter.updateDeviceData(true, new NetconfDeviceCapabilities());
179
180         verify(txChain, times(2)).newWriteOnlyTransaction();
181         verify(writeTx, times(1))
182                 .put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(NetconfNode.class));
183         verify(writeTx, times(1)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class));
184
185     }
186
187     @Test
188     public void testDeviceAugmentedNodePresence() throws Exception {
189
190         Integer dataTestId = 474747;
191
192         NetconfDeviceTopologyAdapter adapter = new NetconfDeviceTopologyAdapter(id, transactionChain);
193
194         QName netconfTestLeafQname = QName.create(
195                 "urn:TBD:params:xml:ns:yang:network-topology-augment-test", "2016-08-08", "test-id").intern();
196
197         YangInstanceIdentifier pathToAugmentedLeaf = YangInstanceIdentifier.builder().node(NetworkTopology.QNAME)
198                 .node(Topology.QNAME)
199                 .nodeWithKey(Topology.QNAME, QName.create(Topology.QNAME, "topology-id"), "topology-netconf")
200                 .node(Node.QNAME)
201                 .nodeWithKey(Node.QNAME, QName.create(Node.QNAME, "node-id"), "test")
202                 .node(netconfTestLeafQname).build();
203
204         NormalizedNode<?, ?> augmentNode = ImmutableLeafNodeBuilder.create().withValue(dataTestId)
205                 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(netconfTestLeafQname)).build();
206
207         DOMDataWriteTransaction wtx =  domDataBroker.newWriteOnlyTransaction();
208         wtx.put(LogicalDatastoreType.OPERATIONAL, pathToAugmentedLeaf, augmentNode);
209         wtx.commit().get(5, TimeUnit.SECONDS);
210
211         adapter.updateDeviceData(true, new NetconfDeviceCapabilities());
212         Optional<NormalizedNode<?, ?>> testNode = domDataBroker.newReadOnlyTransaction()
213                 .read(LogicalDatastoreType.OPERATIONAL, pathToAugmentedLeaf).get(2, TimeUnit.SECONDS);
214
215         assertEquals("Augmented node data should be still present after device update.", true, testNode.isPresent());
216         assertEquals("Augmented data should be the same as before update node.", dataTestId, testNode.get().getValue());
217
218         adapter.setDeviceAsFailed(null);
219         testNode = domDataBroker.newReadOnlyTransaction()
220                 .read(LogicalDatastoreType.OPERATIONAL, pathToAugmentedLeaf).get(2, TimeUnit.SECONDS);
221
222         assertEquals("Augmented node data should be still present after device failed.", true, testNode.isPresent());
223         assertEquals("Augmented data should be the same as before failed device.",
224                 dataTestId, testNode.get().getValue());
225     }
226
227     private DOMSchemaService createSchemaService() {
228         return new DOMSchemaService() {
229
230             @Override
231             public SchemaContext getSessionContext() {
232                 return schemaContext;
233             }
234
235             @Override
236             public SchemaContext getGlobalContext() {
237                 return schemaContext;
238             }
239
240             @Override
241             public ListenerRegistration<SchemaContextListener> registerSchemaContextListener(
242                     final SchemaContextListener listener) {
243                 listener.onGlobalContextUpdated(getGlobalContext());
244                 return new AbstractListenerRegistration<SchemaContextListener>(listener) {
245                     @Override
246                     protected void removeRegistration() {
247                         // No-op
248                     }
249                 };
250             }
251         };
252     }
253
254     @Test
255     public void testRemoveDeviceConfiguration() throws Exception {
256         doReturn(emptyFluentFuture()).when(writeTx).commit();
257
258         NetconfDeviceTopologyAdapter adapter = new NetconfDeviceTopologyAdapter(id, txChain);
259         adapter.close();
260
261         verify(txChain, times(2)).newWriteOnlyTransaction();
262         verify(writeTx).delete(LogicalDatastoreType.OPERATIONAL, id.getTopologyBindingPath());
263         verify(writeTx, times(2)).commit();
264     }
265
266 }