package org.ovirt.engine.core.dao;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
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.Tags;
import org.ovirt.engine.core.common.businessentities.TagsType;
import org.ovirt.engine.core.compat.Guid;
/**
* 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 static final Guid[] EXISTING_TAGS_IDS = {
new Guid("d3ec3e01-ca89-48e1-8b43-a9b38f873b0c"),
new Guid("d3ec3e01-ca89-48e1-8b43-a9b38f873b0d"),
new Guid("d3ec3e01-ca89-48e1-8b43-a9b38f873b0e") };
private CountDownLatch latch = null;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
dao = dbFacade.getTagDao();
}
@Test
public void testGetSameID() throws Exception {
final Tags existing = dao.get(EXISTING_TAGS_IDS[0]);
createAndRunThreadsForRunner(() -> {
Tags result = dao.get(existing.getTagId());
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(() -> {
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(() -> {
int val = counter.incrementAndGet();
Tags tag = createTag("tag" + val, "desc" + val);
dao.save(tag);
Tags fromDb = dao.get(tag.getTagId());
assertEquals(tag, fromDb);
dao.remove(tag.getTagId());
fromDb = dao.get(tag.getTagId());
assertNull(fromDb);
}, 100);
}
private Tags createTag(String name, String desc) {
Tags tag = new Tags();
tag.setChildren(new ArrayList<>());
tag.setDescription(desc);
tag.setTagName(name);
tag.setIsReadonly(true);
tag.setParentId(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();
}
}