72964889366ecaf814f913b7808b29ac64565628
[genius.git] / lockmanager / lockmanager-impl / src / test / java / org / opendaylight / genius / 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.genius.lockmanager.tests;
9
10 import static org.opendaylight.serviceutils.tools.mdsal.testutils.TestFutureRpcResults.assertRpcErrorCause;
11 import static org.opendaylight.serviceutils.tools.mdsal.testutils.TestFutureRpcResults.assertRpcErrorWithoutCausesOrMessages;
12 import static org.opendaylight.serviceutils.tools.mdsal.testutils.TestFutureRpcResults.assertRpcSuccess;
13
14 import java.util.Timer;
15 import java.util.TimerTask;
16 import java.util.concurrent.ExecutionException;
17 import java.util.concurrent.TimeoutException;
18 import javax.inject.Inject;
19 import org.junit.Rule;
20 import org.junit.Test;
21 import org.junit.rules.MethodRule;
22 import org.opendaylight.genius.datastoreutils.testutils.DataBrokerFailures;
23 import org.opendaylight.genius.datastoreutils.testutils.DataBrokerFailuresModule;
24 import org.opendaylight.genius.lockmanager.impl.LockManagerServiceImpl;
25 import org.opendaylight.genius.lockmanager.impl.LockManagerUtils;
26 import org.opendaylight.infrautils.inject.guice.testutils.GuiceRule;
27 import org.opendaylight.infrautils.testutils.LogCaptureRule;
28 import org.opendaylight.infrautils.testutils.LogRule;
29 import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractConcurrentDataBrokerTest;
30 import org.opendaylight.mdsal.common.api.OptimisticLockFailedException;
31 import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockInput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockInputBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockManagerService;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TimeUnits;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TryLockInput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TryLockInputBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.UnlockInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.UnlockInputBuilder;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 /**
44  * Test for {@link LockManagerServiceImpl}.
45  *
46  * @author Michael Vorburger.ch
47  */
48 public class LockManagerTest extends AbstractConcurrentDataBrokerTest {
49
50     private static final Logger LOG = LoggerFactory.getLogger(LockManagerTest.class);
51
52     public @Rule LogRule logRule = new LogRule();
53     public @Rule LogCaptureRule logCaptureRule = new LogCaptureRule();
54     public @Rule MethodRule guice = new GuiceRule(LockManagerTestModule.class, DataBrokerFailuresModule.class);
55
56     @Inject DataBrokerFailures dbFailureSimulator;
57     @Inject LockManagerService lockManager;
58     @Inject LockManagerUtils lockManagerUtils;
59
60     @Test
61     public void testLockAndUnLock() throws InterruptedException, ExecutionException, TimeoutException {
62         LockInput lockInput = new LockInputBuilder().setLockName("testLock").build();
63         assertRpcSuccess(lockManager.lock(lockInput));
64
65         UnlockInput unlockInput = new UnlockInputBuilder().setLockName("testLock").build();
66         assertRpcSuccess(lockManager.unlock(unlockInput));
67     }
68
69     @Test
70     public void testUnLockOfUnknownShouldNotFail() throws InterruptedException, ExecutionException, TimeoutException {
71         UnlockInput unlockInput = new UnlockInputBuilder().setLockName("unknownLock").build();
72         assertRpcSuccess(lockManager.unlock(unlockInput));
73     }
74
75     @Test
76     // test re-lock of already locked key.
77     // lock() RPC will infinitely retry, and it will only come out when the key is unlocked
78     public void testLockAndReLockSameAgain() throws InterruptedException, ExecutionException, TimeoutException {
79         LockInput lockInput = new LockInputBuilder().setLockName("testLock").build();
80         assertRpcSuccess(lockManager.lock(lockInput));
81         runUnlockTimerTask("testLock", 3000);
82
83         // This will retry infinitely since the other lock is not released!
84         // After 5 seconds, the parallel thread will unlock the key, and the below TC will pass
85         assertRpcSuccess(lockManager.lock(lockInput));
86     }
87
88     @Test
89     // test re-lock of already locked key using tryLock() RPC.
90     // tryLock() RPC will retry only specific number of times, and it will only return after that
91     public void testTryLock() throws InterruptedException, ExecutionException, TimeoutException {
92         String uniqueId = lockManagerUtils.getBladeId() + ":2";
93         logCaptureRule.expectError("Failed to get lock testTryLock owner " + uniqueId + " after 3 retries");
94
95         TryLockInput lockInput = new TryLockInputBuilder().setLockName("testTryLock").setTime(3L)
96                 .setTimeUnit(TimeUnits.Seconds).build();
97         assertRpcSuccess(lockManager.tryLock(lockInput));
98
99         // The second acquireLock request will retry for 3 seconds
100         // and since the first lock is not unlocked, the request will fail.
101         lockInput = new TryLockInputBuilder().setLockName("testTryLock").setTime(3000L)
102                 .setTimeUnit(TimeUnits.Milliseconds).build();
103         assertRpcErrorWithoutCausesOrMessages(lockManager.tryLock(lockInput));
104
105         // Try to unlock the key in a separate thread before retry expires, and see
106         // if lock gets acquired.
107         runUnlockTimerTask("testTryLock", 2000);
108
109         lockInput = new TryLockInputBuilder().setLockName("testTryLock").setTime(4000000L)
110                 .setTimeUnit(TimeUnits.Microseconds).build();
111         assertRpcSuccess(lockManager.tryLock(lockInput));
112     }
113
114     @Test
115     public void test3sOptimisticLockFailedExceptionOnLock()
116             throws InterruptedException, ExecutionException, TimeoutException {
117         dbFailureSimulator.failSubmits(new OptimisticLockFailedException("bada boum bam!"));
118         LockInput lockInput = new LockInputBuilder().setLockName("testLock").build();
119         runUnfailSubmitsTimerTask(3000); // see other tests above
120         assertRpcSuccess(lockManager.lock(lockInput));
121     }
122
123     @Test
124     public void testAskTimeOutException() throws InterruptedException, ExecutionException, TimeoutException {
125         String lockName = "testLock";
126         logCaptureRule.expectError("Unable to acquire lock for " + lockName + ", try 1", 1);
127         dbFailureSimulator.failButSubmitsAnyways();
128         LockInput lockInput = new LockInputBuilder().setLockName(lockName).build();
129         assertRpcErrorCause(lockManager.lock(lockInput), TransactionCommitFailedException.class,
130                 "caused by simulated AskTimeoutException");
131     }
132
133     @Test
134     public void testEternalTransactionCommitFailedExceptionOnLock()
135             throws InterruptedException, ExecutionException, TimeoutException {
136         logCaptureRule.expectError("RPC lock() failed; input = LockInput{lockName=testLock, augmentation=[]}");
137         dbFailureSimulator.failSubmits(new TransactionCommitFailedException("bada boum bam!"));
138         LockInput lockInput = new LockInputBuilder().setLockName("testLock").build();
139         assertRpcErrorCause(lockManager.lock(lockInput), TransactionCommitFailedException.class, "bada boum bam!");
140     }
141
142     // TODO testEternalReadFailedExceptionOnLock() throws InterruptedException, ExecutionException, TimeoutException {
143
144     // TODO test3sOptimisticLockFailedExceptionOnUnLock()
145     // TODO testEternalReadFailedExceptionOnUnLock()
146     // TODO testEternalTransactionCommitFailedExceptionOnUnLock()
147
148     // TODO test3sOptimisticLockFailedExceptionOnTryLock()
149     // TODO testEternalReadFailedExceptionOnTryLock()
150     // TODO testEternalTransactionCommitFailedExceptionOnTryLock()
151
152     private void runUnlockTimerTask(String lockKey, long delay) {
153         Timer timer = new Timer();
154         timer.schedule(new TimerTask() {
155             @Override
156             public void run() {
157                 UnlockInput unlockInput = new UnlockInputBuilder().setLockName(lockKey).build();
158                 try {
159                     assertRpcSuccess(lockManager.unlock(unlockInput));
160                 } catch (InterruptedException | ExecutionException | TimeoutException e) {
161                     LOG.error("runUnlockTimerTask() failed", e);
162                     // throw new RuntimeException(e) is useless here, as this in a BG Thread, and it would go nowhere
163                 }
164             }
165         }, delay);
166     }
167
168     private void runUnfailSubmitsTimerTask(long delay) {
169         Timer timer = new Timer();
170         timer.schedule(new TimerTask() {
171             @Override
172             public void run() {
173                 dbFailureSimulator.unfailSubmits();
174             }
175         }, delay);
176     }
177
178 }