Moving all files to root directory
[appc.git] / appc-dispatcher / appc-dispatcher-common / lock-manager-lib / lock-manager-impl / src / test / java / org / openecomp / appc / lockmanager / impl / sql / optimistic / TestMySqlLockManager.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : APP-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *                                              reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  * 
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  * 
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.openecomp.appc.lockmanager.impl.sql.optimistic;
23
24 import org.junit.Assert;
25 import org.junit.Test;
26 import org.openecomp.appc.lockmanager.api.LockException;
27 import org.openecomp.appc.lockmanager.impl.sql.JdbcLockManager;
28 import org.openecomp.appc.lockmanager.impl.sql.MySqlLockManagerBaseTests;
29 import org.openecomp.appc.lockmanager.impl.sql.Synchronizer;
30
31 import java.util.concurrent.*;
32
33 public class TestMySqlLockManager extends MySqlLockManagerBaseTests {
34
35         @Override
36         protected JdbcLockManager createJdbcLockManager(boolean useReal) {
37                 return new MySqlLockManagerMock(useReal);
38         }
39
40         @Test
41         public void testConcurrentLockDifferentOwners() throws LockException, InterruptedException, ExecutionException, TimeoutException {
42
43                 final int participantsNo = 2;
44                 Synchronizer synchronizer = new Synchronizer(participantsNo) {
45
46                         private boolean wait = true;
47
48                         @Override
49                         public void preAddLockRecord(String resource, String owner) {
50                                 if(Owner.A.name().equals(owner)) {
51                                         synchronized(this) {
52                                                 if(wait) {
53                                                         waitOn(this);
54                                                 }
55                                         }
56                                 }
57                         }
58
59                         @Override
60                         public void postAddLockRecord(String resource, String owner) {
61                                 if(!Owner.A.name().equals(owner)) {
62                                         synchronized(this) {
63                                                 notifyAll();
64                                                 wait = false;
65                                         }
66                                 }
67                         }
68
69                         @Override
70                         public void preUpdateLockRecord(String resource, String owner) {
71                                 preAddLockRecord(resource, owner);
72                         }
73
74                         @Override
75                         public void postUpdateLockRecord(String resource, String owner) {
76                                 postAddLockRecord(resource, owner);
77                         }
78                 };
79                 if(!setSynchronizer(synchronizer)) {
80                         return;
81                 }
82                 ExecutorService executor = Executors.newFixedThreadPool(participantsNo);
83                 // acquireLock by owner A should fail as it will wait for acquireLock by owner B
84                 Future<Boolean> future1 = executor.submit(new Callable<Boolean>() {
85                         @Override
86                         public Boolean call() throws Exception {
87                                 try {
88                                         lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name());
89                                         return false;
90                                 } catch(LockException e) {
91                                         // this call should fail as Synchronizer delays its lock to make sure the second call locks the resource first
92                                         Assert.assertEquals("Cannot lock resource [" + Resource.Resource1.name() + "] for [" + Owner.A.name() + "]: already locked by [" + Owner.B.name() + "]", e.getMessage());
93                                         return true;
94                                 }
95                         }
96                 });
97                 try {
98                         // acquireLock by owner B should success
99                         Future<Boolean> future2 = executor.submit(new Callable<Boolean>() {
100                                 @Override
101                                 public Boolean call() throws Exception {
102                                         // this call should success as Synchronizer delays the above lock to make sure this call success to lock the resource
103                                         return lockManager.acquireLock(Resource.Resource1.name(), Owner.B.name());
104                                 }
105                         });
106                         try {
107                                 Assert.assertTrue(future2.get(CONCURRENT_TEST_WAIT_TIME, TimeUnit.SECONDS));
108                                 Assert.assertTrue(future1.get(CONCURRENT_TEST_WAIT_TIME, TimeUnit.SECONDS));
109                         } finally {
110                                 future2.cancel(true);
111                         }
112                 } finally {
113                         future1.cancel(true);
114                 }
115         }
116
117         @Test
118         public void testConcurrentLockSameOwner() throws LockException, InterruptedException, ExecutionException, TimeoutException {
119                 final int participantsNo = 2;
120                 Synchronizer synchronizer = new Synchronizer(participantsNo) {
121
122                         private boolean wait = true;
123
124                         @Override
125                         public void preAddLockRecord(String resource, String owner) {
126                                 synchronized(this) {
127                                         if(wait) {
128                                                 wait = false;
129                                                 waitOn(this);
130                                         }
131                                 }
132                         }
133
134                         @Override
135                         public void postAddLockRecord(String resource, String owner) {
136                                 synchronized(this) {
137                                         notifyAll();
138                                 }
139                         }
140                 };
141                 if(!setSynchronizer(synchronizer)) {
142                         return;
143                 }
144                 ExecutorService executor = Executors.newFixedThreadPool(participantsNo);
145                 // one acquireLock should return true and the other should return false
146                 Callable<Boolean> callable = new Callable<Boolean>() {
147                         @Override
148                         public Boolean call() throws Exception {
149                                 return lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name());
150                         }
151                 };
152                 Future<Boolean> future1 = executor.submit(callable);
153                 try {
154                         Future<Boolean> future2 = executor.submit(callable);
155                         try {
156                                 boolean future1Res = future1.get(CONCURRENT_TEST_WAIT_TIME, TimeUnit.SECONDS);
157                                 boolean future2Res = future2.get(CONCURRENT_TEST_WAIT_TIME, TimeUnit.SECONDS);
158                                 // one of the lock requests should return true, the other one false as lock is requested simultaneously from 2 threads by same owner
159                                 Assert.assertNotEquals(future1Res, future2Res);
160                         } finally {
161                                 future2.cancel(true);
162                         }
163                 } finally {
164                         future1.cancel(true);
165                 }
166         }
167
168         @Test
169         public void testConcurrentUnlockSameOwner() throws LockException, InterruptedException, ExecutionException, TimeoutException {
170                 lockManager.acquireLock(Resource.Resource1.name(), Owner.A.name());
171                 final int participantsNo = 2;
172                 Synchronizer synchronizer = new Synchronizer(participantsNo) {
173
174                         private boolean wait = true;
175
176                         @Override
177                         public void preUpdateLockRecord(String resource, String owner) {
178                                 synchronized(this) {
179                                         // make sure second call updates the LockRecord first
180                                         if(wait) {
181                                                 wait = false;
182                                                 waitOn(this);
183                                         }
184                                 }
185                         }
186
187                         @Override
188                         public void postUpdateLockRecord(String resource, String owner) {
189                                 synchronized(this) {
190                                         notifyAll();
191                                 }
192                         }
193                 };
194                 if(!setSynchronizer(synchronizer)) {
195                         return;
196                 }
197                 ExecutorService executor = Executors.newFixedThreadPool(participantsNo);
198                 Callable<Boolean> callable = new Callable<Boolean>() {
199                         @Override
200                         public Boolean call() throws Exception {
201                                 try {
202                                         lockManager.releaseLock(Resource.Resource1.name(), Owner.A.name());
203                                         // one of the unlock calls should success
204                                         return true;
205                                 } catch(LockException e) {
206                                         // one of the unlock calls should throw the LockException as the resource should already be unlocked by other call
207                                         Assert.assertEquals("Error unlocking resource [" + Resource.Resource1.name() + "]: resource is not locked", e.getMessage());
208                                         return false;
209                                 }
210                         }
211                 };
212                 Future<Boolean> future1 = executor.submit(callable);
213                 try {
214                         Future<Boolean> future2 = executor.submit(callable);
215                         try {
216                                 boolean future1Res = future1.get(CONCURRENT_TEST_WAIT_TIME, TimeUnit.SECONDS);
217                                 boolean future2Res = future2.get(CONCURRENT_TEST_WAIT_TIME, TimeUnit.SECONDS);
218                                 // one of the unlock calls should return true, the other one false as unlock is requested simultaneously from 2 threads by same owner
219                                 Assert.assertNotEquals(future1Res, future2Res);
220                         } finally {
221                                 future2.cancel(true);
222                         }
223                 } finally {
224                         future1.cancel(true);
225                 }
226         }
227 }