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