/*
* Copyright 2016 Crown Copyright
*
* 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 uk.gov.gchq.gaffer.integration.impl;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.junit.Before;
import org.junit.Test;
import uk.gov.gchq.gaffer.commonutil.TestGroups;
import uk.gov.gchq.gaffer.commonutil.iterable.CloseableIterable;
import uk.gov.gchq.gaffer.data.element.Edge;
import uk.gov.gchq.gaffer.data.element.Element;
import uk.gov.gchq.gaffer.data.element.Entity;
import uk.gov.gchq.gaffer.data.element.Properties;
import uk.gov.gchq.gaffer.data.element.id.EdgeId;
import uk.gov.gchq.gaffer.data.element.id.ElementId;
import uk.gov.gchq.gaffer.data.element.id.EntityId;
import uk.gov.gchq.gaffer.data.elementdefinition.view.View;
import uk.gov.gchq.gaffer.integration.AbstractStoreIT;
import uk.gov.gchq.gaffer.operation.OperationException;
import uk.gov.gchq.gaffer.operation.data.EdgeSeed;
import uk.gov.gchq.gaffer.operation.data.EntitySeed;
import uk.gov.gchq.gaffer.operation.graph.GraphFilters.DirectedType;
import uk.gov.gchq.gaffer.operation.graph.SeededGraphFilters.IncludeIncomingOutgoingType;
import uk.gov.gchq.gaffer.operation.impl.get.GetElements;
import uk.gov.gchq.gaffer.user.User;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static uk.gov.gchq.gaffer.operation.SeedMatching.SeedMatchingType;
public class GetElementsIT extends AbstractStoreIT {
// ElementId Seeds
public static final List<ElementId> ENTITY_SEEDS_EXIST =
Arrays.asList(
(ElementId) new EntitySeed(SOURCE_2),
new EntitySeed(DEST_3),
new EntitySeed(SOURCE_DIR_2),
new EntitySeed(DEST_DIR_3));
public static final List<Element> ENTITIES_EXIST =
getElements(ENTITY_SEEDS_EXIST);
public static final List<ElementId> EDGE_SEEDS_EXIST =
Collections.singletonList(
(ElementId) new EdgeSeed(SOURCE_1, DEST_1, false));
public static final List<Element> EDGES_EXIST =
getElements(EDGE_SEEDS_EXIST);
public static final List<ElementId> EDGE_DIR_SEEDS_EXIST =
Collections.singletonList(
(ElementId) new EdgeSeed(SOURCE_DIR_1, DEST_DIR_1, true));
public static final List<Element> EDGES_DIR_EXIST =
getElements(EDGE_DIR_SEEDS_EXIST);
public static final List<ElementId> EDGE_SEEDS_DONT_EXIST =
Arrays.asList(
(ElementId) new EdgeSeed(SOURCE_1, "dest2DoesNotExist", false),
new EdgeSeed("source2DoesNotExist", DEST_1, false),
new EdgeSeed(SOURCE_1, DEST_1, true));// does not exist
public static final List<ElementId> ENTITY_SEEDS_DONT_EXIST =
Collections.singletonList(
(ElementId) new EntitySeed("idDoesNotExist"));
public static final List<ElementId> ENTITY_SEEDS = getEntityIds();
public static final List<ElementId> EDGE_SEEDS = getEdgeIds();
public static final List<ElementId> ALL_SEEDS = getAllSeeds();
public static final List<Object> ALL_SEED_VERTICES = getAllSeededVertices();
@Override
@Before
public void setup() throws Exception {
super.setup();
addDefaultElements();
}
@Test
public void shouldGetElements() throws Exception {
final List<DirectedType> directedTypes = Lists.newArrayList(DirectedType.values());
directedTypes.add(null);
final List<IncludeIncomingOutgoingType> inOutTypes = Lists.newArrayList(IncludeIncomingOutgoingType.values());
inOutTypes.add(null);
for (final boolean includeEntities : Arrays.asList(true, false)) {
for (final boolean includeEdges : Arrays.asList(true, false)) {
if (!includeEntities && !includeEdges) {
// Cannot query for nothing!
continue;
}
for (final DirectedType directedType : directedTypes) {
for (final IncludeIncomingOutgoingType inOutType : inOutTypes) {
try {
shouldGetElementsBySeed(includeEntities, includeEdges, directedType, inOutType);
} catch (final AssertionError e) {
throw new AssertionError("GetElementsBySeed failed with parameters: includeEntities=" + includeEntities
+ ", includeEdges=" + includeEdges + ", directedType=" + directedType + ", inOutType=" + inOutType, e);
}
try {
shouldGetRelatedElements(includeEntities, includeEdges, directedType, inOutType);
} catch (final AssertionError e) {
throw new AssertionError("GetRelatedElements failed with parameters: includeEntities=" + includeEntities
+ ", includeEdges=" + includeEdges + ", directedType=" + directedType + ", inOutType=" + inOutType, e);
}
}
}
}
}
}
@Test
public void shouldReturnEmptyIteratorIfNoSeedsProvidedForGetElementsBySeed() throws Exception {
// Given
final GetElements op = new GetElements();
// When
final CloseableIterable<? extends Element> results = graph.execute(op, getUser());
// Then
assertFalse(results.iterator().hasNext());
}
@Test
public void shouldReturnEmptyIteratorIfNoSeedsProvidedForGetRelatedElements() throws Exception {
// Given
final GetElements op = new GetElements();
// When
final CloseableIterable<? extends Element> results = graph.execute(op, getUser());
// Then
assertFalse(results.iterator().hasNext());
}
private void shouldGetElementsBySeed(final boolean includeEntities,
final boolean includeEdges,
final DirectedType directedType,
final IncludeIncomingOutgoingType inOutType) throws Exception {
final List<Element> expectedElements = new ArrayList<>();
if (includeEntities) {
expectedElements.addAll(ENTITIES_EXIST);
}
if (includeEdges) {
if (DirectedType.UNDIRECTED != directedType) {
expectedElements.addAll(EDGES_DIR_EXIST);
}
if (DirectedType.DIRECTED != directedType) {
expectedElements.addAll(EDGES_EXIST);
}
}
final List<ElementId> seeds;
if (includeEdges) {
if (includeEntities) {
seeds = ALL_SEEDS;
} else {
seeds = EDGE_SEEDS;
}
} else if (includeEntities) {
seeds = ENTITY_SEEDS;
} else {
seeds = new ArrayList<>();
}
shouldGetElements(expectedElements, SeedMatchingType.EQUAL, directedType, includeEntities, includeEdges, inOutType, seeds);
}
private void shouldGetRelatedElements(final boolean includeEntities,
final boolean includeEdges,
final DirectedType directedType,
final IncludeIncomingOutgoingType inOutType) throws Exception {
final List<ElementId> seedTerms = new LinkedList<>();
final List<Element> expectedElements = new LinkedList<>();
if (includeEntities) {
for (final Object identifier : ALL_SEED_VERTICES) {
final EntityId entityId = new EntitySeed(identifier);
seedTerms.add(entityId);
}
}
if (includeEdges) {
if (DirectedType.UNDIRECTED != directedType) {
final EdgeId seed = new EdgeSeed(SOURCE_DIR_1, DEST_DIR_1, true);
seedTerms.add(seed);
if (null == inOutType || IncludeIncomingOutgoingType.BOTH == inOutType || IncludeIncomingOutgoingType.OUTGOING == inOutType) {
final EdgeId seedSourceDestDir2 = new EdgeSeed(SOURCE_DIR_2, DEST_DIR_2, true);
seedTerms.add(seedSourceDestDir2);
}
if (null == inOutType || IncludeIncomingOutgoingType.BOTH == inOutType || IncludeIncomingOutgoingType.INCOMING == inOutType) {
final EdgeId seedSourceDestDir3 = new EdgeSeed(SOURCE_DIR_3, DEST_DIR_3, true);
seedTerms.add(seedSourceDestDir3);
}
}
if (DirectedType.DIRECTED != directedType) {
final EdgeId seedSourceDest1 = new EdgeSeed(SOURCE_1, DEST_1, false);
seedTerms.add(seedSourceDest1);
final EdgeId seedSourceDest2 = new EdgeSeed(SOURCE_2, DEST_2, false);
seedTerms.add(seedSourceDest2);
final EdgeId seedSourceDest3 = new EdgeSeed(SOURCE_3, DEST_3, false);
seedTerms.add(seedSourceDest3);
}
}
expectedElements.addAll(getElements(seedTerms));
shouldGetElements(expectedElements, SeedMatchingType.RELATED, directedType, includeEntities, includeEdges, inOutType, ALL_SEEDS);
}
private void shouldGetElements(final List<Element> expectedElements,
final SeedMatchingType seedMatching,
final DirectedType directedType,
final boolean includeEntities,
final boolean includeEdges,
final IncludeIncomingOutgoingType inOutType,
final Iterable<ElementId> seeds) throws IOException, OperationException {
// Given
final User user = new User();
final View.Builder viewBuilder = new View.Builder();
if (includeEntities) {
viewBuilder.entity(TestGroups.ENTITY);
}
if (includeEdges) {
viewBuilder.edge(TestGroups.EDGE);
}
final GetElements op = new GetElements.Builder()
.input(seeds)
.directedType(directedType)
.inOutType(inOutType)
.view(viewBuilder.build())
.seedMatching(seedMatching).build();
// When
final CloseableIterable<? extends Element> results = graph.execute(op, user);
// Then
final List<Element> expectedElementsCopy = Lists.newArrayList(expectedElements);
for (final Element result : results) {
if (result instanceof Entity) {
Entity entity = (Entity) result;
final Collection<Element> listOfElements = new LinkedList<>();
Iterables.addAll(listOfElements, results);
assertTrue("Entity was not expected: " + entity, expectedElements.contains(entity));
} else {
Edge edge = (Edge) result;
if (edge.isDirected()) {
assertTrue("Edge was not expected: " + edge, expectedElements.contains(edge));
} else {
final Edge edgeReversed = new Edge(TestGroups.EDGE, edge.getDestination(), edge.getSource(), edge.isDirected());
Properties properties = edge.getProperties();
edgeReversed.copyProperties(properties);
expectedElementsCopy.remove(edgeReversed);
assertTrue("Edge was not expected: " + result, expectedElements.contains(result) || expectedElements.contains(edgeReversed));
}
}
expectedElementsCopy.remove(result);
}
assertEquals("The number of elements returned was not as expected. Missing elements: " + expectedElementsCopy + ". Seeds: " + seeds, expectedElements.size(),
Sets.newHashSet(results).size());
assertEquals(new HashSet<>(expectedElements), Sets.newHashSet(results));
}
private static List<Element> getElements(final List<ElementId> seeds) {
final List<Element> elements = new ArrayList<>(seeds.size());
for (final ElementId seed : seeds) {
if (seed instanceof EntityId) {
final Entity entity = new Entity(TestGroups.ENTITY, ((EntityId) seed).getVertex());
entity.putProperty("stringProperty", "3");
elements.add(entity);
} else {
final Edge edge = new Edge(TestGroups.EDGE, ((EdgeId) seed).getSource(), ((EdgeId) seed).getDestination(), ((EdgeId) seed).isDirected());
edge.putProperty("intProperty", 1);
edge.putProperty("count", 1L);
elements.add(edge);
}
}
return elements;
}
private static List<ElementId> getEntityIds() {
List<ElementId> allSeeds = new ArrayList<>();
allSeeds.addAll(ENTITY_SEEDS_EXIST);
allSeeds.addAll(ENTITY_SEEDS_DONT_EXIST);
return allSeeds;
}
private static List<ElementId> getEdgeIds() {
List<ElementId> allSeeds = new ArrayList<>();
allSeeds.addAll(EDGE_SEEDS_EXIST);
allSeeds.addAll(EDGE_DIR_SEEDS_EXIST);
allSeeds.addAll(EDGE_SEEDS_DONT_EXIST);
return allSeeds;
}
private static List<ElementId> getAllSeeds() {
List<ElementId> allSeeds = new ArrayList<>();
allSeeds.addAll(ENTITY_SEEDS);
allSeeds.addAll(EDGE_SEEDS);
return allSeeds;
}
private static List<Object> getAllSeededVertices() {
List<Object> allSeededVertices = new ArrayList<>();
for (final ElementId elementId : ENTITY_SEEDS_EXIST) {
allSeededVertices.add(((EntityId) elementId).getVertex());
}
for (final ElementId elementId : EDGE_SEEDS_EXIST) {
allSeededVertices.add(((EdgeId) elementId).getSource());
allSeededVertices.add(((EdgeId) elementId).getDestination());
}
for (final ElementId elementId : EDGE_DIR_SEEDS_EXIST) {
allSeededVertices.add(((EdgeId) elementId).getSource());
allSeededVertices.add(((EdgeId) elementId).getDestination());
}
return allSeededVertices;
}
}