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 com.google.common.truth.Truth.assertThat;
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;
19 import javax.inject.Inject;
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.controller.md.sal.common.api.data.OptimisticLockFailedException;
27 import org.opendaylight.genius.datastoreutils.testutils.DataBrokerFailures;
28 import org.opendaylight.genius.datastoreutils.testutils.DataBrokerFailuresModule;
29 import org.opendaylight.genius.lockmanager.LockManager;
30 import org.opendaylight.infrautils.inject.guice.testutils.GuiceRule;
31 import org.opendaylight.infrautils.testutils.LogCaptureRule;
32 import org.opendaylight.infrautils.testutils.LogRule;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockInput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockInputBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockManagerService;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TimeUnits;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TryLockInput;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TryLockInputBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.UnlockInput;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.UnlockInputBuilder;
41 import org.opendaylight.yangtools.yang.common.RpcResult;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
46 * Test for {@link LockManager}.
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 DataBroker dataBroker;
58 @Inject DataBrokerFailures dbFailureSimulator;
59 @Inject LockManagerService lockManager;
62 public void testLockAndUnLock() throws InterruptedException, ExecutionException, TimeoutException {
63 LockInput lockInput = new LockInputBuilder().setLockName("testLock").build();
64 assertSuccessfulFutureRpcResult(lockManager.lock(lockInput));
66 UnlockInput unlockInput = new UnlockInputBuilder().setLockName("testLock").build();
67 assertSuccessfulFutureRpcResult(lockManager.unlock(unlockInput));
71 public void testUnLockOfUnknownShouldNotFail() throws InterruptedException, ExecutionException, TimeoutException {
72 UnlockInput unlockInput = new UnlockInputBuilder().setLockName("unknownLock").build();
73 assertSuccessfulFutureRpcResult(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 assertSuccessfulFutureRpcResult(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 assertSuccessfulFutureRpcResult(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 logCaptureRule.expectError("Failed to get lock testTryLock after 3 retries");
95 TryLockInput lockInput = new TryLockInputBuilder().setLockName("testTryLock").setTime(3L)
96 .setTimeUnit(TimeUnits.Seconds).build();
97 assertSuccessfulFutureRpcResult(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 assertFailedFutureRpcResult(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 assertSuccessfulFutureRpcResult(lockManager.tryLock(lockInput));
115 public void testOptimisticLockFailedException() throws InterruptedException, ExecutionException, TimeoutException {
116 dbFailureSimulator.failSubmits(new OptimisticLockFailedException("bada boum bam!"));
117 LockInput lockInput = new LockInputBuilder().setLockName("testLock").build();
118 runUnfailSubmitsTimerTask(3000); // see other tests above
119 assertSuccessfulFutureRpcResult(lockManager.lock(lockInput));
122 private void assertSuccessfulFutureRpcResult(Future<RpcResult<Void>> futureRpcResult)
123 throws InterruptedException, ExecutionException, TimeoutException {
124 assertThat(futureRpcResult.get(5, TimeUnit.SECONDS).isSuccessful()).isTrue();
125 assertThat(futureRpcResult.get(5, TimeUnit.SECONDS).getErrors()).isEmpty();
128 private void assertFailedFutureRpcResult(Future<RpcResult<Void>> futureRpcResult)
129 throws InterruptedException, ExecutionException, TimeoutException {
130 assertThat(futureRpcResult.get(5, TimeUnit.SECONDS).isSuccessful()).isFalse();
133 private void runUnlockTimerTask(String lockKey, long delay) {
134 Timer timer = new Timer();
135 timer.schedule(new TimerTask() {
138 UnlockInput unlockInput = new UnlockInputBuilder().setLockName(lockKey).build();
140 assertSuccessfulFutureRpcResult(lockManager.unlock(unlockInput));
141 } catch (InterruptedException | ExecutionException | TimeoutException e) {
142 LOG.error("runUnlockTimerTask() failed", e);
143 // throw new RuntimeException(e) is useless here, as this in a BG Thread, and it would go nowhere
149 private void runUnfailSubmitsTimerTask(long delay) {
150 Timer timer = new Timer();
151 timer.schedule(new TimerTask() {
154 dbFailureSimulator.unfailSubmits();