package org.dcache.resilience.util; import com.google.common.collect.ImmutableList; import org.junit.Before; import org.junit.Test; import java.util.Collection; import java.util.Map; import java.util.stream.Collectors; import diskCacheV111.util.CacheException; import org.dcache.resilience.TestBase; import org.dcache.vehicles.FileAttributes; import static org.junit.Assert.assertTrue; public final class RemoveLocationExtractorTest extends TestBase { private String pool; private Collection<String> onlyOneCopyPer; private FileAttributes attributes; private RemoveLocationExtractor extractor; private Collection<String> selected; private int currentWeight = Integer.MAX_VALUE; @Before public void setUp() throws CacheException { setUpBase(); } @Test public void selectedPoolsShouldMonotonicallyDescreaseInWeightWhenContinuouslyRemoved() throws CacheException { givenAFileWithAReplicaOnAllResilientPools(); givenTagConstraintsOn("hostname", "rack"); givenThePoolInfoForThisFile(); do { whenTheExtractorIsCalledForTheSetOfLocationsToRemove(); andThenAPoolIsRandomlySelectedAndRemoved(); assertTrue(theWeightsAreMonotonicallyDecreasing()); } while (selected != null && !selected.isEmpty()); } @Test public void shouldSelectAllPoolsWhenThereAreNoConstraints() throws CacheException { givenAFileWithAReplicaOnAllResilientPools(); givenNoTagConstraints(); givenThePoolInfoForThisFile(); whenTheExtractorIsCalledForTheSetOfLocationsToRemove(); assertTrue(theSelectedPoolsWere(allAvailablePools())); } @Test public void shouldSelectPools10And11WhenContraintsIncludeBoth() throws CacheException { givenAFileWithAReplicaOnAllResilientPools(); givenTagConstraintsOn("hostname", "rack"); givenThePoolInfoForThisFile(); whenTheExtractorIsCalledForTheSetOfLocationsToRemove(); assertTrue(theSelectedPoolsWere(pools10And11())); } @Test public void shouldSelectPoolsWithValueR0WhenContraintIsRack() throws CacheException { givenAFileWithAReplicaOnAllResilientPools(); givenTagConstraintsOn("rack"); givenThePoolInfoForThisFile(); whenTheExtractorIsCalledForTheSetOfLocationsToRemove(); assertTrue(theSelectedPoolsWere(poolsWithRackValueR0())); } @Test public void shouldSelectPoolsWithValuesH0H1WhenContraintIsHost() throws CacheException { givenAFileWithAReplicaOnAllResilientPools(); givenTagConstraintsOn("hostname"); givenThePoolInfoForThisFile(); whenTheExtractorIsCalledForTheSetOfLocationsToRemove(); assertTrue(theSelectedPoolsWere(poolsWithHostValuesH0AndH1())); } private Collection<String> allAvailablePools() { return memberPools().stream().map((i) -> poolInfoMap.getPool(i)).collect( Collectors.toSet()); } private Collection<Integer> memberPools() { return poolInfoMap.getPoolsOfGroup(poolInfoMap.getResilientPoolGroup( poolInfoMap.getPoolIndex(pool))); } private void andThenAPoolIsRandomlySelectedAndRemoved() { pool = RandomSelectionStrategy.SELECTOR.apply(selected); attributes.getLocations().remove(pool); } private void givenAFileWithAReplicaOnAllResilientPools() throws CacheException { loadFilesWithExcessLocations(); attributes = aFileWithAReplicaOnAllResilientPools(); } private void givenNoTagConstraints() { } private void givenTagConstraintsOn(String ... keys) { onlyOneCopyPer = ImmutableList.copyOf(keys); } private void givenThePoolInfoForThisFile() { pool = attributes.getLocations().iterator().next(); extractor = new RemoveLocationExtractor(onlyOneCopyPer, poolInfoMap); } private Collection<String> pools10And11() { return ImmutableList.of("resilient_pool-10", "resilient_pool-11"); } private Collection<String> poolsWithHostValuesH0AndH1() { return getPoolsWithTag("hostname", "h0", "h1"); } private Collection<String> poolsWithRackValueR0() { return getPoolsWithTag("rack", "r0"); } private Collection<String> getPoolsWithTag(final String tag, final String ... values) { return memberPools().stream().filter((p) -> { Map<String, String> tagMap = poolInfoMap.getTags(p); if (tagMap.isEmpty()) { return false; } String tagValue = tagMap.get(tag); for (String v : values) { if (v.equals(tagValue)) { return true; } } return false; }).map((i) -> poolInfoMap.getPool(i)).collect(Collectors.toSet()); } private boolean theSelectedPoolsWere(Collection<String> pools) { for (String pool : pools) { if (!selected.contains(pool)) { return false; } } for (String pool : selected) { if (!pools.contains(pool)) { return false; } } return true; } private boolean theWeightsAreMonotonicallyDecreasing() { int last = currentWeight; currentWeight = extractor.getLastComputedMaximum(); return currentWeight <= last; } private void whenTheExtractorIsCalledForTheSetOfLocationsToRemove() { selected = extractor.getCandidateLocations(attributes.getLocations()); } }