Update MRI projects for Aluminium
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / test / java / org / opendaylight / ovsdb / hwvtepsouthbound / TransactionInvokerImplTest.java
1 /*
2  * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. 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
9 package org.opendaylight.ovsdb.hwvtepsouthbound;
10
11 import com.google.common.util.concurrent.FluentFuture;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.MoreExecutors;
14 import com.google.common.util.concurrent.SettableFuture;
15 import java.util.concurrent.CountDownLatch;
16 import java.util.concurrent.TimeUnit;
17 import org.junit.After;
18 import org.junit.Before;
19 import org.junit.Test;
20 import org.junit.runner.RunWith;
21 import org.mockito.junit.MockitoJUnitRunner;
22 import org.opendaylight.mdsal.binding.api.DataBroker;
23 import org.opendaylight.mdsal.binding.api.ReadWriteTransaction;
24 import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractConcurrentDataBrokerTest;
25 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
26 import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionCommand;
27 import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvokerImpl;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentationBuilder;
31 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
32 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
33 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
34 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
35 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
37 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 @RunWith(MockitoJUnitRunner.class)
43 public class TransactionInvokerImplTest extends AbstractConcurrentDataBrokerTest {
44
45     private static final Logger LOG = LoggerFactory.getLogger(DataChangeListenerTestBase.class);
46
47     private final CountDownLatch sleepingPillStartedLatch = new CountDownLatch(1);
48     private final CountDownLatch sleepingPillEndLatch = new CountDownLatch(1);
49     private CountDownLatch nullPointerPillStart = new CountDownLatch(1);
50
51     private final TransactionCommand sleepingPill = transaction -> {
52         try {
53             LOG.debug("Running sleeping pill");
54             sleepingPillStartedLatch.countDown();
55             sleepingPillEndLatch.await(5, TimeUnit.SECONDS);
56         } catch (InterruptedException e) {
57             //ignore the error
58         }
59     };
60
61     private final TransactionCommand nullPointerPill = transaction -> {
62         LOG.debug("Running npe TransactionCommand");
63         nullPointerPillStart.countDown();
64         throw new NullPointerException("Failed to execute command");
65     };
66
67     private InstanceIdentifier<Node> nodeIid1;
68     private InstanceIdentifier<Node> nodeIid2;
69     private InstanceIdentifier<Node> nodeIid3;
70
71     private DataBroker dataBroker;
72     private TransactionInvokerImpl invoker;
73
74     @Before
75     public void setupTest() throws Exception {
76         dataBroker = getDataBroker();
77         invoker = new TransactionInvokerImpl(dataBroker);
78         nodeIid1 = createInstanceIdentifier(java.util.UUID.randomUUID().toString());
79         nodeIid2 = createInstanceIdentifier(java.util.UUID.randomUUID().toString());
80         nodeIid3 = createInstanceIdentifier(java.util.UUID.randomUUID().toString());
81     }
82
83     @After
84     public void cleanup() throws Exception {
85         deleteNode(nodeIid1);
86         deleteNode(nodeIid2);
87         deleteNode(nodeIid3);
88     }
89
90     private void deleteNode(final InstanceIdentifier<Node> iid) {
91         ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
92         tx.delete(LogicalDatastoreType.CONFIGURATION, iid);
93         tx.commit();
94     }
95
96     @Test
97     public void testMiddleCommandNullPointerFailure() throws Exception {
98         final SettableFuture ft1 = SettableFuture.create();
99         final SettableFuture ft2 = SettableFuture.create();
100         final SettableFuture ft3 = SettableFuture.create();
101
102         //add a command which does a sleep of 500ms
103         invoker.invoke(sleepingPill);
104
105         //wait fot the above one to be scheduled
106         sleepingPillStartedLatch.await(5, TimeUnit.SECONDS);
107
108         //Now add the commands which will be picked up in one lot
109         invoker.invoke(new AddNodeCmd(nodeIid1, ft1));
110         invoker.invoke(nullPointerPill);
111         invoker.invoke(new AddNodeCmd(nodeIid2, ft2));
112
113         sleepingPillEndLatch.countDown();
114
115         ft1.get(5, TimeUnit.SECONDS);
116         ft2.get(5, TimeUnit.SECONDS);
117
118         nullPointerPillStart = new CountDownLatch(1);
119         invoker.invoke(nullPointerPill);
120         nullPointerPillStart.await(5, TimeUnit.SECONDS);
121
122         //make sure that any commands which are submitted after the previous failure run smoothly
123         invoker.invoke(new AddNodeCmd(nodeIid3, ft3));
124         ft3.get(5, TimeUnit.SECONDS);
125     }
126
127
128     private InstanceIdentifier<Node> createInstanceIdentifier(final String nodeIdString) {
129         NodeId nodeId = new NodeId(new Uri(nodeIdString));
130         NodeKey nodeKey = new NodeKey(nodeId);
131         TopologyKey topoKey = new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID);
132         return InstanceIdentifier.builder(NetworkTopology.class)
133                 .child(Topology.class, topoKey)
134                 .child(Node.class, nodeKey)
135                 .build();
136     }
137
138     private static class AddNodeCmd extends DefaultTransactionComamndImpl {
139         InstanceIdentifier<Node> iid;
140
141         AddNodeCmd(final InstanceIdentifier<Node> iid, final SettableFuture ft) {
142             super(ft);
143             this.iid = iid;
144         }
145
146         @Override
147         public void execute(final ReadWriteTransaction transaction) {
148             NodeBuilder nodeBuilder = new NodeBuilder();
149             nodeBuilder.setNodeId(iid.firstKeyOf(Node.class).getNodeId());
150             HwvtepGlobalAugmentationBuilder builder = new HwvtepGlobalAugmentationBuilder();
151             nodeBuilder.addAugmentation(HwvtepGlobalAugmentation.class, builder.build());
152             transaction.mergeParentStructurePut(LogicalDatastoreType.CONFIGURATION, iid, nodeBuilder.build());
153
154         }
155     }
156
157     private static class DeleteNodeCmd extends DefaultTransactionComamndImpl {
158         InstanceIdentifier<Node> iid;
159
160         DeleteNodeCmd(final InstanceIdentifier<Node> iid, final SettableFuture ft) {
161             super(ft);
162             this.iid = iid;
163         }
164
165         @Override
166         public void execute(final ReadWriteTransaction transaction) {
167             transaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
168         }
169     }
170
171     private static class DefaultTransactionComamndImpl implements TransactionCommand {
172         SettableFuture ft;
173
174         DefaultTransactionComamndImpl(final SettableFuture ft) {
175             this.ft = ft;
176         }
177
178         @Override
179         public void execute(final ReadWriteTransaction transaction) {
180
181         }
182
183         @Override
184         public void setTransactionResultFuture(final FluentFuture future) {
185             future.addCallback(new FutureCallback<>() {
186                 @Override
187                 public void onSuccess(final Object notUsed) {
188                     ft.set(null);
189                 }
190
191                 @Override
192                 public void onFailure(final Throwable throwable) {
193                     ft.setException(throwable);
194                 }
195             }, MoreExecutors.directExecutor());
196         }
197     }
198 }