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.opendaylight.yangtools.yang.common.Uint32;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
45 * Test for {@link LockManagerServiceImpl}.
47 * @author Michael Vorburger.ch
49 public class LockManagerTest extends AbstractConcurrentDataBrokerTest {
51 private static final Logger LOG = LoggerFactory.getLogger(LockManagerTest.class);
53 public @Rule LogRule logRule = new LogRule();
54 public @Rule LogCaptureRule logCaptureRule = new LogCaptureRule();
55 public @Rule MethodRule guice = new GuiceRule(LockManagerTestModule.class, DataBrokerFailuresModule.class);
57 @Inject DataBrokerFailures dbFailureSimulator;
58 @Inject LockManagerService lockManager;
59 @Inject LockManagerUtils lockManagerUtils;
62 public void testLockAndUnLock() throws InterruptedException, ExecutionException, TimeoutException {
63 LockInput lockInput = new LockInputBuilder().setLockName("testLock").build();
64 assertRpcSuccess(lockManager.lock(lockInput));
66 UnlockInput unlockInput = new UnlockInputBuilder().setLockName("testLock").build();
67 assertRpcSuccess(lockManager.unlock(unlockInput));
71 public void testUnLockOfUnknownShouldNotFail() throws InterruptedException, ExecutionException, TimeoutException {
72 UnlockInput unlockInput = new UnlockInputBuilder().setLockName("unknownLock").build();
73 assertRpcSuccess(lockManager.unlock(unlockInput));
77 // test re-lock of already locked key.
78 // lock() RPC will infinitely retry, and it will only come out when the key is unlocked
79 public void testLockAndReLockSameAgain() throws InterruptedException, ExecutionException, TimeoutException {
80 LockInput lockInput = new LockInputBuilder().setLockName("testLock").build();
81 assertRpcSuccess(lockManager.lock(lockInput));
82 runUnlockTimerTask("testLock", 3000);
84 // This will retry infinitely since the other lock is not released!
85 // After 5 seconds, the parallel thread will unlock the key, and the below TC will pass
86 assertRpcSuccess(lockManager.lock(lockInput));
90 // test re-lock of already locked key using tryLock() RPC.
91 // tryLock() RPC will retry only specific number of times, and it will only return after that
92 public void testTryLock() throws InterruptedException, ExecutionException, TimeoutException {
93 String uniqueId = lockManagerUtils.getBladeId() + ":2";
94 logCaptureRule.expectError("Failed to get lock testTryLock owner " + uniqueId + " after 3 retries");
96 TryLockInput lockInput = new TryLockInputBuilder().setLockName("testTryLock").setTime(Uint32.valueOf(3))
97 .setTimeUnit(TimeUnits.Seconds).build();
98 assertRpcSuccess(lockManager.tryLock(lockInput));
100 // The second acquireLock request will retry for 3 seconds
101 // and since the first lock is not unlocked, the request will fail.
102 lockInput = new TryLockInputBuilder().setLockName("testTryLock").setTime(Uint32.valueOf(3000))
103 .setTimeUnit(TimeUnits.Milliseconds).build();
104 assertRpcErrorWithoutCausesOrMessages(lockManager.tryLock(lockInput));
106 // Try to unlock the key in a separate thread before retry expires, and see
107 // if lock gets acquired.
108 runUnlockTimerTask("testTryLock", 2000);
110 lockInput = new TryLockInputBuilder().setLockName("testTryLock").setTime(Uint32.valueOf(4000000))
111 .setTimeUnit(TimeUnits.Microseconds).build();
112 assertRpcSuccess(lockManager.tryLock(lockInput));
116 public void test3sOptimisticLockFailedExceptionOnLock()
117 throws InterruptedException, ExecutionException, TimeoutException {
118 dbFailureSimulator.failSubmits(new OptimisticLockFailedException("bada boum bam!"));
119 LockInput lockInput = new LockInputBuilder().setLockName("testLock").build();
120 runUnfailSubmitsTimerTask(3000); // see other tests above
121 assertRpcSuccess(lockManager.lock(lockInput));
125 public void testAskTimeOutException() throws InterruptedException, ExecutionException, TimeoutException {
126 String lockName = "testLock";
127 logCaptureRule.expectError("Unable to acquire lock for " + lockName + ", try 1", 1);
128 dbFailureSimulator.failButSubmitsAnyways();
129 LockInput lockInput = new LockInputBuilder().setLockName(lockName).build();
130 assertRpcErrorCause(lockManager.lock(lockInput), TransactionCommitFailedException.class,
131 "caused by simulated AskTimeoutException");
135 public void testEternalTransactionCommitFailedExceptionOnLock()
136 throws InterruptedException, ExecutionException, TimeoutException {
137 logCaptureRule.expectError("RPC lock() failed; input = LockInput{lockName=testLock, augmentation=[]}");
138 dbFailureSimulator.failSubmits(new TransactionCommitFailedException("bada boum bam!"));
139 LockInput lockInput = new LockInputBuilder().setLockName("testLock").build();
140 assertRpcErrorCause(lockManager.lock(lockInput), TransactionCommitFailedException.class, "bada boum bam!");
143 // TODO testEternalReadFailedExceptionOnLock() throws InterruptedException, ExecutionException, TimeoutException {
145 // TODO test3sOptimisticLockFailedExceptionOnUnLock()
146 // TODO testEternalReadFailedExceptionOnUnLock()
147 // TODO testEternalTransactionCommitFailedExceptionOnUnLock()
149 // TODO test3sOptimisticLockFailedExceptionOnTryLock()
150 // TODO testEternalReadFailedExceptionOnTryLock()
151 // TODO testEternalTransactionCommitFailedExceptionOnTryLock()
153 private void runUnlockTimerTask(String lockKey, long delay) {
154 Timer timer = new Timer();
155 timer.schedule(new TimerTask() {
158 UnlockInput unlockInput = new UnlockInputBuilder().setLockName(lockKey).build();
160 assertRpcSuccess(lockManager.unlock(unlockInput));
161 } catch (InterruptedException | ExecutionException | TimeoutException e) {
162 LOG.error("runUnlockTimerTask() failed", e);
163 // throw new RuntimeException(e) is useless here, as this in a BG Thread, and it would go nowhere
169 private void runUnfailSubmitsTimerTask(long delay) {
170 Timer timer = new Timer();
171 timer.schedule(new TimerTask() {
174 dbFailureSimulator.unfailSubmits();