Skip to content

Commit

Permalink
Test for DefaultBoundMapperFacade race condition
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexander Demukh committed Jun 27, 2020
1 parent 19ed073 commit 0af16e7
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package ma.glasnost.orika.test.concurrency;

import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import com.google.common.collect.Lists;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.test.MappingUtil;
import ma.glasnost.orika.test.concurrency.model.ModelWithNestedObjDest;
import ma.glasnost.orika.test.concurrency.model.ModelWithNestedObjSource;
import ma.glasnost.orika.test.concurrency.model.NestedModel;

/**
* Checks that instantiation and cache inside of <{@link ma.glasnost.orika.impl.DefaultBoundMapperFacade} is thread safe.
*/
public class DefaultBoundMapperFacadeConcurrentInitTestCase {

private MapperFacade mapper;

private int threads = 20;
private ExecutorService executor;

@Before
public void setup() {
MapperFactory factory = MappingUtil.getMapperFactory();
factory.classMap(ModelWithNestedObjSource.class, ModelWithNestedObjDest.class)
.byDefault()
.register();

mapper = factory.getMapperFacade();

executor = Executors.newFixedThreadPool(threads);
}

@After
public void cleanup() {
if (executor != null) {
executor.shutdownNow();
}
}

@Test
public void testCase() {
CountDownLatch readyLatch = new CountDownLatch(threads);

List<Future<?>> futures = IntStream.range(0, threads).mapToObj(i ->
executor.submit(() -> {
ModelWithNestedObjSource model = i % 2 == 0
? new ModelWithNestedObjSource(Lists.newArrayList(new NestedModel("str")))
: new ModelWithNestedObjSource(Lists.newArrayList(new NestedModel(1)));

readyLatch.countDown();
try {
if (readyLatch.await(1, TimeUnit.SECONDS)) {
Assert.assertEquals(model.getValue(), mapper.map(model, ModelWithNestedObjDest.class).getValue());
} else {
throw new RuntimeException("Latch timeout");
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
})
).collect(Collectors.toList());

// check that no exception thrown inside futures
for (Future<?> future : futures) {
try {
future.get(1, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
throw new RuntimeException(e);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ma.glasnost.orika.test.concurrency.model;

import java.util.List;

public class ModelWithNestedObjDest {

private List<NestedModel> value;

public List<NestedModel> getValue() {
return value;
}

public void setValue(List<NestedModel> value) {
this.value = value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package ma.glasnost.orika.test.concurrency.model;

import java.util.List;

public class ModelWithNestedObjSource {

private List<NestedModel> value;

public ModelWithNestedObjSource(List<NestedModel> value) {
this.value = value;
}

public List<NestedModel> getValue() {
return value;
}

public void setValue(List<NestedModel> value) {
this.value = value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package ma.glasnost.orika.test.concurrency.model;

import java.util.Objects;

public class NestedModel {

private Object value;

public NestedModel(Object value) {
this.value = value;
}

public Object getValue() {
return value;
}

public void setValue(Object value) {
this.value = value;
}

@Override
public int hashCode() {
return Objects.hash(value);
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
NestedModel other = (NestedModel) obj;
return Objects.equals(value, other.value);
}

}

0 comments on commit 0af16e7

Please sign in to comment.