f97374e15691cf19fce04add0c99cd1c4414fab6
[genius.git] / lockmanager / lockmanager-impl / src / test / java / org / opendaylight / lockmanager / tests / LockManagerTest.java
1 /*
2  * Copyright (c) 2017 Red Hat, 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 package org.opendaylight.lockmanager.tests;
9
10 import static com.google.common.truth.Truth.assertThat;
11
12 import java.util.Timer;
13 import java.util.TimerTask;
14 import java.util.concurrent.ExecutionException;
15 import java.util.concurrent.Future;
16 import java.util.concurrent.TimeUnit;
17 import java.util.concurrent.TimeoutException;
18
19 import javax.inject.Inject;
20
21 import org.junit.Rule;
22 import org.junit.Test;
23 import org.junit.rules.MethodRule;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.test.AbstractConcurrentDataBrokerTest;
26 import org.opendaylight.genius.datastoreutils.testutils.TestableDataTreeChangeListenerModule;
27 import org.opendaylight.infrautils.inject.guice.testutils.GuiceRule;
28 import org.opendaylight.infrautils.testutils.LogRule;
29 import org.opendaylight.lockmanager.LockManager;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockInput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockInputBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockManagerService;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TimeUnits;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TryLockInput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TryLockInputBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.UnlockInput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.UnlockInputBuilder;
38 import org.opendaylight.yangtools.yang.common.RpcResult;
39
40 /**
41  * Test for {@link LockManager}.
42  * @author Michael Vorburger.ch
43  */
44 public class LockManagerTest extends AbstractConcurrentDataBrokerTest {
45
46     public final @Rule LogRule logRule = new LogRule();
47     @Inject DataBroker dataBroker;
48     @Inject LockManagerService lockManager;
49     public @Rule MethodRule guice = new GuiceRule(new LockManagerTestModule(),
50             new TestableDataTreeChangeListenerModule());
51
52     @Test
53     public void testLockAndUnLock() throws InterruptedException, ExecutionException, TimeoutException {
54         LockInput lockInput = new LockInputBuilder().setLockName("testLock").build();
55         assertSuccessfulFutureRpcResult(lockManager.lock(lockInput));
56
57         UnlockInput unlockInput = new UnlockInputBuilder().setLockName("testLock").build();
58         assertSuccessfulFutureRpcResult(lockManager.unlock(unlockInput));
59     }
60
61     @Test
62     public void testUnLockOfUnknownShouldNotFail() throws InterruptedException, ExecutionException, TimeoutException {
63         UnlockInput unlockInput = new UnlockInputBuilder().setLockName("unknownLock").build();
64         assertSuccessfulFutureRpcResult(lockManager.unlock(unlockInput));
65     }
66
67     @Test
68     // test re-lock of already locked key.
69     // lock() RPC will infinitely retry, and it will only come out when the key is unlocked
70     public void testLockAndReLockSameAgain() throws InterruptedException, ExecutionException, TimeoutException {
71         LockInput lockInput = new LockInputBuilder().setLockName("testLock").build();
72         assertSuccessfulFutureRpcResult(lockManager.lock(lockInput));
73         runUnlockTimerTask("testLock", 3000);
74
75         // This will retry infinitely since the other lock is not released!
76         // After 5 seconds, the parallel thread will unlock the key, and the below TC will pass
77         assertSuccessfulFutureRpcResult(lockManager.lock(lockInput));
78     }
79
80     @Test
81     // test re-lock of already locked key using tryLock() RPC.
82     // tryLock() RPC will retry only specific number of times, and it will only return after that
83     public void testTryLock() throws InterruptedException, ExecutionException, TimeoutException {
84         TryLockInput lockInput = new TryLockInputBuilder().setLockName("testTryLock").setTime(3L)
85             .setTimeUnit(TimeUnits.Seconds).build();
86         assertSuccessfulFutureRpcResult(lockManager.tryLock(lockInput));
87
88         // The second acquireLock request will retry for 3 seconds
89         // and since the first lock is not unlocked, the request will fail.
90         lockInput = new TryLockInputBuilder().setLockName("testTryLock").setTime(3000L)
91             .setTimeUnit(TimeUnits.Milliseconds).build();
92         assertFailedFutureRpcResult(lockManager.tryLock(lockInput));
93
94         // Try to unlock the key in a separate thread before retry expires, and see
95         // if lock gets acquired.
96         runUnlockTimerTask("testTryLock", 2000);
97
98         lockInput = new TryLockInputBuilder().setLockName("testTryLock").setTime(4000000L)
99             .setTimeUnit(TimeUnits.Microseconds).build();
100         assertSuccessfulFutureRpcResult(lockManager.tryLock(lockInput));
101     }
102
103
104     private void assertSuccessfulFutureRpcResult(Future<RpcResult<Void>> futureRpcResult)
105             throws InterruptedException, ExecutionException, TimeoutException {
106         assertThat(futureRpcResult.get(5, TimeUnit.SECONDS).isSuccessful()).isTrue();
107         assertThat(futureRpcResult.get(5, TimeUnit.SECONDS).getErrors()).isEmpty();
108     }
109
110     private void assertFailedFutureRpcResult(Future<RpcResult<Void>> futureRpcResult)
111             throws InterruptedException, ExecutionException, TimeoutException {
112         assertThat(futureRpcResult.get(5, TimeUnit.SECONDS).isSuccessful()).isFalse();
113     }
114
115     private void runUnlockTimerTask(String lockKey, long delay) {
116         Timer timer = new Timer();
117         timer.schedule(new TimerTask() {
118             @Override
119             public void run() {
120                 UnlockInput unlockInput = new UnlockInputBuilder().setLockName(lockKey).build();
121                 try {
122                     assertSuccessfulFutureRpcResult(lockManager.unlock(unlockInput));
123                 } catch (InterruptedException | ExecutionException | TimeoutException e) {
124                     throw new RuntimeException(e);
125                 }
126             }
127         }, delay);
128     }
129 }