package pl.edu.icm.saos.search.indexing; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.LinkedList; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.stream.Collectors; import java.util.stream.IntStream; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.springframework.batch.item.ExecutionContext; import org.springframework.batch.item.NonTransientResourceException; import org.springframework.batch.item.ParseException; import org.springframework.batch.item.UnexpectedInputException; import org.springframework.test.util.ReflectionTestUtils; import pl.edu.icm.saos.enrichment.apply.JudgmentEnrichmentService; import pl.edu.icm.saos.persistence.model.CommonCourtJudgment; import pl.edu.icm.saos.persistence.model.Judgment; import com.google.common.collect.Lists; /** * @author madryk */ public class JudgmentIndexingReaderTest { private JudgmentIndexingReader judgmentIndexingReader = new JudgmentIndexingReader(); private JudgmentEnrichmentService judgmentEnrichmentService = mock(JudgmentEnrichmentService.class); private JudgmentIndexingItemFetcher judgmentIndexingItemFetcher = mock(JudgmentIndexingItemFetcher.class); @Before public void setUp() { judgmentIndexingReader.setJudgmentEnrichmentService(judgmentEnrichmentService); judgmentIndexingReader.setJudgmentIndexingItemFetcher(judgmentIndexingItemFetcher); } //------------------------ TESTS -------------------------- @Test public void read_NOT_FOUND() throws UnexpectedInputException, ParseException, NonTransientResourceException, Exception { when(judgmentIndexingItemFetcher.fetchJudgmentIndexingItems()).thenReturn(Lists.newLinkedList()); judgmentIndexingReader.open(new ExecutionContext()); JudgmentIndexingData judgmentIndexingData = judgmentIndexingReader.read(); assertNull(judgmentIndexingData); } @Test public void read_FOUND() throws UnexpectedInputException, ParseException, NonTransientResourceException, Exception { Judgment firstJudgment = createCcJudgment(1); Judgment secondJudgment = createCcJudgment(2); Judgment thirdJudgment = createCcJudgment(3); JudgmentIndexingItem firstJudgmentIndexingItem = new JudgmentIndexingItem(1L, 31L); JudgmentIndexingItem secondJudgmentIndexingItem = new JudgmentIndexingItem(2L, 0L); JudgmentIndexingItem thirdJudgmentIndexingItem = new JudgmentIndexingItem(3L, 53L); when(judgmentIndexingItemFetcher.fetchJudgmentIndexingItems()) .thenReturn(Lists.newArrayList(firstJudgmentIndexingItem, secondJudgmentIndexingItem, thirdJudgmentIndexingItem)); when(judgmentEnrichmentService.findOneAndEnrich(1l)).thenReturn(firstJudgment); when(judgmentEnrichmentService.findOneAndEnrich(2l)).thenReturn(secondJudgment); when(judgmentEnrichmentService.findOneAndEnrich(3l)).thenReturn(thirdJudgment); judgmentIndexingReader.open(new ExecutionContext()); JudgmentIndexingData actualFirst = judgmentIndexingReader.read(); JudgmentIndexingData actualSecond = judgmentIndexingReader.read(); JudgmentIndexingData actualThird = judgmentIndexingReader.read(); JudgmentIndexingData actualFourth = judgmentIndexingReader.read(); assertNotNull(actualFirst.getJudgment()); assertEquals(firstJudgment.getId(), actualFirst.getJudgment().getId()); assertEquals(31L, actualFirst.getReferencingCount()); assertNotNull(actualSecond.getJudgment()); assertEquals(secondJudgment.getId(), actualSecond.getJudgment().getId()); assertEquals(0L, actualSecond.getReferencingCount()); assertNotNull(actualThird.getJudgment()); assertEquals(thirdJudgment.getId(), actualThird.getJudgment().getId()); assertEquals(53L, actualThird.getReferencingCount()); assertNull(actualFourth); } @Test public void read_THREAD_SAFE_CHECK() throws InterruptedException { final int threadsCount = 5; final int judgmentsCount = 300; List<Long> ids = IntStream .rangeClosed(1, judgmentsCount) .mapToObj(x -> Long.valueOf(x)) .collect(Collectors.toList()); List<JudgmentIndexingItem> judgmentIndexingItems = IntStream .rangeClosed(1, judgmentsCount) .mapToObj(x -> new JudgmentIndexingItem(Long.valueOf(x), 0L)) .collect(Collectors.toList()); when(judgmentIndexingItemFetcher.fetchJudgmentIndexingItems()).thenReturn(judgmentIndexingItems); when(judgmentEnrichmentService.findOneAndEnrich(Mockito.anyLong())).thenAnswer(new Answer<Judgment>( ) { @Override public Judgment answer(InvocationOnMock invocation) throws Throwable { long id = (long)(invocation.getArguments()[0]); return (id >=1 && id <=judgmentsCount) ? createCcJudgment(id) : null; } }); judgmentIndexingReader.open(new ExecutionContext()); final CountDownLatch latch = new CountDownLatch(threadsCount); final List<List<Long>> threadsResultsIds = Lists.newLinkedList(); for (int i=0; i<threadsCount; ++i) { List<Long> threadResultsIds = runReaderThread(latch, i); threadsResultsIds.add(threadResultsIds); } latch.await(); // wait for threads to finish reading List<Long> actualIds = threadsResultsIds.stream().flatMap(List::stream).collect(Collectors.toList()); assertThat(actualIds, containsInAnyOrder(ids.toArray())); } //------------------------ PRIVATE -------------------------- private CommonCourtJudgment createCcJudgment(long id) { CommonCourtJudgment ccJudgment = new CommonCourtJudgment(); ReflectionTestUtils.setField(ccJudgment, "id", id); return ccJudgment; } private List<Long> runReaderThread(final CountDownLatch latch, int threadNumber) { final List<Long> threadResultsIds = new LinkedList<Long>(); Runnable runner = new Runnable() { public void run() { try { JudgmentIndexingData judgmentIndexingData = null; do { judgmentIndexingData = judgmentIndexingReader.read(); if (judgmentIndexingData != null) { threadResultsIds.add(judgmentIndexingData.getJudgment().getId()); } } while (judgmentIndexingData != null); } catch (Exception e) { } finally { latch.countDown(); } } }; new Thread(runner, "ReaderThread"+threadNumber).start(); return threadResultsIds; } }