2 * Copyright (c) 2017 Red Hat, Inc. and others. All rights reserved.
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
8 package org.opendaylight.genius.lockmanager.tests;
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;
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;
44 * Test for {@link LockManagerServiceImpl}.
46 * @author Michael Vorburger.ch
48 public class LockManagerTest extends AbstractConcurrentDataBrokerTest {
50 private static final Logger LOG = LoggerFactory.getLogger(LockManagerTest.class);
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);
56 @Inject DataBrokerFailures dbFailureSimulator;
57 @Inject LockManagerService lockManager;
58 @Inject LockManagerUtils lockManagerUtils;
61 public void testLockAndUnLock() throws InterruptedException, ExecutionException, TimeoutException {
62 LockInput lockInput = new LockInputBuilder().setLockName("testLock").build();
63 assertRpcSuccess(lockManager.lock(lockInput));
65 UnlockInput unlockInput = new UnlockInputBuilder().setLockName("testLock").build();
66 assertRpcSuccess(lockManager.unlock(unlockInput));
70 public void testUnLockOfUnknownShouldNotFail() throws InterruptedException, ExecutionException, TimeoutException {
71 UnlockInput unlockInput = new UnlockInputBuilder().setLockName("unknownLock").build();
72 assertRpcSuccess(lockManager.unlock(unlockInput));
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);
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));
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");
95 TryLockInput lockInput = new TryLockInputBuilder().setLockName("testTryLock").setTime(3L)
96 .setTimeUnit(TimeUnits.Seconds).build();
97 assertRpcSuccess(lockManager.tryLock(lockInput));
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));
105 // Try to unlock the key in a separate thread before retry expires, and see
106 // if lock gets acquired.
107 runUnlockTimerTask("testTryLock", 2000);
109 lockInput = new TryLockInputBuilder().setLockName("testTryLock").setTime(4000000L)
110 .setTimeUnit(TimeUnits.Microseconds).build();
111 assertRpcSuccess(lockManager.tryLock(lockInput));
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));
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");
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!");
142 // TODO testEternalReadFailedExceptionOnLock() throws InterruptedException, ExecutionException, TimeoutException {
144 // TODO test3sOptimisticLockFailedExceptionOnUnLock()
145 // TODO testEternalReadFailedExceptionOnUnLock()
146 // TODO testEternalTransactionCommitFailedExceptionOnUnLock()
148 // TODO test3sOptimisticLockFailedExceptionOnTryLock()
149 // TODO testEternalReadFailedExceptionOnTryLock()
150 // TODO testEternalTransactionCommitFailedExceptionOnTryLock()
152 private void runUnlockTimerTask(String lockKey, long delay) {
153 Timer timer = new Timer();
154 timer.schedule(new TimerTask() {
157 UnlockInput unlockInput = new UnlockInputBuilder().setLockName(lockKey).build();
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
168 private void runUnfailSubmitsTimerTask(long delay) {
169 Timer timer = new Timer();
170 timer.schedule(new TimerTask() {
173 dbFailureSimulator.unfailSubmits();