Migrate common module to JUnit5
[transportpce.git] / common / src / test / java / org / opendaylight / transportpce / common / device / DeviceTransactionManagerTest.java
1 /*
2  * Copyright © 2017 Orange, 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
9 package org.opendaylight.transportpce.common.device;
10
11 import static org.junit.jupiter.api.Assertions.assertFalse;
12 import static org.junit.jupiter.api.Assertions.assertTrue;
13 import static org.junit.jupiter.api.Assertions.fail;
14 import static org.mockito.ArgumentMatchers.any;
15 import static org.mockito.Mockito.lenient;
16 import static org.mockito.Mockito.when;
17
18 import java.util.LinkedList;
19 import java.util.List;
20 import java.util.Optional;
21 import java.util.concurrent.ExecutionException;
22 import java.util.concurrent.Future;
23 import java.util.concurrent.TimeUnit;
24 import java.util.concurrent.TimeoutException;
25 import org.junit.jupiter.api.AfterEach;
26 import org.junit.jupiter.api.BeforeEach;
27 import org.junit.jupiter.api.Test;
28 import org.junit.jupiter.api.extension.ExtendWith;
29 import org.mockito.Mock;
30 import org.mockito.Mockito;
31 import org.mockito.junit.jupiter.MockitoExtension;
32 import org.opendaylight.mdsal.binding.api.DataBroker;
33 import org.opendaylight.mdsal.binding.api.MountPoint;
34 import org.opendaylight.mdsal.binding.api.MountPointService;
35 import org.opendaylight.mdsal.binding.api.ReadWriteTransaction;
36 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NetworkId;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.Networks;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.Network;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.networks.NetworkBuilder;
41 import org.opendaylight.yangtools.util.concurrent.FluentFutures;
42 import org.opendaylight.yangtools.yang.binding.DataObject;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44
45 @ExtendWith(MockitoExtension.class)
46 public class DeviceTransactionManagerTest {
47
48     @Mock
49     private MountPointService mountPointServiceMock;
50     @Mock
51     private MountPoint mountPointMock;
52     @Mock
53     private DataBroker dataBrokerMock;
54     @Mock
55     private ReadWriteTransaction rwTransactionMock;
56
57
58     private DeviceTransactionManagerImpl transactionManager;
59     private String defaultDeviceId = "device-id";
60     private LogicalDatastoreType defaultDatastore = LogicalDatastoreType.OPERATIONAL;
61     private InstanceIdentifier<Network> defaultIid = InstanceIdentifier
62         .builder(Networks.class).child(Network.class).build();
63     private Network defaultData;
64     private long defaultTimeout = 1000;
65     private TimeUnit defaultTimeUnit = TimeUnit.MILLISECONDS;
66
67     @BeforeEach
68     void before() {
69         when(mountPointServiceMock.getMountPoint(any())).thenReturn(Optional.of(mountPointMock));
70         when(mountPointMock.getService(any())).thenReturn(Optional.of(dataBrokerMock));
71         when(dataBrokerMock.newReadWriteTransaction()).thenReturn(rwTransactionMock);
72         lenient().when(rwTransactionMock.commit()).thenReturn(FluentFutures.immediateNullFluentFuture());
73         NetworkId networkId =  new NetworkId("NETWORK1");
74         defaultData = new NetworkBuilder().setNetworkId(networkId).build();
75         this.transactionManager = new DeviceTransactionManagerImpl(mountPointServiceMock, 3000);
76     }
77
78     @AfterEach
79     void after() {
80         transactionManager.preDestroy();
81     }
82
83     @Test
84     void basicPositiveTransactionTest() {
85         try {
86             putAndSubmit(transactionManager, defaultDeviceId, defaultDatastore, defaultIid, defaultData);
87         } catch (InterruptedException | ExecutionException e) {
88             fail("Exception catched! " + e);
89             return;
90         }
91
92         Mockito.verify(rwTransactionMock, Mockito.times(1)).put(defaultDatastore, defaultIid, defaultData);
93         Mockito.verify(rwTransactionMock, Mockito.times(1)).commit();
94     }
95
96     @Test
97     void advancedPositiveTransactionTest() {
98         try {
99             Future<java.util.Optional<DeviceTransaction>> firstDeviceTxFuture =
100                     transactionManager.getDeviceTransaction(defaultDeviceId);
101             DeviceTransaction firstDeviceTx = firstDeviceTxFuture.get().get();
102
103             Future<java.util.Optional<DeviceTransaction>> secondDeviceTxFuture =
104                     transactionManager.getDeviceTransaction(defaultDeviceId);
105             assertFalse(secondDeviceTxFuture.isDone());
106
107             Future<java.util.Optional<DeviceTransaction>> thirdDeviceTxFuture =
108                     transactionManager.getDeviceTransaction(defaultDeviceId);
109             assertFalse(thirdDeviceTxFuture.isDone());
110
111             firstDeviceTx.put(defaultDatastore, defaultIid, defaultData);
112             assertFalse(secondDeviceTxFuture.isDone());
113             assertFalse(thirdDeviceTxFuture.isDone());
114             Thread.sleep(200);
115             assertFalse(secondDeviceTxFuture.isDone());
116             assertFalse(thirdDeviceTxFuture.isDone());
117
118             Future<java.util.Optional<DeviceTransaction>> anotherDeviceTxFuture =
119                     transactionManager.getDeviceTransaction("another-id");
120             Thread.sleep(50);
121             assertTrue(anotherDeviceTxFuture.isDone());
122             anotherDeviceTxFuture.get().get().commit(defaultTimeout, defaultTimeUnit);
123
124             firstDeviceTx.commit(defaultTimeout, defaultTimeUnit);
125             Thread.sleep(200);
126             assertTrue(secondDeviceTxFuture.isDone());
127             assertFalse(thirdDeviceTxFuture.isDone());
128
129             DeviceTransaction secondDeviceTx = secondDeviceTxFuture.get().get();
130             secondDeviceTx.put(defaultDatastore, defaultIid, defaultData);
131             assertFalse(thirdDeviceTxFuture.isDone());
132
133             secondDeviceTx.commit(defaultTimeout, defaultTimeUnit);
134             Thread.sleep(200);
135             assertTrue(thirdDeviceTxFuture.isDone());
136
137             DeviceTransaction thirdDeviceTx = thirdDeviceTxFuture.get().get();
138             thirdDeviceTx.put(defaultDatastore, defaultIid, defaultData);
139             thirdDeviceTx.commit(defaultTimeout, defaultTimeUnit);
140
141             Mockito.verify(rwTransactionMock, Mockito.times(3)).put(defaultDatastore, defaultIid, defaultData);
142             Mockito.verify(rwTransactionMock, Mockito.times(4)).commit();
143         } catch (InterruptedException | ExecutionException e) {
144             fail("Exception catched! " + e);
145         }
146     }
147
148     @Test
149     void bigAmountOfTransactionsOnSameDeviceTest() {
150         int numberOfTxs = 100;
151         List<Future<java.util.Optional<DeviceTransaction>>> deviceTransactionFutures = new LinkedList<>();
152         List<DeviceTransaction> deviceTransactions = new LinkedList<>();
153
154         for (int i = 0; i < numberOfTxs; i++) {
155             deviceTransactionFutures.add(transactionManager.getDeviceTransaction(defaultDeviceId));
156         }
157
158         try {
159             for (Future<java.util.Optional<DeviceTransaction>> futureTx : deviceTransactionFutures) {
160                 DeviceTransaction deviceTx = futureTx.get().get();
161                 deviceTx.commit(defaultTimeout, defaultTimeUnit);
162                 deviceTransactions.add(deviceTx);
163             }
164         } catch (InterruptedException | ExecutionException e) {
165             fail("Exception catched! " + e);
166         }
167
168         for (DeviceTransaction deviceTx : deviceTransactions) {
169             assertTrue(deviceTx.wasSubmittedOrCancelled().get());
170         }
171     }
172
173     @Test
174     void bigAmountOfTransactionsOnDifferentDevicesTest() {
175         int numberOfTxs = 1000;
176         List<DeviceTransaction> deviceTransactions = new LinkedList<>();
177
178         try {
179             for (int i = 0; i < numberOfTxs; i++) {
180                 deviceTransactions.add(transactionManager.getDeviceTransaction(defaultDeviceId + " " + i).get().get());
181             }
182         } catch (InterruptedException | ExecutionException e) {
183             fail("Exception catched! " + e);
184         }
185
186         deviceTransactions.parallelStream()
187                 .forEach(deviceTransaction -> deviceTransaction.commit(defaultTimeout, defaultTimeUnit));
188
189         deviceTransactions.parallelStream()
190                 .forEach(deviceTransaction -> assertTrue(deviceTransaction.wasSubmittedOrCancelled().get()));
191     }
192
193     @Test
194     void bigAmountOfTransactionsOnDifferentDevicesWithoutSubmitTest() {
195         int numberOfTxs = 1000;
196         List<DeviceTransaction> deviceTransactions = new LinkedList<>();
197
198         try {
199             for (int i = 0; i < numberOfTxs; i++) {
200                 deviceTransactions.add(transactionManager.getDeviceTransaction(defaultDeviceId + " " + i).get().get());
201             }
202         } catch (InterruptedException | ExecutionException e) {
203             fail("Exception catched! " + e);
204         }
205
206         try {
207             Thread.sleep(transactionManager.getMaxDurationToSubmitTransaction() + 1000);
208         } catch (InterruptedException e) {
209             fail("Exception catched! " + e);
210         }
211         deviceTransactions.parallelStream()
212                 .forEach(deviceTransaction -> assertTrue(deviceTransaction.wasSubmittedOrCancelled().get()));
213     }
214
215     @Test
216     void notSubmittedTransactionTest() {
217         Future<java.util.Optional<DeviceTransaction>> deviceTxFuture =
218                 transactionManager.getDeviceTransaction(defaultDeviceId);
219         try {
220             deviceTxFuture.get();
221             Thread.sleep(transactionManager.getMaxDurationToSubmitTransaction() + 1000);
222         } catch (InterruptedException | ExecutionException e) {
223             fail("Exception catched! " + e);
224         }
225         Mockito.verify(rwTransactionMock, Mockito.times(1)).cancel();
226
227         try {
228             putAndSubmit(transactionManager, defaultDeviceId, defaultDatastore, defaultIid, defaultData);
229         } catch (InterruptedException | ExecutionException e) {
230             fail("Exception catched! " + e);
231             return;
232         }
233
234         Mockito.verify(rwTransactionMock, Mockito.times(1)).cancel();
235         Mockito.verify(rwTransactionMock, Mockito.times(1)).put(defaultDatastore, defaultIid, defaultData);
236         Mockito.verify(rwTransactionMock, Mockito.times(1)).commit();
237     }
238
239     @Test
240     void dataBrokerTimeoutTransactionTest() {
241         Mockito.when(dataBrokerMock.newReadWriteTransaction()).then(invocation -> {
242             Thread.sleep(transactionManager.getMaxDurationToSubmitTransaction() + 1000);
243             return rwTransactionMock;
244         });
245
246         try {
247             putAndSubmit(transactionManager, defaultDeviceId, defaultDatastore, defaultIid, defaultData);
248         } catch (InterruptedException | ExecutionException e) {
249             fail("Exception catched! " + e);
250         }
251
252         Mockito.verify(rwTransactionMock, Mockito.times(1)).commit();
253
254         Mockito.when(dataBrokerMock.newReadWriteTransaction()).thenReturn(rwTransactionMock); // remove sleep
255
256         try {
257             putAndSubmit(transactionManager, defaultDeviceId, defaultDatastore, defaultIid, defaultData);
258         } catch (InterruptedException | ExecutionException e) {
259             fail("Exception catched! " + e);
260             return;
261         }
262
263         Mockito.verify(rwTransactionMock, Mockito.times(2)).put(defaultDatastore, defaultIid, defaultData);
264         Mockito.verify(rwTransactionMock, Mockito.times(2)).commit();
265     }
266
267     @Test
268     void getFutureTimeoutTransactionTest() {
269         Mockito.when(dataBrokerMock.newReadWriteTransaction()).then(invocation -> {
270             Thread.sleep(3000);
271             return rwTransactionMock;
272         });
273
274         Exception throwedException = null;
275
276         Future<java.util.Optional<DeviceTransaction>> deviceTxFuture =
277                 transactionManager.getDeviceTransaction(defaultDeviceId);
278         try {
279             deviceTxFuture.get(1000, TimeUnit.MILLISECONDS);
280         } catch (InterruptedException | ExecutionException e) {
281             fail("Exception catched! " + e);
282         } catch (TimeoutException e) {
283             throwedException = e;
284         }
285
286         if (throwedException == null) {
287             fail("TimeoutException should be thrown!");
288             return;
289         }
290
291         Mockito.when(dataBrokerMock.newReadWriteTransaction()).thenReturn(rwTransactionMock); // remove sleep
292
293         try {
294             putAndSubmit(transactionManager, defaultDeviceId, defaultDatastore, defaultIid, defaultData);
295         } catch (InterruptedException | ExecutionException e) {
296             fail("Exception catched! " + e);
297             return;
298         }
299
300         Mockito.verify(rwTransactionMock, Mockito.times(1)).put(defaultDatastore, defaultIid, defaultData);
301         Mockito.verify(rwTransactionMock, Mockito.times(1)).commit();
302     }
303
304     private <T extends DataObject> void putAndSubmit(DeviceTransactionManagerImpl deviceTxManager, String deviceId,
305             LogicalDatastoreType store, InstanceIdentifier<T> path, T data)
306             throws ExecutionException, InterruptedException {
307         Future<java.util.Optional<DeviceTransaction>> deviceTxFuture = deviceTxManager.getDeviceTransaction(deviceId);
308         DeviceTransaction deviceTx = deviceTxFuture.get().get();
309         deviceTx.put(store, path, data);
310         deviceTx.commit(defaultTimeout, defaultTimeUnit);
311     }
312 }