/* /* * 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; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.rules.TestName; import uk.gov.gchq.gaffer.commonutil.TestGroups; import uk.gov.gchq.gaffer.commonutil.TestPropertyNames; import uk.gov.gchq.gaffer.commonutil.TestTypes; import uk.gov.gchq.gaffer.data.element.Edge; import uk.gov.gchq.gaffer.data.element.Entity; import uk.gov.gchq.gaffer.data.element.id.EdgeId; import uk.gov.gchq.gaffer.data.element.id.EntityId; import uk.gov.gchq.gaffer.graph.Graph; import uk.gov.gchq.gaffer.operation.OperationException; import uk.gov.gchq.gaffer.operation.data.EdgeSeed; import uk.gov.gchq.gaffer.operation.data.ElementSeed; import uk.gov.gchq.gaffer.operation.data.EntitySeed; import uk.gov.gchq.gaffer.operation.impl.add.AddElements; import uk.gov.gchq.gaffer.serialisation.implementation.StringSerialiser; import uk.gov.gchq.gaffer.serialisation.implementation.raw.CompactRawLongSerialiser; import uk.gov.gchq.gaffer.serialisation.implementation.raw.RawIntegerSerialiser; import uk.gov.gchq.gaffer.store.StoreProperties; import uk.gov.gchq.gaffer.store.StoreTrait; import uk.gov.gchq.gaffer.store.schema.Schema; import uk.gov.gchq.gaffer.store.schema.SchemaEdgeDefinition; import uk.gov.gchq.gaffer.store.schema.SchemaEntityDefinition; import uk.gov.gchq.gaffer.store.schema.TypeDefinition; import uk.gov.gchq.gaffer.user.User; import uk.gov.gchq.koryphe.impl.binaryoperator.Max; import uk.gov.gchq.koryphe.impl.binaryoperator.StringConcat; import uk.gov.gchq.koryphe.impl.binaryoperator.Sum; import uk.gov.gchq.koryphe.impl.predicate.AgeOff; import uk.gov.gchq.koryphe.impl.predicate.IsLessThan; import java.io.File; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; import static org.junit.Assume.assumeTrue; /** * Logic/config for setting up and running store integration tests. * All tests will be skipped if the storeProperties variable has not been set * prior to running the tests. */ public abstract class AbstractStoreIT { protected static final String USER_01 = "user01"; protected static final long AGE_OFF_TIME = 4L * 1000; // 4 seconds; // Temporary folder location protected static final File tmpFolder = new File(System.getProperty("java.io.tmpdir")); // Identifier prefixes public static final String SOURCE = "source"; public static final String DEST = "dest"; public static final String SOURCE_DIR = "sourceDir"; public static final String DEST_DIR = "destDir"; public static final String A = "A"; public static final String B = "B"; public static final String C = "C"; public static final String D = "D"; public static final String[] VERTEX_PREFIXES = new String[]{A, B, C, D}; // Identifiers public static final String SOURCE_1 = SOURCE + 1; public static final String DEST_1 = DEST + 1; public static final String SOURCE_2 = SOURCE + 2; public static final String DEST_2 = DEST + 2; public static final String SOURCE_3 = SOURCE + 3; public static final String DEST_3 = DEST + 3; public static final String SOURCE_DIR_0 = SOURCE_DIR + 0; public static final String DEST_DIR_0 = DEST_DIR + 0; public static final String SOURCE_DIR_1 = SOURCE_DIR + 1; public static final String DEST_DIR_1 = DEST_DIR + 1; public static final String SOURCE_DIR_2 = SOURCE_DIR + 2; public static final String DEST_DIR_2 = DEST_DIR + 2; public static final String SOURCE_DIR_3 = SOURCE_DIR + 3; public static final String DEST_DIR_3 = DEST_DIR + 3; protected static Graph graph; private static Schema storeSchema = new Schema(); private static StoreProperties storeProperties; private static String singleTestMethod; private final Map<EntityId, Entity> entities = createEntities(); private final Map<EdgeId, Edge> edges = createEdges(); @Rule public TestName name = new TestName(); private static Map<? extends Class<? extends AbstractStoreIT>, String> skippedTests; public static void setStoreProperties(final StoreProperties storeProperties) { AbstractStoreIT.storeProperties = storeProperties; } public static StoreProperties getStoreProperties() { return storeProperties; } public static Schema getStoreSchema() { return storeSchema; } public static void setStoreSchema(final Schema storeSchema) { AbstractStoreIT.storeSchema = storeSchema; } public static void setSkipTests(final Map<? extends Class<? extends AbstractStoreIT>, String> skippedTests) { AbstractStoreIT.skippedTests = skippedTests; } public static void setSingleTestMethod(final String singleTestMethod) { AbstractStoreIT.singleTestMethod = singleTestMethod; } /** * Setup the Parameterised Graph for each type of Store. * Excludes tests where the graph's Store doesn't implement the required StoreTraits. * * @throws Exception should never be thrown */ @Before public void setup() throws Exception { assumeTrue("Skipping test as no store properties have been defined.", null != storeProperties); final String originalMethodName = name.getMethodName().endsWith("]") ? name.getMethodName().substring(0, name.getMethodName().indexOf("[")) : name.getMethodName(); assumeTrue("Skipping test as only " + singleTestMethod + " is being run.", null == singleTestMethod || singleTestMethod.equals(originalMethodName)); final Method testMethod = this.getClass().getMethod(originalMethodName); final Collection<StoreTrait> requiredTraits = new ArrayList<>(); for (final Annotation annotation : testMethod.getDeclaredAnnotations()) { if (annotation.annotationType().equals(TraitRequirement.class)) { final TraitRequirement traitRequirement = (TraitRequirement) annotation; requiredTraits.addAll(Arrays.asList(traitRequirement.value())); } } assumeTrue("Skipping test. Justification: " + skippedTests.get(getClass()), !skippedTests.containsKey(getClass())); graph = new Graph.Builder() .storeProperties(storeProperties) .addSchema(createSchema()) .addSchema(storeSchema) .build(); for (final StoreTrait requiredTrait : requiredTraits) { assumeTrue("Skipping test as the store does not implement all required traits.", graph.hasTrait(requiredTrait)); } } protected Schema createSchema() { return createDefaultSchema(); } public static Schema createDefaultSchema() { return new Schema.Builder() .type(TestTypes.ID_STRING, new TypeDefinition.Builder() .clazz(String.class) .build()) .type(TestTypes.DIRECTED_EITHER, new TypeDefinition.Builder() .clazz(Boolean.class) .build()) .type(TestTypes.PROP_STRING, new TypeDefinition.Builder() .clazz(String.class) .aggregateFunction(new StringConcat()) .serialiser(new StringSerialiser()) .build()) .type(TestTypes.PROP_INTEGER, new TypeDefinition.Builder() .clazz(Integer.class) .aggregateFunction(new Max()) .serialiser(new RawIntegerSerialiser()) .build()) .type(TestTypes.PROP_COUNT, new TypeDefinition.Builder() .clazz(Long.class) .aggregateFunction(new Sum()) .serialiser(new CompactRawLongSerialiser()) .build()) .type(TestTypes.TIMESTAMP, new TypeDefinition.Builder() .clazz(Long.class) .aggregateFunction(new Max()) .serialiser(new CompactRawLongSerialiser()) .build()) .type(TestTypes.TIMESTAMP_2, new TypeDefinition.Builder() .clazz(Long.class) .aggregateFunction(new Max()) .serialiser(new CompactRawLongSerialiser()) .validateFunctions(new AgeOff(AGE_OFF_TIME)) .build()) .type(TestTypes.PROP_INTEGER_2, new TypeDefinition.Builder() .clazz(Integer.class) .aggregateFunction(new Max()) .serialiser(new RawIntegerSerialiser()) .validateFunctions(new IsLessThan(10)) .build()) .entity(TestGroups.ENTITY, new SchemaEntityDefinition.Builder() .vertex(TestTypes.ID_STRING) .property(TestPropertyNames.STRING, TestTypes.PROP_STRING) .groupBy(TestPropertyNames.INT) .build()) .edge(TestGroups.EDGE, new SchemaEdgeDefinition.Builder() .source(TestTypes.ID_STRING) .destination(TestTypes.ID_STRING) .directed(TestTypes.DIRECTED_EITHER) .property(TestPropertyNames.INT, TestTypes.PROP_INTEGER) .property(TestPropertyNames.COUNT, TestTypes.PROP_COUNT) .groupBy(TestPropertyNames.INT) .build()) .entity(TestGroups.ENTITY_2, new SchemaEntityDefinition.Builder() .property(TestPropertyNames.TIMESTAMP, TestTypes.TIMESTAMP_2) .property(TestPropertyNames.INT, TestTypes.PROP_INTEGER_2) .build()) .vertexSerialiser(new StringSerialiser()) .build(); } @After public void tearDown() { graph = null; } public void addDefaultElements() throws OperationException { graph.execute(new AddElements.Builder() .input(getEntities().values()) .build(), getUser()); graph.execute(new AddElements.Builder() .input(getEdges().values()) .build(), getUser()); } public Map<EntityId, Entity> getEntities() { return entities; } public Map<EdgeId, Edge> getEdges() { return edges; } public Entity getEntity(final Object vertex) { return entities.get(new EntitySeed(vertex)); } public Edge getEdge(final Object source, final Object dest, final boolean isDirected) { return edges.get(new EdgeSeed(source, dest, isDirected)); } protected Map<EdgeId, Edge> createEdges() { return createDefaultEdges(); } public static Map<EdgeId, Edge> createDefaultEdges() { final Map<EdgeId, Edge> edges = new HashMap<>(); for (int i = 0; i <= 10; i++) { for (int j = 0; j < VERTEX_PREFIXES.length; j++) { final Edge edge = new Edge(TestGroups.EDGE, VERTEX_PREFIXES[0] + i, VERTEX_PREFIXES[j] + i, false); edge.putProperty(TestPropertyNames.INT, 1); edge.putProperty(TestPropertyNames.COUNT, 1L); addToMap(edge, edges); } final Edge firstEdge = new Edge(TestGroups.EDGE, SOURCE + i, DEST + i, false); firstEdge.putProperty(TestPropertyNames.INT, 1); firstEdge.putProperty(TestPropertyNames.COUNT, 1L); addToMap(firstEdge, edges); final Edge secondEdge = new Edge(TestGroups.EDGE, SOURCE_DIR + i, DEST_DIR + i, true); secondEdge.putProperty(TestPropertyNames.INT, 1); secondEdge.putProperty(TestPropertyNames.COUNT, 1L); addToMap(secondEdge, edges); } return edges; } protected Map<EntityId, Entity> createEntities() { return createDefaultEntities(); } public static Map<EntityId, Entity> createDefaultEntities() { final Map<EntityId, Entity> entities = new HashMap<>(); for (int i = 0; i <= 10; i++) { for (int j = 0; j < VERTEX_PREFIXES.length; j++) { final Entity entity = new Entity(TestGroups.ENTITY, VERTEX_PREFIXES[j] + i); entity.putProperty(TestPropertyNames.STRING, "3"); addToMap(entity, entities); } final Entity secondEntity = new Entity(TestGroups.ENTITY, SOURCE + i); secondEntity.putProperty(TestPropertyNames.STRING, "3"); addToMap(secondEntity, entities); final Entity thirdEntity = new Entity(TestGroups.ENTITY, DEST + i); thirdEntity.putProperty(TestPropertyNames.STRING, "3"); addToMap(thirdEntity, entities); final Entity fourthEntity = new Entity(TestGroups.ENTITY, SOURCE_DIR + i); fourthEntity.putProperty(TestPropertyNames.STRING, "3"); addToMap(fourthEntity, entities); final Entity fifthEntity = new Entity(TestGroups.ENTITY, DEST_DIR + i); fifthEntity.putProperty(TestPropertyNames.STRING, "3"); addToMap(fifthEntity, entities); } return entities; } protected static void addToMap(final Edge element, final Map<EdgeId, Edge> edges) { edges.put(ElementSeed.createSeed(element), element); } protected static void addToMap(final Entity element, final Map<EntityId, Entity> entities) { entities.put(ElementSeed.createSeed(element), element); } protected User getUser() { return new User(USER_01); } }