/* * Copyright 2012 NGDATA nv * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.lilyproject.indexer.derefmap; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.UUID; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.lilyproject.hadooptestfw.TestHelper; import org.lilyproject.repository.api.AbsoluteRecordId; import org.lilyproject.repository.api.IdGenerator; import org.lilyproject.repository.api.LRepository; import org.lilyproject.repository.api.RecordId; import org.lilyproject.repository.api.SchemaId; import org.lilyproject.repository.impl.id.AbsoluteRecordIdImpl; import org.lilyproject.repotestfw.RepositorySetup; import org.lilyproject.util.hbase.LilyHBaseSchema.Table; import org.lilyproject.util.io.Closer; /** * This tests the functionality of the {@link DerefMapHbaseImpl}. Note there is also a DerefMapIndexTest which * tests it in real indexing scenario's. * * */ public class DerefMapBasicTest { private final static RepositorySetup repoSetup = new RepositorySetup(); public static final String REPO_NAME = "DerefMapBasicTestRepo"; private static IdGenerator ids; private static DerefMapHbaseImpl derefMap; private static int nextIdPrefix = 0; @BeforeClass public static void setUpBeforeClass() throws Exception { TestHelper.setupLogging("org.lilyproject.indexer"); repoSetup.setupCore(); repoSetup.setupRepository(REPO_NAME); LRepository repository = repoSetup.getRepositoryManager().getRepository(REPO_NAME); ids = repository.getIdGenerator(); derefMap = (DerefMapHbaseImpl) DerefMapHbaseImpl.create(REPO_NAME,"test", repoSetup.getHadoopConf(), null, ids); } @AfterClass public static void tearDownAfterClass() throws Exception { Closer.close(repoSetup); } private static AbsoluteRecordId absId(RecordId recordId) { return new AbsoluteRecordIdImpl(Table.RECORD.name, recordId); } @Test public void emptyDependencies() throws Exception { String idPrefix = newIdPrefix(); final SchemaId dummyVtag = ids.getSchemaId(UUID.randomUUID()); final SchemaId dummyField = ids.getSchemaId(UUID.randomUUID()); final RecordId id1 = ids.newRecordId(idPrefix + "id1"); final HashMap<DependencyEntry, Set<SchemaId>> empty = new HashMap<DependencyEntry, Set<SchemaId>>(); derefMap.updateDependants(absId(id1), dummyVtag, empty); // consistency check final Set<DependencyEntry> found = derefMap.findDependencies(absId(id1), dummyVtag); assertTrue(found.isEmpty()); final DependantRecordIdsIterator dependants = derefMap.findDependantsOf(absId(id1), dummyField, dummyVtag); assertFalse(dependants.hasNext()); } @Test public void oneDependency() throws Exception { String idPrefix = newIdPrefix(); final SchemaId dummyVtag = ids.getSchemaId(UUID.randomUUID()); final SchemaId dependencyField = ids.getSchemaId(UUID.randomUUID()); final SchemaId anotherField = ids.getSchemaId(UUID.randomUUID()); final RecordId dependant = ids.newRecordId(idPrefix + idPrefix + "dependant"); final RecordId dependency = ids.newRecordId(idPrefix + idPrefix + "dependency"); final RecordId dependencyAfterUpdate = ids.newRecordId(idPrefix + idPrefix + "dependencyAfterUpdate"); // the dependant depends on the dependencyField of the dependency final HashMap<DependencyEntry, Set<SchemaId>> dependencies = new HashMap<DependencyEntry, Set<SchemaId>>(); dependencies.put(new DependencyEntry(absId(dependency)), Sets.newHashSet(dependencyField)); derefMap.updateDependants(absId(dependant), dummyVtag, dependencies); // consistency check final Set<DependencyEntry> found = derefMap.findDependencies(absId(dependant), dummyVtag); assertEquals(1, found.size()); assertEquals(absId(dependency), found.iterator().next().getDependency()); // check that the dependant is found as only dependant of the dependency via the dependencyField DependantRecordIdsIterator dependants = derefMap.findDependantsOf(absId(dependency), dependencyField, dummyVtag); assertTrue(dependants.hasNext()); assertEquals(absId(dependant), dependants.next()); assertFalse(dependants.hasNext()); // idem but with a set of fields among which the dependencyField dependants = derefMap.findDependantsOf(absId(dependency), Sets.newHashSet(dependencyField, anotherField), dummyVtag); assertTrue(dependants.hasNext()); assertEquals(absId(dependant), dependants.next()); assertFalse(dependants.hasNext()); // check that nothing is found as dependency of the dependant assertFalse(derefMap.findDependantsOf(absId(dependant), dependencyField, dummyVtag).hasNext()); // check that nothing is found as dependency of the dependency via another field than the dependencyField assertFalse(derefMap.findDependantsOf(absId(dependency), anotherField, dummyVtag).hasNext()); // now update the dependency to be from the dependant to the dependencyAfterUpdate (via the same field) final HashMap<DependencyEntry, Set<SchemaId>> updatedDependencies = new HashMap<DependencyEntry, Set<SchemaId>>(); updatedDependencies .put(new DependencyEntry(absId(dependencyAfterUpdate)), Sets.newHashSet(dependencyField)); derefMap.updateDependants(absId(dependant), dummyVtag, updatedDependencies); // consistency check final Set<DependencyEntry> foundAfterUpdate = derefMap.findDependencies(absId(dependant), dummyVtag); assertEquals(1, foundAfterUpdate.size()); assertEquals(absId(dependencyAfterUpdate), foundAfterUpdate.iterator().next().getDependency()); // check that the dependant is found as only dependant of the dependencyAfterUpdate via the dependencyField final DependantRecordIdsIterator dependantsAfterUpdate = derefMap.findDependantsOf(absId(dependencyAfterUpdate), dependencyField, dummyVtag); assertTrue(dependantsAfterUpdate.hasNext()); assertEquals(absId(dependant), dependantsAfterUpdate.next()); assertFalse(dependantsAfterUpdate.hasNext()); // check that nothing is found any longer as dependency on the previous dependency (from before the update) assertFalse(derefMap.findDependantsOf(absId(dependency), dependencyField, dummyVtag).hasNext()); } @Test public void oneDependencyWithMoreDimensionedVariants() throws Exception { String idPrefix = newIdPrefix(); final SchemaId dummyVtag = ids.getSchemaId(UUID.randomUUID()); final RecordId dependant = ids.newRecordId(idPrefix + "master", ImmutableMap.of("bar", "x")); final RecordId dependency = ids.newRecordId(idPrefix + "master", ImmutableMap.of("bar", "x", "foo", "y")); // the dependant depends on the dependencyField of the dependency via a "+foo" dereferencing rule final HashMap<DependencyEntry, Set<SchemaId>> dependencies = new HashMap<DependencyEntry, Set<SchemaId>>(); dependencies.put(new DependencyEntry(absId(dependency), ImmutableSet.of("foo")), Sets.<SchemaId>newHashSet()); derefMap.updateDependants(absId(dependant), dummyVtag, dependencies); // consistency check final Set<DependencyEntry> found = derefMap.findDependencies(absId(dependant), dummyVtag); assertEquals(1, found.size()); final DependencyEntry foundDependencyEntry = found.iterator().next(); assertEquals(absId(ids.newRecordId(idPrefix + "master", ImmutableMap.of("bar", "x"))), foundDependencyEntry.getDependency()); assertEquals(Sets.newHashSet("foo"), foundDependencyEntry.getMoreDimensionedVariants()); // check that the dependant is found as only dependant of the dependency (without specifying a field) DependantRecordIdsIterator dependants = derefMap.findDependantsOf(absId(dependency)); assertTrue(dependants.hasNext()); assertEquals(absId(dependant), dependants.next()); assertFalse(dependants.hasNext()); // check that other records (which would in reality not yet exist at index time) that match the "+foo" rule // are returned as dependants of our dependant (such that in reality reindexation of the dependant happens) final RecordId shouldTriggerOurDependant = ids.newRecordId(idPrefix + "master", ImmutableMap.of("bar", "x", "foo", "another-value")); dependants = derefMap.findDependantsOf(absId(shouldTriggerOurDependant)); assertTrue(dependants.hasNext()); assertEquals(absId(dependant), dependants.next()); assertFalse(dependants.hasNext()); // doesn't have the foo property final RecordId shouldNotTriggerOurDependant1 = ids.newRecordId(idPrefix + "master", ImmutableMap.of("bar", "x")); assertFalse(derefMap.findDependantsOf(absId(shouldNotTriggerOurDependant1)).hasNext()); // doesn't have the bar property final RecordId shouldNotTriggerOurDependant2 = ids.newRecordId(idPrefix + "master", ImmutableMap.of("foo", "x")); assertFalse(derefMap.findDependantsOf(absId(shouldNotTriggerOurDependant2)).hasNext()); // wrong value for the bar property final RecordId shouldNotTriggerOurDependant3 = ids.newRecordId(idPrefix + "master", ImmutableMap.of("bar", "y", "foo", "another-value")); assertFalse(derefMap.findDependantsOf(absId(shouldNotTriggerOurDependant3)).hasNext()); // additional unmatched property final RecordId shouldNotTriggerOurDependant4 = ids.newRecordId(idPrefix + "master", ImmutableMap.of("bar", "x", "foo", "another-value", "baz", "z")); assertFalse(derefMap.findDependantsOf(absId(shouldNotTriggerOurDependant4)).hasNext()); // another master final RecordId shouldNotTriggerOurDependant5 = ids.newRecordId(idPrefix + "another-master", ImmutableMap.of("bar", "x", "foo", "another-value")); assertFalse(derefMap.findDependantsOf(absId(shouldNotTriggerOurDependant5)).hasNext()); // wrong properties final RecordId shouldNotTriggerOurDependant6 = ids.newRecordId(idPrefix + "master", ImmutableMap.of("a", "b", "c", "d")); assertFalse(derefMap.findDependantsOf(absId(shouldNotTriggerOurDependant6)).hasNext()); // no properties final RecordId shouldNotTriggerOurDependant7 = ids.newRecordId(idPrefix + "master", ImmutableMap.<String, String>of()); assertFalse(derefMap.findDependantsOf(absId(shouldNotTriggerOurDependant7)).hasNext()); } /** * Simulates what would happen in case of a dereference expression like n:link1=>n:link2=>n:field. */ @Test public void chainOfDependencies() throws Exception { String idPrefix = newIdPrefix(); final SchemaId dummyVtag = ids.getSchemaId(UUID.randomUUID()); final SchemaId linkField1 = ids.getSchemaId(UUID.randomUUID()); final SchemaId linkField2 = ids.getSchemaId(UUID.randomUUID()); final SchemaId field = ids.getSchemaId(UUID.randomUUID()); final RecordId dependant = ids.newRecordId(idPrefix + "dependant"); final RecordId dependency1 = ids.newRecordId(idPrefix + "dependency1"); final RecordId dependency2 = ids.newRecordId(idPrefix + "dependency2"); // scenario: dependant has linkField1 -> dependency1 which has linkField2 -> dependency2 which has field "field" final Map<DependencyEntry, Set<SchemaId>> dependencies = new HashMap<DependencyEntry, Set<SchemaId>>(); // 1) dependant depends on dependency1 from which it uses linkField2 dependencies.put(new DependencyEntry(absId(dependency1)), Sets.newHashSet(linkField2)); // 2) dependant depends on dependency2 from which it uses field dependencies.put(new DependencyEntry(absId(dependency2)), Sets.newHashSet(field)); derefMap.updateDependants(absId(dependant), dummyVtag, dependencies); // consistency check final Set<DependencyEntry> found = derefMap.findDependencies(absId(dependant), dummyVtag); assertEquals(2, found.size()); // check that the dependant is found as only dependant of the dependencies via the corresponding fields DependantRecordIdsIterator viaDependency1AndLinkField1 = derefMap.findDependantsOf(absId(dependency1), linkField1, dummyVtag); assertFalse(viaDependency1AndLinkField1.hasNext()); DependantRecordIdsIterator viaDependency2AndLinkField1 = derefMap.findDependantsOf(absId(dependency2), linkField1, dummyVtag); assertFalse(viaDependency2AndLinkField1.hasNext()); DependantRecordIdsIterator viaDependency1AndLinkField2 = derefMap.findDependantsOf(absId(dependency1), linkField2, dummyVtag); assertTrue(viaDependency1AndLinkField2.hasNext()); assertEquals(absId(dependant), viaDependency1AndLinkField2.next()); assertFalse(viaDependency1AndLinkField2.hasNext()); DependantRecordIdsIterator viaDependency2AndLinkField2 = derefMap.findDependantsOf(absId(dependency2), linkField2, dummyVtag); assertFalse(viaDependency2AndLinkField2.hasNext()); DependantRecordIdsIterator viaDependency2AndField = derefMap.findDependantsOf(absId(dependency2), field, dummyVtag); assertTrue(viaDependency2AndField.hasNext()); assertEquals(absId(dependant), viaDependency2AndField.next()); assertFalse(viaDependency2AndField.hasNext()); DependantRecordIdsIterator viaDependency1WithoutSpecifyingField = derefMap.findDependantsOf(absId(dependency1)); assertTrue(viaDependency1WithoutSpecifyingField.hasNext()); assertEquals(absId(dependant), viaDependency1WithoutSpecifyingField.next()); assertFalse(viaDependency1WithoutSpecifyingField.hasNext()); DependantRecordIdsIterator viaDependency2WithoutSpecifyingField = derefMap.findDependantsOf(absId(dependency2)); assertTrue(viaDependency2WithoutSpecifyingField.hasNext()); assertEquals(absId(dependant), viaDependency2WithoutSpecifyingField.next()); assertFalse(viaDependency2WithoutSpecifyingField.hasNext()); } /** * Simulates what would happen in case of a dereference expression like n:link1=>n:link2=>n:link3. */ @Test public void chainOfDependenciesWhichDoesNotEndInField() throws Exception { String idPrefix = newIdPrefix(); final SchemaId dummyVtag = ids.getSchemaId(UUID.randomUUID()); final SchemaId linkField1 = ids.getSchemaId(UUID.randomUUID()); final SchemaId linkField2 = ids.getSchemaId(UUID.randomUUID()); final SchemaId linkField3 = ids.getSchemaId(UUID.randomUUID()); final RecordId dependant = ids.newRecordId(idPrefix + "dependant"); final RecordId dependency1 = ids.newRecordId(idPrefix + "dependency1"); final RecordId dependency2 = ids.newRecordId(idPrefix + "dependency2"); final RecordId dependency3 = ids.newRecordId(idPrefix + "dependency3"); // scenario: dependant has linkField1 -> dependency1 which has linkField2 -> dependency2 which has linkField3 -> dependency3 final Map<DependencyEntry, Set<SchemaId>> dependencies = new HashMap<DependencyEntry, Set<SchemaId>>(); // 1) dependant depends on dependency1 from which it uses linkField2 dependencies.put(new DependencyEntry(absId(dependency1)), Sets.newHashSet(linkField2)); // 2) dependant depends on dependency2 from which it uses linkField3 which points to dependency3 dependencies.put(new DependencyEntry(absId(dependency2)), Sets.newHashSet(linkField3)); derefMap.updateDependants(absId(dependant), dummyVtag, dependencies); // consistency check final Set<DependencyEntry> found = derefMap.findDependencies(absId(dependant), dummyVtag); assertEquals(2, found.size()); // check that the dependant is found as only dependant of the dependencies via the corresponding fields DependantRecordIdsIterator viaDependency1AndLinkField2 = derefMap.findDependantsOf(absId(dependency1), linkField2, dummyVtag); assertTrue(viaDependency1AndLinkField2.hasNext()); assertEquals(absId(dependant), viaDependency1AndLinkField2.next()); assertFalse(viaDependency1AndLinkField2.hasNext()); DependantRecordIdsIterator viaDependency2AndLinkField3 = derefMap.findDependantsOf(absId(dependency2), linkField3, dummyVtag); assertTrue(viaDependency2AndLinkField3.hasNext()); assertEquals(absId(dependant), viaDependency2AndLinkField3.next()); assertFalse(viaDependency2AndLinkField3.hasNext()); } /** * Simulates what would happen in case of a dereference expression like +prop1=>n:link1=>+prop2=>n:field. */ @Test public void chainOfDependenciesIncludingMoreDimensionedVariantProperties() throws Exception { String idPrefix = newIdPrefix(); final SchemaId dummyVtag = ids.getSchemaId(UUID.randomUUID()); final SchemaId linkField1 = ids.getSchemaId(UUID.randomUUID()); final SchemaId field = ids.getSchemaId(UUID.randomUUID()); final RecordId dependant = ids.newRecordId(idPrefix + "dependant"); final RecordId dependantWithProp1 = ids.newRecordId(idPrefix + "dependant", ImmutableMap.of("prop1", "x")); final RecordId dependency1 = ids.newRecordId(idPrefix + "dependency1"); final RecordId dependency1WithProp2 = ids.newRecordId(idPrefix + "dependency1", ImmutableMap.of("prop2", "y")); // scenario: dependant depends on all dependant +prop1 records. One such a record (dependantWithProp1) exists // with a linkField1 pointing to dependency1. Via the +prop2 rule, we end up with all dependency1 + prop2 // records, of which there is one instance (dependency1WithProp2). Of this instance, we use the field "field". final Map<DependencyEntry, Set<SchemaId>> dependencies = new HashMap<DependencyEntry, Set<SchemaId>>(); // 1) dependant depends on all similar with prop1, of which it uses linkField1 dependencies .put(new DependencyEntry(absId(dependant), ImmutableSet.of("prop1")), Sets.newHashSet(linkField1)); // 2) dependant depends on dependency1WithProp2 (and all similar with prop2) from which it uses field "field" dependencies.put(new DependencyEntry(absId(dependency1WithProp2), ImmutableSet.of("prop2")), Sets.newHashSet(field)); derefMap.updateDependants(absId(dependant), dummyVtag, dependencies); // consistency check final Set<DependencyEntry> found = derefMap.findDependencies(absId(dependant), dummyVtag); assertEquals(2, found.size()); // check that the dependant is found as only dependant of the dependencies via the corresponding fields (in a few scenarios) // scenario1: as if a dependency1 with prop2=value is being created final RecordId someRecordLikeDependency1WithProp2 = ids.newRecordId(idPrefix + "dependency1", ImmutableMap.of("prop2", "value")); DependantRecordIdsIterator scenario1 = derefMap.findDependantsOf(absId(someRecordLikeDependency1WithProp2), field, dummyVtag); assertTrue(scenario1.hasNext()); assertEquals(absId(dependant), scenario1.next()); assertFalse(scenario1.hasNext()); // scenario2: as if a new record like dependant is created with prop1=value final RecordId someRecordLikeDependantWithProp1 = ids.newRecordId(idPrefix + "dependant", ImmutableMap.of("prop1", "value")); DependantRecordIdsIterator scenario2 = derefMap.findDependantsOf(absId(someRecordLikeDependantWithProp1), linkField1, dummyVtag); assertTrue(scenario2.hasNext()); assertEquals(absId(dependant), scenario2.next()); assertFalse(scenario2.hasNext()); } @Test public void multipleDependencies() throws Exception { String idPrefix = newIdPrefix(); final SchemaId dummyVtag = ids.getSchemaId(UUID.randomUUID()); final SchemaId dependencyField = ids.getSchemaId(UUID.randomUUID()); final RecordId dependant = ids.newRecordId(idPrefix + "dependant"); final RecordId dependency1 = ids.newRecordId(idPrefix + "dependency1"); final RecordId dependency2 = ids.newRecordId(idPrefix + "dependency2"); // the dependant depends on the dependencyField of the dependency1 and dependency2 final HashMap<DependencyEntry, Set<SchemaId>> dependencies = new HashMap<DependencyEntry, Set<SchemaId>>(); dependencies.put(new DependencyEntry(absId(dependency1)), Sets.newHashSet(dependencyField)); dependencies.put(new DependencyEntry(absId(dependency2)), Sets.newHashSet(dependencyField)); derefMap.updateDependants(absId(dependant), dummyVtag, dependencies); // consistency check final Set<DependencyEntry> found = derefMap.findDependencies(absId(dependant), dummyVtag); assertEquals(2, found.size()); // check that the dependant is found as only dependant of the dependency1 via the dependencyField final DependantRecordIdsIterator dependantsOf1 = derefMap.findDependantsOf(absId(dependency1), dependencyField, dummyVtag); assertTrue(dependantsOf1.hasNext()); assertEquals(absId(dependant), dependantsOf1.next()); assertFalse(dependantsOf1.hasNext()); // check that the dependant is also found as only dependant of the dependency2 via the dependencyField final DependantRecordIdsIterator dependantsOf2 = derefMap.findDependantsOf(absId(dependency2), dependencyField, dummyVtag); assertTrue(dependantsOf2.hasNext()); assertEquals(absId(dependant), dependantsOf2.next()); assertFalse(dependantsOf2.hasNext()); } @Test public void multipleVariantsDependingOnMaster() throws Exception { String idPrefix = newIdPrefix(); final SchemaId dummyVtag = ids.getSchemaId(UUID.randomUUID()); final SchemaId dependencyField = ids.getSchemaId(UUID.randomUUID()); final RecordId master = ids.newRecordId(idPrefix + "myrecord"); final RecordId v1variant = ids.newRecordId(idPrefix + "myrecord", Collections.singletonMap("v1", "x")); final RecordId v1v2variant = ids.newRecordId(idPrefix + "myrecord", map("v1", "x", "v2", "y")); final HashMap<DependencyEntry, Set<SchemaId>> dependencies = new HashMap<DependencyEntry, Set<SchemaId>>(); dependencies.put(new DependencyEntry(absId(master)), Sets.newHashSet(dependencyField)); derefMap.updateDependants(absId(v1variant), dummyVtag, dependencies); derefMap.updateDependants(absId(v1v2variant), dummyVtag, dependencies); Set<AbsoluteRecordId> recordIds = asRecordIds(derefMap.findDependantsOf(absId(master))); assertEquals(recordIds, Sets.newHashSet(absId(v1variant), absId(v1v2variant))); } @Test public void multipleDependants() throws Exception { String idPrefix = newIdPrefix(); final SchemaId dummyVtag = ids.getSchemaId(UUID.randomUUID()); final SchemaId dependencyField = ids.getSchemaId(UUID.randomUUID()); final RecordId dependant1 = ids.newRecordId(idPrefix + "dependant1"); final RecordId dependant2 = ids.newRecordId(idPrefix + "dependant2"); final RecordId dependency = ids.newRecordId(idPrefix + "dependency"); // the dependant1 and dependant2 depend on the dependencyField of the dependency final HashMap<DependencyEntry, Set<SchemaId>> dependencies = new HashMap<DependencyEntry, Set<SchemaId>>(); dependencies.put(new DependencyEntry(absId(dependency)), Sets.newHashSet(dependencyField)); derefMap.updateDependants(absId(dependant1), dummyVtag, dependencies); derefMap.updateDependants(absId(dependant2), dummyVtag, dependencies); // consistency check dependant1 final Set<DependencyEntry> dependenciesOf1 = derefMap.findDependencies(absId(dependant1), dummyVtag); assertEquals(1, dependenciesOf1.size()); assertEquals(absId(dependency.getMaster()), dependenciesOf1.iterator().next().getDependency()); // consistency check dependant2 final Set<DependencyEntry> dependenciesOf2 = derefMap.findDependencies(absId(dependant1), dummyVtag); assertEquals(1, dependenciesOf2.size()); assertEquals(absId(dependency.getMaster()), dependenciesOf2.iterator().next().getDependency()); // check that both dependant1 and dependant2 are found as dependants of the dependency final DependantRecordIdsIterator dependants = derefMap.findDependantsOf(absId(dependency), dependencyField, dummyVtag); assertTrue(dependants.hasNext()); final AbsoluteRecordId firstFoundDependant = dependants.next(); assertTrue(dependants.hasNext()); final AbsoluteRecordId secondFoundDependant = dependants.next(); assertFalse(dependants.hasNext()); // check that the two found dependants are dependant1 and dependant2 (order doesn't matter) assertTrue((absId(dependant1).equals(firstFoundDependant) && absId(dependant2).equals(secondFoundDependant)) || (absId(dependant2).equals(firstFoundDependant) && absId(dependant1).equals(secondFoundDependant))); } @Test public void resultIndependentOfOrder() throws Exception { for (int i = 0; i < 10; i++) { final SchemaId dummyVtag = ids.getSchemaId(UUID.randomUUID()); final SchemaId dependencyField = ids.getSchemaId(UUID.randomUUID()); final RecordId master = ids.newRecordId(); final RecordId var1 = ids.newRecordId(master, Collections.singletonMap("prop1", "x")); final RecordId var2 = ids.newRecordId(master, map("prop1", "x", "prop2", "y")); Set<SchemaId> fields = Sets.newHashSet(dependencyField); Map<DependencyEntry, Set<SchemaId>> dependencies = Maps.newHashMap(); dependencies.put(new DependencyEntry(absId(master)), fields); dependencies.put(new DependencyEntry(absId(var2)), fields); derefMap.updateDependants(absId(var1), dummyVtag, dependencies); Set<AbsoluteRecordId> recordIds = asRecordIds(derefMap.findDependantsOf(absId(var2))); assertEquals("Iteration " + i, Sets.newHashSet(absId(var1)), recordIds); } } @Test public void twoVTagsDependingOnOneRecord() throws Exception { final SchemaId tag1 = ids.getSchemaId(UUID.randomUUID()); final SchemaId tag2 = ids.getSchemaId(UUID.randomUUID()); final SchemaId field = ids.getSchemaId(UUID.randomUUID()); final Set<SchemaId> fields = Sets.newHashSet(field); final RecordId a = ids.newRecordId(); final RecordId b = ids.newRecordId(); derefMap.updateDependants(absId(a), tag1, Collections.singletonMap(new DependencyEntry(absId(b)), fields)); assertEquals(Sets.newHashSet(absId(a)), asRecordIds(derefMap.findDependantsOf(absId(b), field, tag1))); assertEquals(Sets.newHashSet(), asRecordIds(derefMap.findDependantsOf(absId(b), field, tag2))); derefMap.updateDependants(absId(a), tag2, Collections.singletonMap(new DependencyEntry(absId(b)), fields)); assertEquals(Sets.newHashSet(absId(a)), asRecordIds(derefMap.findDependantsOf( absId(b), field, tag1))); assertEquals(Sets.newHashSet(absId(a)), asRecordIds(derefMap.findDependantsOf( absId(b), field, tag2))); } private Set<AbsoluteRecordId> asRecordIds(DependantRecordIdsIterator iter) throws IOException { Set<AbsoluteRecordId> result = Sets.newHashSet(); while (iter.hasNext()) { result.add(iter.next()); } return result; } private Map<String, String> map(String... keyOrValue) { Map<String, String> map = Maps.newHashMap(); for (int i = 0; i < keyOrValue.length; i += 2) { map.put(keyOrValue[i], keyOrValue[i + 1]); } return map; } private String newIdPrefix() { return String.format("TEST%3d", nextIdPrefix++); } }