package org.ovirt.engine.core.dao; import java.util.ArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Before; import org.junit.Test; import org.ovirt.engine.core.common.businessentities.TagsType; import org.ovirt.engine.core.common.businessentities.tags; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.compat.LogCompat; import org.ovirt.engine.core.compat.LogFactoryCompat; import org.ovirt.engine.core.utils.thread.LatchedRunnableWrapper; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; /** * The following test checks multi-threading issues with DAO usage. * The test uses the TagsDAO, but any other DAO can be used */ public class MultiThreadedDAOTest extends BaseDAOTestCase { private TagDAO dao; private LogCompat log = LogFactoryCompat.getLog(MultiThreadedDAOTest.class); private static final Guid[] EXISTING_TAGS_IDS = { Guid.createGuidFromString("d3ec3e01-ca89-48e1-8b43-a9b38f873b0c"), Guid.createGuidFromString("d3ec3e01-ca89-48e1-8b43-a9b38f873b0d"), Guid.createGuidFromString("d3ec3e01-ca89-48e1-8b43-a9b38f873b0e") }; private CountDownLatch latch = null; @Override @Before public void setUp() throws Exception { super.setUp(); dao = prepareDAO(dbFacade.getTagDAO()); } @Test public void testGetSameID() throws Exception { final tags existing = dao.get(EXISTING_TAGS_IDS[0]); createAndRunThreadsForRunner(new Runnable() { @Override public void run() { tags result = dao.get(existing.gettag_id()); assertEquals(existing, result); } }, 100); } @Test public void testGetDifferentID() throws Exception { final AtomicInteger counter = new AtomicInteger(); final tags[] existingTags = new tags[EXISTING_TAGS_IDS.length]; for (int i = 0; i < EXISTING_TAGS_IDS.length; i++) { existingTags[i] = dao.get(EXISTING_TAGS_IDS[i]); } createAndRunThreadsForRunner(new Runnable() { @Override public void run() { int val = counter.incrementAndGet(); int index = val % EXISTING_TAGS_IDS.length; tags result = dao.get(EXISTING_TAGS_IDS[index]); assertEquals(existingTags[index], result); } }, 100); } @Test public void testReadWriteDelete() throws Exception { final AtomicInteger counter = new AtomicInteger(); createAndRunThreadsForRunner(new Runnable() { @Override public void run() { int val = counter.incrementAndGet(); tags tag = createTag("tag" + val, "desc" + val); dao.save(tag); tags fromDb = dao.get(tag.gettag_id()); assertEquals(tag, fromDb); dao.remove(tag.gettag_id()); fromDb = dao.get(tag.gettag_id()); assertNull(fromDb); } }, 100); } private tags createTag(String name, String desc) { tags tag = new tags(); tag.setChildren(new ArrayList<tags>()); tag.setdescription(desc); tag.settag_name(name); tag.setIsReadonly(true); tag.setparent_id(Guid.Empty); tag.settype(TagsType.GeneralTag); return tag; } private void createAndRunThreadsForRunner(Runnable runnable, int numOfThreads) throws Exception { if (runnable == null) { return; } latch = new CountDownLatch(numOfThreads); ExecutorService threadPool = Executors.newFixedThreadPool(numOfThreads); for (int counter = 0; counter < numOfThreads; counter++) { threadPool.execute(new LatchedRunnableWrapper(runnable, latch)); } latch.await(); } }