/***************************************************************************
* Copyright (c) 2012-2014 VMware, Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
package com.vmware.bdd.manager;
import mockit.Mock;
import mockit.MockUp;
import mockit.Mockit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.vmware.bdd.aop.lock.LockFactory;
import com.vmware.bdd.manager.intf.IConcurrentLockedClusterEntityManager;
import com.vmware.bdd.manager.intf.IExclusiveLockedClusterEntityManager;
import com.vmware.bdd.manager.intf.ILockedClusterEntityManager;
import com.vmware.bdd.service.impl.ClusterSyncService;
import com.vmware.bdd.service.sp.MockClusterEntityManager;
@ContextConfiguration(locations = { "classpath:/spring/*-context.xml", "classpath:/spring/aop.xml" })
public class TestLockedClusterEntityManager extends AbstractTestNGSpringContextTests {
private MockClusterEntityManager mockedMgr;
private static class LockTestThread extends Thread {
private ILockedClusterEntityManager clusterEntityMgr;
private volatile boolean started = false;
public LockTestThread(ILockedClusterEntityManager clusterEntityMgr) {
this.clusterEntityMgr = clusterEntityMgr;
}
public boolean isStarted() {
return started;
}
@Override
public void run() {
started = true;
clusterEntityMgr.syncUp(LOCKED_CLUSTER_NAME, false);
}
}
private static final String LOCKED_CLUSTER_NAME = "LockedClusterEntity";
private static final String UNLOCKED_CLUSTER_NAME = "UnLockedClusterEntity";
@Autowired
private IConcurrentLockedClusterEntityManager competitiveLockedMgr;
@Autowired
private IExclusiveLockedClusterEntityManager exclusiveLockedMgr;
@BeforeClass
public void setup() {
new MockUp<ClusterSyncService>() {
@Mock
public void syncUp(String clusterName, boolean updateClusterStatus) {
try {
Thread.sleep(200);
System.out.println("ClusterSyncService MOCK: Sleep 200ms.");
} catch(Exception e) {
e.printStackTrace(System.out);
}
}
};
mockedMgr = new MockClusterEntityManager();
competitiveLockedMgr.setClusterEntityMgr(mockedMgr);
exclusiveLockedMgr.setClusterEntityMgr(mockedMgr);
Mockit.setUpMock(MockClusterEntityManager.class);
}
@AfterClass
public void deleteAll() {
}
@Test
public void testConcurrentWrite() {
competitiveLockedMgr.removeVmReference(LOCKED_CLUSTER_NAME, "");
exclusiveLockedMgr.removeVmReference(LOCKED_CLUSTER_NAME, "");
}
@Test
public void testSequentialInOneThread() throws Exception {
competitiveLockedMgr.removeVmReference(LOCKED_CLUSTER_NAME, "");
exclusiveLockedMgr.removeVmReference(LOCKED_CLUSTER_NAME, "");
competitiveLockedMgr.removeVmReference(LOCKED_CLUSTER_NAME, "");
exclusiveLockedMgr.removeVmReference(LOCKED_CLUSTER_NAME, "");
}
@Test
public void testConcurrencyInTwoThread() throws Exception {
LockTestThread t = new LockTestThread(competitiveLockedMgr);
t.start();
while (!t.isStarted()) {
Thread.sleep(10);
}
long start = System.currentTimeMillis();
competitiveLockedMgr.removeVmReference(LOCKED_CLUSTER_NAME, "");
long end = System.currentTimeMillis();
System.out.println("Lock takes " + (end - start) + "ms for testConcurrencyInTwoThread");
Assert.assertTrue((end - start) < 150);
t.join();
}
@Test
public void testExclusiveInTwoThread() throws Exception {
LockTestThread t = new LockTestThread(exclusiveLockedMgr);
t.start();
while (!t.isStarted()) {
Thread.sleep(10);
}
long start = System.currentTimeMillis();
exclusiveLockedMgr.removeVmReference(LOCKED_CLUSTER_NAME, "");
long end = System.currentTimeMillis();
System.out.println("Lock takes " + (end - start) + "ms for testExclusiveInTwoThread");
Assert.assertTrue((end - start) > 150);
t.join();
}
@Test
public void testExclusiveCompetitiveInTwoThread() throws Exception {
LockTestThread t = new LockTestThread(exclusiveLockedMgr);
t.start();
while (!t.isStarted()) {
Thread.sleep(10);
}
Thread.sleep(40);
long start = System.currentTimeMillis();
exclusiveLockedMgr.removeVmReference(LOCKED_CLUSTER_NAME, "");
long end = System.currentTimeMillis();
System.out.println("Lock takes " + (end - start) + "ms for testExclusiveCompetitiveInTwoThread");
// the lock time is impacted by previous test case execution.
Assert.assertTrue((end - start) >= 100, "Expected bigger than 100, but got " + (end - start));
t.join();
}
@Test
public void testReverseInTwoThread() throws Exception {
LockTestThread t = new LockTestThread(competitiveLockedMgr);
t.start();
while (!t.isStarted()) {
Thread.sleep(10);
}
long start = System.currentTimeMillis();
exclusiveLockedMgr.removeVmReference(LOCKED_CLUSTER_NAME, "");
long end = System.currentTimeMillis();
System.out.println("Lock takes " + (end - start) + "ms testReverseInTwoThread");
Assert.assertTrue((end - start) > 150);
t.join();
}
@Test
public void testCompetitiveInTwoThreadForTwoClusters() throws Exception {
LockTestThread t = new LockTestThread(exclusiveLockedMgr);
t.start();
while (!t.isStarted()) {
Thread.sleep(10);
}
long start = System.currentTimeMillis();
exclusiveLockedMgr.removeVmReference(UNLOCKED_CLUSTER_NAME, "");
long end = System.currentTimeMillis();
System.out.println("Lock takes " + (end - start) + "ms for testCompetitiveInTwoThreadForTwoClusters");
Assert.assertTrue((end - start) < 150);
t.join();
}
@Test
public void testReleaseDelayed() throws Exception {
long start = System.currentTimeMillis();
LockFactory.getClusterLock(LOCKED_CLUSTER_NAME).writeLock().lock();
System.out.println("Lock exlusively for " + LOCKED_CLUSTER_NAME
+ " separately.");
LockTestThread t = new LockTestThread(exclusiveLockedMgr);
t.start();
Thread.sleep(50);
LockFactory.getClusterLock(LOCKED_CLUSTER_NAME).writeLock().unlock();
t.join();
long end = System.currentTimeMillis();
System.out.println("Lock takes " + (end - start) + "ms for testReleaseDelayed");
Assert.assertTrue((end - start) > 230);
}
}