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