Update release in docs/conf.yaml
[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().orElseThrow();
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().orElseThrow().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().orElseThrow();
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().orElseThrow();
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().orElseThrow();
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()
181                     .orElseThrow());
182             }
183         } catch (InterruptedException | ExecutionException e) {
184             fail("Exception catched! " + e);
185         }
186
187         deviceTransactions.parallelStream()
188                 .forEach(deviceTransaction -> deviceTransaction.commit(defaultTimeout, defaultTimeUnit));
189
190         deviceTransactions.parallelStream()
191                 .forEach(deviceTransaction -> assertTrue(deviceTransaction.wasSubmittedOrCancelled().get()));
192     }
193
194     @Test
195     void bigAmountOfTransactionsOnDifferentDevicesWithoutSubmitTest() {
196         int numberOfTxs = 1000;
197         List<DeviceTransaction> deviceTransactions = new LinkedList<>();
198
199         try {
200             for (int i = 0; i < numberOfTxs; i++) {
201                 deviceTransactions.add(transactionManager.getDeviceTransaction(defaultDeviceId + " " + i).get()
202                     .orElseThrow());
203             }
204         } catch (InterruptedException | ExecutionException e) {
205             fail("Exception catched! " + e);
206         }
207
208         try {
209             Thread.sleep(transactionManager.getMaxDurationToSubmitTransaction() + 1000);
210         } catch (InterruptedException e) {
211             fail("Exception catched! " + e);
212         }
213         deviceTransactions.parallelStream()
214                 .forEach(deviceTransaction -> assertTrue(deviceTransaction.wasSubmittedOrCancelled().get()));
215     }
216
217     @Test
218     void notSubmittedTransactionTest() {
219         Future<java.util.Optional<DeviceTransaction>> deviceTxFuture =
220                 transactionManager.getDeviceTransaction(defaultDeviceId);
221         try {
222             deviceTxFuture.get();
223             Thread.sleep(transactionManager.getMaxDurationToSubmitTransaction() + 1000);
224         } catch (InterruptedException | ExecutionException e) {
225             fail("Exception catched! " + e);
226         }
227         Mockito.verify(rwTransactionMock, Mockito.times(1)).cancel();
228
229         try {
230             putAndSubmit(transactionManager, defaultDeviceId, defaultDatastore, defaultIid, defaultData);
231         } catch (InterruptedException | ExecutionException e) {
232             fail("Exception catched! " + e);
233             return;
234         }
235
236         Mockito.verify(rwTransactionMock, Mockito.times(1)).cancel();
237         Mockito.verify(rwTransactionMock, Mockito.times(1)).put(defaultDatastore, defaultIid, defaultData);
238         Mockito.verify(rwTransactionMock, Mockito.times(1)).commit();
239     }
240
241     @Test
242     void dataBrokerTimeoutTransactionTest() {
243         Mockito.when(dataBrokerMock.newReadWriteTransaction()).then(invocation -> {
244             Thread.sleep(transactionManager.getMaxDurationToSubmitTransaction() + 1000);
245             return rwTransactionMock;
246         });
247
248         try {
249             putAndSubmit(transactionManager, defaultDeviceId, defaultDatastore, defaultIid, defaultData);
250         } catch (InterruptedException | ExecutionException e) {
251             fail("Exception catched! " + e);
252         }
253
254         Mockito.verify(rwTransactionMock, Mockito.times(1)).commit();
255
256         Mockito.when(dataBrokerMock.newReadWriteTransaction()).thenReturn(rwTransactionMock); // remove sleep
257
258         try {
259             putAndSubmit(transactionManager, defaultDeviceId, defaultDatastore, defaultIid, defaultData);
260         } catch (InterruptedException | ExecutionException e) {
261             fail("Exception catched! " + e);
262             return;
263         }
264
265         Mockito.verify(rwTransactionMock, Mockito.times(2)).put(defaultDatastore, defaultIid, defaultData);
266         Mockito.verify(rwTransactionMock, Mockito.times(2)).commit();
267     }
268
269     @Test
270     void getFutureTimeoutTransactionTest() {
271         Mockito.when(dataBrokerMock.newReadWriteTransaction()).then(invocation -> {
272             Thread.sleep(3000);
273             return rwTransactionMock;
274         });
275
276         Exception throwedException = null;
277
278         Future<java.util.Optional<DeviceTransaction>> deviceTxFuture =
279                 transactionManager.getDeviceTransaction(defaultDeviceId);
280         try {
281             deviceTxFuture.get(1000, TimeUnit.MILLISECONDS);
282         } catch (InterruptedException | ExecutionException e) {
283             fail("Exception catched! " + e);
284         } catch (TimeoutException e) {
285             throwedException = e;
286         }
287
288         if (throwedException == null) {
289             fail("TimeoutException should be thrown!");
290             return;
291         }
292
293         Mockito.when(dataBrokerMock.newReadWriteTransaction()).thenReturn(rwTransactionMock); // remove sleep
294
295         try {
296             putAndSubmit(transactionManager, defaultDeviceId, defaultDatastore, defaultIid, defaultData);
297         } catch (InterruptedException | ExecutionException e) {
298             fail("Exception catched! " + e);
299             return;
300         }
301
302         Mockito.verify(rwTransactionMock, Mockito.times(1)).put(defaultDatastore, defaultIid, defaultData);
303         Mockito.verify(rwTransactionMock, Mockito.times(1)).commit();
304     }
305
306     private <T extends DataObject> void putAndSubmit(DeviceTransactionManagerImpl deviceTxManager, String deviceId,
307             LogicalDatastoreType store, InstanceIdentifier<T> path, T data)
308             throws ExecutionException, InterruptedException {
309         Future<java.util.Optional<DeviceTransaction>> deviceTxFuture = deviceTxManager.getDeviceTransaction(deviceId);
310         DeviceTransaction deviceTx = deviceTxFuture.get().orElseThrow();
311         deviceTx.put(store, path, data);
312         deviceTx.commit(defaultTimeout, defaultTimeUnit);
313     }
314 }