/** * Copyright (c) Codice Foundation * <p> * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, either version 3 of the * License, or any later version. * <p> * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. A copy of the GNU Lesser General Public License * is distributed along with this program and can be found at * <http://www.gnu.org/licenses/lgpl.html>. */ package ddf.catalog.cache.solr.impl; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.anyCollectionOf; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import com.google.common.collect.Lists; import ddf.catalog.data.Metacard; import ddf.catalog.data.Result; @RunWith(MockitoJUnitRunner.class) public class CacheBulkProcessorTest { @Captor ArgumentCaptor<Collection<Metacard>> capturedMetacards; private CacheBulkProcessor cacheBulkProcessor; @Mock private SolrCache mockSolrCache; @Before public void setUp() throws Exception { cacheBulkProcessor = new CacheBulkProcessor(mockSolrCache, 1, TimeUnit.MILLISECONDS); cacheBulkProcessor.setBatchSize(10); } @After public void tearDown() throws Exception { cacheBulkProcessor.shutdown(); } @Test public void bulkAdd() throws Exception { cacheBulkProcessor.setFlushInterval(TimeUnit.MINUTES.toMillis(1)); List<Result> mockResults = getMockResults(10); cacheBulkProcessor.add(mockResults); waitForPendingMetacardsToCache(); verify(mockSolrCache, times(1)).create(capturedMetacards.capture()); assertThat(capturedMetacards.getValue()).containsAll(getMetacards(mockResults)); } @Test public void partialFlush() throws Exception { cacheBulkProcessor.setFlushInterval(1); List<Result> mockResults = getMockResults(1); cacheBulkProcessor.add(mockResults); waitForPendingMetacardsToCache(); verify(mockSolrCache, times(1)).create(capturedMetacards.capture()); assertThat(capturedMetacards.getValue()).containsAll(getMetacards(mockResults)); } @Test public void nullResult() throws Exception { cacheBulkProcessor.add(Collections.singletonList((Result) null)); verify(mockSolrCache, never()).create(anyCollectionOf(Metacard.class)); } @Test public void nullMetacard() throws Exception { Result mockResult = mock(Result.class); when(mockResult.getMetacard()).thenReturn(null); cacheBulkProcessor.add(Collections.singletonList(mockResult)); verify(mockSolrCache, never()).create(anyCollectionOf(Metacard.class)); } @Test public void exceedsBacklog() throws Exception { cacheBulkProcessor.setMaximumBacklogSize(0); cacheBulkProcessor.add(getMockResults(10)); verify(mockSolrCache, never()).create(anyCollectionOf(Metacard.class)); } @Test public void cacheThrowsExcpetion() throws Exception { doThrow(new RuntimeException()).doNothing() .when(mockSolrCache) .create(anyCollectionOf(Metacard.class)); List<Result> mockResults = getMockResults(10); cacheBulkProcessor.add(mockResults); waitForPendingMetacardsToCache(); verify(mockSolrCache, atLeast(2)).create(capturedMetacards.capture()); for (Collection<Metacard> metacards : capturedMetacards.getAllValues()) { assertThat(metacards).containsAll(getMetacards(mockResults)); } } @Test public void updateMetacards() throws Exception { cacheBulkProcessor.setFlushInterval(TimeUnit.MINUTES.toMillis(1)); List<List<Result>> mockResultHalfs = Lists.partition(getMockResults(10), 5); List<Result> mockResults = new ArrayList<>(mockResultHalfs.get(0)); // Duplicate the first half Collections.addAll(mockResults, mockResultHalfs.get(0) .toArray(new Result[5])); // Add the second half Collections.addAll(mockResults, mockResultHalfs.get(1) .toArray(new Result[5])); cacheBulkProcessor.add(mockResults); waitForPendingMetacardsToCache(); verify(mockSolrCache).create(capturedMetacards.capture()); assertThat(capturedMetacards.getValue()).containsAll(getMetacards(mockResults)); } private void waitForPendingMetacardsToCache() throws InterruptedException { while (cacheBulkProcessor.pendingMetacards() > 0) { Thread.sleep(2); } } private Collection<Metacard> getMetacards(List<Result> results) { List<Metacard> metacards = new ArrayList<>(results.size()); for (Result result : results) { metacards.add(result.getMetacard()); } return metacards; } private List<Result> getMockResults(int size) { List<Result> results = new ArrayList<>(size); for (int i = 0; i < size; i++) { Metacard mockMetacard = mock(Metacard.class); when(mockMetacard.getId()).thenReturn(Integer.toString(i)); Result mockResult = mock(Result.class); when(mockResult.getMetacard()).thenReturn(mockMetacard); results.add(mockResult); } return results; } }